JavaScript深入之——原型与原型链

很长一段时间对JS的原型与原型链理解的很模糊,而想学好JS,原型与原型链却是绕不开的话题,所以只好进行对其进行一个梳理。

理解原型和原型链,需理解三个重要的属性: prototype、__proto__、constructor

 

prototype

JavaScript函数中,每一个函数都有一个prototype属性,叫原型对象。

代码示例:

function Person(){

}

Person.prototype.name = 'zhangsan'
let person = new Person()

console.log(person.name)    // zhangsan

上面的代码中,创建了一个构造函数Person,并在它的原型上添加一个属性name为zhangsan, 然后再创建了实例对象person,那么这个实例对象上也有name属性,打印输出“zhangsan”

可以看出:

Person这个函数的prototype属性指向了一个对象,即:Person.prototype 也是一个对象,这个对象正是调用该构造函数而创建的实例的原型,即person的原型。

方便理解,我们进行拆解:

1.创建了构造函数Person

2.使用new关键字进行调用

3.调用得到了实例person

4.实例和原型的关系:person的原型就是Person.prototype

  

那什么是原型呢?可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另外一个对象,这个对象就是我们所说的原型,而每一个对象都会从原型"继承"属性。

我们用一张图表示构造函数和原型之间的关系:

构造函数和实例原型之间的关系我们已经梳理清楚了,那怎么表示实例与原型,也就是person和Person.prototype之间的关系呢?

 

__proto__

其实每一个JavaScript对象(除了null)都有一个属性,叫__proto__,这个属性会指向该对象的原型。

代码示例:

function Person(){

}

let person = new Person()
console.log(person.__proto__ === Person.prototype)   // true

构造函数Person的实例对象person,有个属性叫__proto__,这个属性指向原型,即Person.prototype。

补全上面的关系图:

Q:原型是否有属性指向构造函数或者实例对象呢?

 

constructor

代码示例:

function Person() {

}
let person = new Person()
console.log(Person === Person.prototype.constructor); // true

 

继续完善关系图:

原型的constructor指向构造函数,但没有属性指向实例,因为可能有多个实例。

其实 person 中并没有constructor 属性,当不能读取到constructor属性时,会从 person 的原型也就是 Person.prototype中读取

console.log(person.constructor === Person)   // true
console.log(person.constructor === Person.prototype.constructor)  // true

  

  

 实例与原型

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

代码示例:

 function Person() {

}

Person.prototype.name = 'zhangsan';

let person = new Person();

 person.name = 'lisi';
 console.log(person.name) // lisi

delete person.name;
console.log(person.name) // zhangsan

 

new创建了一个实例对象person,有个属性name值为“lisi”,当我们把删除了这个name属性后,依然能够打印出“zhangsan”,实际情况是从 person 实例对象中找不到 name 属性,就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 zhangsan

 

原型的原型

代码示例:

Object.prototype.name = 'wangwu'

function Person(){

}

let person = new Person()
		
		
console.log(person.name)   // wangwu

Person 的实例对象person,本身没有name属性值,所有会去原型上找,Person.prototype上也没有,就去原型的原型上找,即:Object.prototype,有一个name为“wangwu”的属性,所有输出“wangwu”

其实原型对象就是通过Object构造函数生成的,结合之前我们所说的,实例的__proto__指向构造函数的 prototype 所以我们再丰富一下我们的关系图:

 

原型链

那Object.prototype 的原型呢?Object是根节点的对象,再往上查找就是null,我们可以打印:

  console.log(Object.prototype.__proto__ === null) // true

 我们将null也加入关系图,就比较完整了:

 

上面的person实例对象到null的这条线即为原型链。

 

我们还可以把大Function加上

console.log(Person.constructor === Function)  // true
console.log(obj.__proto__ === Object.prototype) // true
console.log(obj.__proto__.constructor === Object) /// true
console.log(obj.__proto__.constructor.__proto__ === Function.prototype) // true
console.log(obj.__proto__.constructor.__proto__.constructor === Function) // true
console.log(Person.__proto__ === Function.prototype) // true console.log(Object.__proto__ === Function.prototype) // true

 从网上找了张图,现在再去理解原型与原型链,就好理解了吧

 

posted @ 2019-01-31 15:19  王大师  阅读(501)  评论(0编辑  收藏  举报