javascript中的原型链与继承
javascipt中的原型链和继承机制是这门语言所特有的,但js中的原型机制也因为它的奇特性让我在学习中遇到了很多困惑,现在经过多番查找资料和学习之后,总结如下:
一.prototype和__proto__
prototype
prototype这个属性是js为了模仿类的概念为每个函数所填上的一个属性,这个属性只有类才有。
每当我们创建一个函数的时候,js会自动给这个函数加上prototype属性,并将它指向一个空对象(实际上这个对象还是会有constructor等默认属性的,js中几乎没有真正意义上的空对象)。当我们将这个函数当作构造函数使用new操作符来调用它的时候,js就会帮你创建一个构造函数的实例,并且继承构造函数的prototype上的属性和方法(其实就是通过将实例对象的__proto__属性指向构造函数的prototype实现的)
//constructor
function myObject() {
this.a = 1;
this.b = 2;
}
myObject.prototype.c = 3;
var ob1 = new myObject();
console.log(ob1.a) //1
console.log(ob1.c) //3
console.log(ob1.__proto__ === myObject.prototype) //true
console.log(ob1.constructor === myObject) //true
__proto__
__proto__这个属性是每一个js对象都会有的属性,它的值其实就是它所对应的原型对象。如上例中的ob1.__proto__ === myObject.prototype
var a = {x: 1};
var b = new Object();
console.log(a.__proto__ === Object.prototype) //true
console.log(b.__proto__ === Object.prototype) //true
可以看到,无论是通过字面量创建的对象还是通过构造函数创建的对象,它们的__proto__属性都是指向它们的原型对象Object.prototype的(a和b都是Object的实例,上例中的ob1是myObject的实例)
二.原型链
看完了prototype和__proto__,再来看原型链也就明白了。js就是通过prototype和__proto__的合作从而实现的原型链,以及对象的继承。
构造函数,通过prototype来存储要共享的属性和方法,也可以设置prototype指向现存的对象来继承该对象。
对象的__proto__指向自己构造函数的prototype。obj.__proto__.__proto__...的原型链由此产生,包括我们的操作符instanceof正是通过探测obj.__proto__.__proto__... === Constructor.prototype来验证obj是否是Constructor的实例。
在上例中的原型链就是
ob1 --> myObject.prototype --> Object.prototype --> null
注意:原型链的最终为null。
可以看到原型链实现的关键就是__proto__,它起到了一个指针的作用不断指向原型链的上层原型对象。
引用网上的一张图
属性查找
当查找一个对象的属性或方法时,js会顺着原型链向上遍历,直至查找到给定的属性或方法名,若一直查找到原型链的顶点Object.prototype(Object.prototype.__proto__ === null)都没有找到,则返回undefined
hasOwnProperty方法
这是一个用来过滤对象对象原型链上属性的方法,继承于Object.prototype的hasOwnProperty方法。当我们只需要查找对象自身的方法而不想查找从原型继承而来的属性和方法时,可以使用这个方法来过滤
function myObject() {
this.a = 1;
this.b = 2;
}
myObject.prototype.c = 3;
var o = new myObject();
o.hasOwnProperty('a'); //true
o.hasOwnProperty('b'); //true
o.hasOwnProperty('c'); //false