一、前言
在深入理解原型和原型链之前,我们首先要搞懂以下两点:
- 对应名称
prototype: 原型,每一个对象都会从原型上‘继承’属性
__proto__: 原型链,并不是单一指某一个,而是一条__proto__连起来的链条,当js引擎查找对象属性时,先查找对象本身是否具有,如果没有就去原型链上查找
function Person() { } Person.prototype.fun = function (){ console.log('我是构造函数的方法') } var person = new Person(); console.log(person.fun()); //我是构造函数的方法
- 从属关系
prototype ——> 函数的一个属性:对象{} (每个函数都有prototype属性)
——>定义函数时自动添加,默认指向一个空的Object的对象
__proto_ _——> 对象Object的一个属性: 对象{} (每个对象都有__proto__属性)
——>创建对象时自动添加,默认值为构造函数的prototype的属性值
二、理解__proto__和prototype的联系
首先,我们来看一张图:
从图片可以看出,通俗来讲,就是函数里面有个prototype属性指向原型对象,实例化对象里面有个__proto__属性也指向原型对象,且与构造函数的原型对象是同一个,然后原型对象里面有个constructor属性指向的是构造函数。
function Person() { }
var person = new Person();
console.log(person.__proto__ === Person.prototype); //true
console.log(Person === Person.prototype.constructor);//true
补充说明,当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性
console.log(person.constructor === Person); // true
扩展,万一原型没找到,那么原型的原型又是什么呢?其中Object.prototype.__proto__ 的值为 null 跟也就表示Object.prototype 没有原型,而图中红色的这条线就是原型链
三、实例理解原型链
1、原型链属性查找
首先我们来看一段代码:
function Fun() { this.add = function (x, y) { return x + y; } } Fun.prototype.add = function (x, y) { return x + y + 10; } Object.prototype.subtract = function (x, y) { return x - y; } var fun = new Fun(); console.log(fun.add(1, 2)); //结果是3,而不是13 console.log(fun.subtract(1, 2)); //结果是-1
可以看出当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,如果查找到达原型链的顶部 ,也就是 Object.prototype ,但是仍然没有找到指定的属性,就会返回 undefined
2、this指向问题,
sayName这个方法内部使用了this.name,那么这个this的指向是什么么?我们可以看到是person调用的sayName,隐式调用,this就指向person,而person的name就是Andy
function Person(name) { this.name = name } Person.prototype.sayName = function (welcome){ console.log(welcome,this.name); }
var person = new Person('Andy'); person.sayName('hello');//hello Andy