JavaScript实例属性与构造器属性

在构造器上设置属性

首先在js中函数也是对象,所以在js中函数也可以挂载属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
function Bar(){}
Bar.name="i m bar";
Bar.sayname=function(){
console.log(this.name)
}
Bar.sayname();//Bar;
var sum=Bar;
sum.sayname="no this function";
console.log(Bar.sayname);//"no this function"
Bar=null;
console.log(sum.sayname);//no this function

首先Bar.sayname()结果并不是”i m bar”而是一个”Bar” 而且你是无法改写这个name属性的 说明函数自身就带了一个name属性,保存的是他的名字.所以弹出的会是”Bar”
下面我们声明了一个变量sum并且把Bar赋值给他.同时改写了一下sum的sayname属性.然后调用了Bar.sayname得出的结果是”no this function” 接着我们把Bar设置为null 然后再调用一下sum的.sayname方法发现还是存在的。

JavaScript高级程序设计里有段话说的挺好的 #110

由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同.换句话说函数可能会有多个名字.即时我们将Bar设置为null但是sum是他的另外一个名字.

构造器的属性去哪了?

1
2
3
4
5
6
7
Function.prototype.testname="i m test name";
function Bar(){}
Bar.sayTestName=function(){
console.log("%c "+this.testname,"color:red;")
}
Bar.sayTestName();//i m test name
Bar instanceof Function//true

okay,我们知道Function的proto是指向Function的原型的.那么我们把属性挂载到原型.那么函数就是Function的实例,实例中找不到的属性自然就会顺着原型链去原型上面找了.

在Object.prototype和Object添加会产生什么效果?

1
2
3
4
5
6
7
Object.testname="i m ObjectEntry name";
Object.prototype.testname="i m Object prototype name ";
function Bar(){}
Bar.sayTestName=function(){
console.log("%c "+this.testname,"color:red;")
}
Bar.sayTestName();//i m Object prototype name

首先我们知道所有的Function.prototype都来自于Object.prototype那么在Function.prototype找不到的自然就会去Object.prototype上面寻找了.
Object是Object的实例所以并不会在这上面找.实例的方法与原型的方法是相隔的.具体解释看下面的

new 构造器是什么鬼?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function.prototype.testname="i m test name";
Object.prototype.testname="i m bar object name";
function Bar(){
this.sayTrueName=function(){
console.log("%c "+this.testname,"color:green;")
}
}
Bar.sayTestName=function(){
console.log("%c "+this.testname,"color:red;")
}
Bar.sayTestName();//i m test name
var bar=new Bar()
console.log("can you find bar.sayname ?",bar.sayname);//undefined
bar.sayTrueName();//

okay.从上述代码我们可以看出了一些道理了

  • new 一个函数 实际上是创建了Object的一个实例
  • 声明一个函数实际上是创建了一个Function实例

写点继承来理解下实例与构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var XiaoMing=function(){
this.info="i m xiaoming today i choose death";
this.sayHello=function(){
console.log(this.info)
}
}
XiaoMing.prototype.goToDie=function(){
console.log(this.name+" go die")
}
var XiaoHong=function(){
this.name="xiaohong";
}
XiaoHong.prototype=new XiaoMing();
var xiaohong=new XiaoHong();
xiaohong.goToDie();//xiaohong go die;
xiaohong.sayHello();//i m xiaoming today i choose death;

通过设置XiaoHong的原型来构建成一条原型链,下面来大概解释下
new XiaoHong=>XiaoHong.prototype=>new XiaoMing()=>XiaoMing.prototype=>Object.prototype=>null;
首先我们实例化小明的时候.那么小明会有以下的属性

1
2
3
4
5
6
7
8
9
10
11
12
xiaoming:{
info:"i m xiaoming today i choose death";
sayHello:function(){
console.log(this.info)
}
_proto_:xiaoming.prototype
}
xiaoming.prototype:{
goToDie:function(){
....
}
}

那么实例化小红的时候也是同理.
当调用xiaohong的goToDie()方法实际上是去顺着proto这个属性来寻找.

  • A:xiaohong本身(this)有没有这个goToDie方法啊?
  • B:不好意思,没有
  • A:那麻烦你去xiaohong的原型链(prototype)上找找好不到
  • B:okay let me find… oh. i find new XiaoMing..i must instantiate(实例化) XiaoMing
  • B:我在实例化XiaoMing..让我在实例化的XiaoMing本身找找…恩..貌似没有.但是它有proto让我去它原型链上找找
  • B:找到了!在实例化XiaoMing的原型链上 来给你
  • A:thanks

