图解JavaScript原型和原型链

先看看最简单的栗子:

//构造函数
function People(name, age){ 
    this.name = name;
    this.age = age;
}

//原型对象(所有由构造函数实例而来的对象都继承自这个对象)
People.prototype = {
   constructor:People,  //显式设置构造函数的反向引用,避免实例的constructor属性指向Object函数
  introduce:function(){ console.log(this.name + '今年' + this.age + '岁'); },
  speak:function(x){ console.log(this.name + "会讲" + x + "语言"); } 
}

let p1= new Person('leaf',12);
let p2 = new Person('kafu',13);

console.log(p1.__proto__===People.prototype); //true 
console.log(People.prototype.constructor===People); //true
console.log(Object.getPrototypeOf(p1)); 

  

  

先说明几个概念再上图

1、prototype

每个函数都有一个prototype属性,这个属性值是一个对象。而构造函数的
prototype属性被用作新对象的原型, 也就是实例的原型。

在ECMAScript5中,该属性是不能被直接读取或修改的,但是可以通过Object.getPrototypeOf()间接的读取到它.

作用:实现类的扩充、类之间的继承

2、__proto__

js对象(除了null)都"具有"的这个属性,这个属性会指向该对象的原型。

”具有”,它并不存在与Person.prototype中,实际上,它是来自于Object.prototype。

即:p1.__proto__ === People.prototype

作用:创建一个以指定对象为原型的对象,以及,为内置类型添加子类型。

3、constructor
前面讲到,每个函数都有一个prototype属性,这个属性值是一个对象,这个对象包含唯一一个不可枚举的
属性constructor,constructor属性的值是一个函数对象, 它始终指向创建当前对象的构造函数。即:People.prototype.constructor===People,其实实例.constructor也指向了构造函数;这里有一个坑!看下面

 

4、prototype和constructor之坑

当我们给原型对象添加新方法时候,如果我们是改写People.prototype,比如

People.prototype={
    getName:function(){
        return this name;
    }
}

此时我们再去打印console.log(People.prototype.constructor===People)  //false

why?

因为当重写People.prototype对象的时候,相当于

  Person.prototype = new Object({
            getName: function() {
                return this.name;
            }
        });

  

那此时People.prototype对象的构造函数是不是就是 Object了?而constructor始终指向创建当前对象的构造函数,所以此时:People.prototype.constructor===Object了。

修正方法:

可以重新覆盖People.prototype.constructor,即People.prototype.constructor===People;

或者不该重写People.prototype,添加属性,直接在后面加就可以了。

People.prototype.method1=...

People.prototype.method2=...

5、实例与原型

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

6、原型链
如图中红色线形成的链状结构,一直指到null。

7、图解

 

posted @ 2017-05-30 16:59  leaf+  阅读(369)  评论(0编辑  收藏  举报