原型

Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain. ---MDN

当我们在一个obj对象上查找是否具有某个属性的时候,这个过程是这样的:
1.现在obj 对象中查找是否有该属性,如果有,查找终止。(也就是说如果obj对象上面和它的原型上又一个同名属性,那么对象上面的属性优先。)
2.如果没有,则查看当前obj是否具有__proto__。这个__proto__就是obj原型的引用。如果obj对象没有原型,那么查找终止。
3.如果obj有原型,就查找obj的原型上是否有这个属性。如果有,查找终止。返回这个属性。
4.如果obj的原型上没有这个属性,则查看obj的原型是否有原型。如果没有,则查找终止。
5.如果obj的原型上上面有它自己的原型,那么继续在obj的原型的原型上继续查找。

几乎每一个js对象都有原型,但是有个例外。

let a = Obeject.crate(null)
let b = {}

当Object.create()传入null的时候, 返回一个真正的空对象a。这个对象不同于b,a对象上什么都没有,但是b对象上还有一个__proto__指向Object.prototype。

__proto__和prototype

function Man(name){
    this.name = name
}
Man.prototype.setName = function(name){
    this.name = name
}
let a = new Man("lee")
console.log(a)

输出如下:

clipboard.png

实例化的对象a中 有两个属性一个是name,还有一个就是它的原型__proto__。而这个__proto__是指向a 这个对象的构造函数 (a.__proto__.constructor 就是a这个对象的构造函数,也就是Man这个函数。) 的原型的。并且,修改对象的__proto__是不推荐的做法,对于性能的影响可能有时候我们不能不重视。而在Man的这个函数的prototype上面我们定义了一个setName的属性。
所以按照上面的查找流程,我们在a对象的原型上找到了setName属性。

如何继承

let animal = {
    weight:20,
    setWeight:function(weight){
        this.weight = weight
    }
}

function Cat(name){
    this.name = name
}

cat.prototype = animal

如上,只需简单将函数的prototype指向一个对象,就完成了对这个的对象的继承。现在所有通过new Cat()创建的对象都共享这个animal对象里面的属性。
这一点和直接使用Object.create()函数的继承方式很像。

另外一种继承方式,也是比较受开发者认可,类似于下面这种:

function Animal(weight){
    this.weight = weight
}
Animal.prototype.setWeight = function(weight){
    this.weight = weight
}
function Cat(name,weight){
    Animal.call(this,weight)
    this.name = name
}
//同时,我们别忘了,将Cat的prototype设为Animal的prototype,这样就完成了对Animal的继承。
Cat.prototype = Object.create(Animal.prototype)
Cat.prototype.constructor = Cat

ES6 中出现了类的语法糖,我们写继承就更简便了。

最后附上一张原型链的解析图:

clipboard.png


BBQ只有番薯
300 声望6 粉丝

« 上一篇
C2:动画队列
下一篇 »
mocha