原型和原型链
构造函数
在学习原型和原型链之前,我们先来了解构造函数。在ES6之前,对象不是基于类创建的,而是一种称为构造函数的特殊函数来定义对象和他们的特征;
实例成员:构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问;
静态成员:在构造函数本身添加的成员,只能通过构造函数来访问,不能通过对象来访问;
由于构造函数在创建对象之后,在构造函数中,每个对象都为同一个方法开辟了不同内存空间,这样就存在浪费内存的问题,于是这里就用到了我们原型;
原型
原型(prototype):构造函数通过原型分配的函数是所有对象所共享的;
在JavaScript中,每个函数都有一个prototype属性,指向另一个对象;注意:prototype就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有。因此我们可以把那些不变的方法,直接定义在prototype对象上。
一般情况,我们的公共属性定义到构造函数里面;公共方法放到原型对象上面;
__proto__:(非标准属性)每个对象都有的__proto__属性,__proto__属性的指向取决于对象创建时的实现方式,一般指向构造函数的原型对象(prototype);在实际开发中不用这个属性,主要是为了对象查找机制提供一个方向;
function Fun(uname){
this.uname = uname;
}
var o =new Fun('xiaoming');
//o__proto__ === Fun.prototype//实例对象o的隐式原型指向它构造函数的显式原型
console.log( o.__proto__ === Fun.prototype);//true
constructor: 构造函数本身里面的属性(指向原来的构造函数)主要用于记录该对象引用了哪个构造函数,它可以让原型对象重新指向原来的构造函数;
Star.prototype = {
constructor:Star,//这个必须加,不然constructor这个属性就会被覆盖掉
sing:function(){},
movie:function(){}
}
如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
Star.prototype = new Array();
Star.prototype.constructor = Star;
原型链
JavaScript成员查找机制是按照原型链来查找的(就近原则)
- 当访问一个对象(包括方法)时,首先查找这个对象自身有没有该属性(方法)
- 如果没有,就找它的原型(__proto__)指向的是构造函数的原型对象(prototype)
- 如果还没有,就找原型对象的原型(__proto__)指向的是Object的原型对象(prototype)
- 以此类推,递归访问__proto__直到(null)找到
function Fun(uname) {
this.uname = uname;
}
var o = new Fun('xiaoming');
console.log(o.__proto__.constructor);Fun构造函数
console.log(o.__proto__ === Fun.prototype);//true
console.log(o.__proto__.__proto__ === Object.prototype);//true
console.log(o.__proto__.__proto__.__proto__ === null);//true