彻底理解JS的原型和原型链
一、前言
在深入理解原型和原型链之前,我们首先要搞懂以下两点:
- 对应名称
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 没有原型,而图中红色的这条线就是原型链
看到这里,我们大致对__proto__和prototype也有了一定的模糊概念,那么他们又有什么用呢?
实例对象的__proto__指向构造函数的prototype,从而实现了继承,prototype对象相当于所有实例化对象都可以访问的公共容器,接下来我们来看一段代码从而更好的理解“公共容器”
function Person(name,age) {
this.name = name
this.age = age
}
Person.prototype.sayName = function (){
console.log(this.name);
}
var person1 = new Person('Andy',13);
var person2 = new Person('Mary',18);
person1.sayName();//Andy
person2.sayName();//Mary
三、实例理解原型链
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
注:原型和原型链的具体应用可以看https://www.cnblogs.com/WuAnqi/p/15405247.html