(正在学习英语..让我写几句渣渣英语 大神勿喷..)

大概就是这么一个寻找过程..如果在中间任何一个环节找到了就不会继续往下寻找了.
那么我们也可以通过设置原型链的模式来继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var XiaoMing=function(){
this.info="i m xiaoming today i choose death";
this.sayHello=function(){
console.log(this.info)
}
}
XiaoMing.prototype.goToDie=function(){
console.log(this.name+" go die")
}
var XiaoHong=function(){
this.name="xiaohong";
}
XiaoHong.prototype=XiaoMing.prototype;
var xiaohong=new XiaoHong();
console.log(xiaohong)
xiaohong.goToDie();//xiaohong go die;
xiaohong.sayHello();//error;

~~ 通过设置XiaoHong.prototype来获得继承也是可以的. ~~

如果是new XiaoMing()这样会把XiaoMing本身的属性也就是this.xxx=xxx给继承下来.我们仅仅是需要原型链上的属性.所以我们可以用Object.create(XiaoMing.prototype)来继承.

同时实例之间的属性并不会相互影响 下面摘录JavaScript高级程序设计中的代码 #150

1
2
3
4
5
6
7
8
9
10
11
12
function Person(){
this.name="123";
this.sayName=function(){
console.log(this.name)
}
}
var person1=new Person();
var person2=new Person();
person2.name="456"
person1.sayName()//123
person2.sayName()//456
console.log(person1.sayName===person2.sayName)//false

但是通过构造函数实例化后.不同实例上的同名函数是不想等的.但是原型就不同了.下面把上面的例子改写一下

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(){
}
Person.prototype.name="123";
Person.prototype.sayName=function(){
console.log(this.name)
}
var person1=new Person();
var person2=new Person();
person2.name="456";
person1.sayName()//123
person2.sayName()//456
console.log(person1.sayName===person2.sayName)//true

当然原型上的属性是不会相等的.

所以我们会这样称呼上述的属性 代码转自here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
(function(){
//私有静态成员
var user = "";
//私有静态方法
function privateStaticMethod(){
}
Box = function(value){
//私有成员
privateStaticUser = value;
//这个是私有方法
function privateMethod(){
}
//公有方法,因为能访问私有成员,也可以说是特权函数,也可以说是实例方法
this.getUser = function(){
return user;
};
//公有成员
this.user = 1;
};
//公有共享访问
Box.prototype.sharedMethod = function () {};
//公有共享属性
Box.prototype.sharedProperty = function () {};
//公有静态方法
Box.staticMethod = function(){};
//公有静态成员
Box.staticProperty = 1;
})();

那么问题来了

什么是公有共享 公有静态?

首先私有的很好理解 就是外面不能访问到的.
那么公有共享就是原型链上面的方法和属性了 包括函数内部的this.xxx 因为在实例化后都能访问到 这些都是公有共享
那么公有静态是什么?
公有静态是直接挂载到函数上的还是用一段代码来演示 转自here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Man(name, age) {
//定义实例属性
this.name = name;
this.age = age;
}
//定义静态属性。默认性别是男,不排除变性,^v^
Man.sex = '男';
//定义原型属性
Man.prototype.phone = '123456';
//除了name.sex和Man.prototype.phone其余全部是Undefined
alert(Man.sex + "-----" + Man.prototype.phone + "--" + Man.name + "--" + Man.age + "--" + Man.phone);
var man = new Man("Tom", 24);
alert(Man.sex + "--" + man.name + "--" + man.age + "--" + man.phone);
/**
* 通过例子说明:原型属性在实例化之后作为类的实例属性。
* 但是实例属性在实例化之后却不能作为原型属性。
*/

okay 上面有两个公有属性 this.name和this.age 一个公有共享的属性Man.prototype.phone 一个公有静态方法 Man.sex
那么没有实例化之前 我们只能访问到prototype和Man.sex 其他的都需要实例化后才能获取到.
实例化后.我们能够访问到Man.sex但是访问不到man(实例).sex 因为公有静态方法是不会通过原型继承的.而公有共享和公有方法是可以通过原型继承的.

今天就说这么多吧.有什么坑后续再填