原型
JavaScript 原型是构造函数所构造对象的模板。
例如:
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.hair = 'black';
Person.prototype.skin = 'yellow';
var person = new Person('Cheney',23,'male');
那么person为
可以看到person具有的显式属性只有name,age,sex,那如果我们访问person.skin和person.hair会怎么样呢?
由于person自身没有设置hair和skin属性,那么访问时系统就会查找它的原型中的属性。
我们可以这样理解,prototype是DNA,其中有这个种族共有的特性,比如我们的黑头发黄皮肤是刻在DNA中的,不需要后期赋值就具有的属性。
在查看person时,我们发现它有一个__proto__属性,在chrome控制台呈浅粉色,访问它
这种以双下划线开头和结尾的变量一般为系统赋予的隐式变量,即系统不希望被修改的属性(当然,如果你想修改,它也没办法)。
__proto__指向了构造函数的原型,即构造这个对象的模板
实际上在构造函数中,系统隐式地添加了这一句
this.__proto__ = Person.prototype;
person.__proto__和Person.prototype指向同一块内存,而那块内存保存着模板信息,即
this.__proto__ = Person.prototype = {
hair: 'black',
skin: 'yellow'
}
至此,我们知道,构造函数的prototype为一个对象,这个对象保存着构造新对象时所用的模板信息,在构造新对象时,系统隐式地给对象赋予一个__proto__属性,并将构造函数的prototype的值传给它(传递的是上面代码中对象的地址)。访问生成的新对象的属性时,会优先访问该对象自己的属性值,如果该对象没有这个属性,就查找__proto__中的属性。
*************************************************************************************************************************************************
以下为题目,供理解参考
// Q1
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.__proto__ = Person.prototype;
}
Person.prototype.hair = 'black';
Person.prototype.skin = 'yellow';
var person = new Person('Cheney',23,'male');
Person.prototype.hair = 'yellow';
console.log(person.hair);
// A1: yellow
/********分割线,以下代码与以上代码无关********/
// Q2
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.__proto__ = Person.prototype;
}
Person.prototype.hair = 'black';
Person.prototype.skin = 'yellow';
var person = new Person('Cheney',23,'male');
Person.prototype = {
hair: yellow
}
console.log(person.hair);
// A2: black
/********分割线,以下代码与以上代码无关********/
// Q3
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.__proto__ = Person.prototype;
}
Person.prototype.hair = 'black';
Person.prototype.skin = 'yellow';
Person.prototype = {
hair: yellow
}
var person = new Person('Cheney',23,'male');
console.log(person.hair);
// A3: yellow
*注意prototype传递给__proto__为地址传递,即可解决以上问题
原型链
接下来谈一下原型链。
Grand.prototype.lastName = "Smith";
function Grand(){}
var grand = new Grand();
Father.prototype = grand;
function Father(){}
var father = new Father();
Son.prototype = father;
function Son(){}
var son = new Son();
console.log(son.lastName);;
执行以上的语句
我们说过,访问生成的新对象的属性时,会优先访问该对象自己的属性值,如果该对象没有这个属性,就查找__proto__中的属性。
son自己的属性里找不到lastName,就去son.__proto__里找,即father,而father的属性中也找不到lastName,那么继续向上,转向father.__proto__中查找,同理......最后终于在grand.__proto__中找到,这样原型连成链的结构称为原型链。