阅读 1391

彻底理解JS原型链

前言:

JS原型是极为重要一个知识点,很多小伙伴都说知道,看过,却只能答出一二,真正能够讲清楚的很少,希望这边文章能够帮助正在学习JS原型的小伙伴们。

一、 构造函数,原型对象以及实例对象之间的关系

1 构造函数(constructor)中有 prototype 属性, 它是一个指针,指向原型对象

        2 原型对象中有 constructor 属性,是一个指针,指向该原型对应的构造函数

        3 实例(instance)内部有 __proto__ 属性,是一个指针,指向该构造函数的原型

Note: 很多小伙伴搞不清 prototype 和 proto,prototype(显式原型属性)是函数才有的属性, proto (隐式原型属性)存在于函数对象内部, 但 proto 不是一个规范属性,只有部分浏览器实现了此属性,对应的规范属性为 [[Prototype]]

var a = {};
console.log(a.prototype); // undefined,prototype只存在于函数中
console.log(a.__proto__); // Object ,实例的__proto__指向构造函数的原型
复制代码

当引用实例的某个属性的时候,首先会在该对象内部寻找,如果找不到才会在该对象的原型去找。

二、 对象的原型(__proto__的指向)

1 常见的创建对象的方式

 1 字面量:var a = {id: 1};

 2 构造函数:
 var Person = function (id) { 
     this.id = id;
 }; 
 var p1 = new Person(1);

 3 Object.create(a):var a = {id: 1}; 
   var b = Object.create(a);

 4 new Object: var c = new Object();
复制代码

**2 **__proto__的指向取决于对象创建的方式

(1) 字面量方式创建的对象a,__proto__指向 Object 的原型, 
    即:a.__proto__ === Object.prototype // ture

(2) 构造函数方式创建的对象p1,__proto__指向 构造函数 的原型,
    即:p1.__proto__ === Person.prototype // true 

(3) 通过Object.create()创建的对象b,__proto__指向 a,
    即:b.__proto__ === a // true

(4) 通过new Object()创建的对象c,__proto__指向Object 的原型(这里其实跟第2点一样,
    Object也是一个构造器,所以指向构造器的原型)   
    即:c.__proto__ === Object.prototype // ture
复制代码

三、 错误概念

(1) 所有的对象都是Object的实例。其实这句话并不完全准确,因为Function是Object的构造函数,也就是说Object是Function的实例(原来Function才是隐藏的大Boss!)

(2) Js中的其他对象都是从Object继承而来,这句话其实也不准确。准确说法应该是:Js中的其他对象都继承了Object.prototype中的属性和方法。小伙伴们可以试一下下面这个栗子:

var a = {};
Object.b = 1;
Object.prototype.c = 2;
a.b // undefind
a.c // 2
复制代码

(3) proto__只存在与对象中,其实函数中也有__proto,函数也是Function的实例 

var a = function () {};
typeof a; // 'function'
a.__proto__ === Function.prototype; // true
复制代码

四、原型链解析

var Person = function() {};
Person.prototype.say = "say Person";
Person.prototype.age = "Person age";
var Father = function() {};
var Children = function() {};
var p = new Person();
Father.prototype = p;
var f = new Father();
f.age = "father age"
Children.prototype = f;
var c = new Children();
复制代码

解析:c的__proto__指向Children(构造函数)的prototype(原型), Children.prototype指向f, f.__proto__指向Father.prototype,Father.prototype指向实例对象p,p.__proto__指向Person.prototype,Person.prototype本身也是Object的实例对象,所以Person.prototype.__proto__指向Object.prototype, Object.prototype也是个对象,它的__proto__指向null。

总结:

1 Object是由Function创建的,是Function的实例     Object instanceof Function // true   Object.__proto__ === Function.prototype // true

2 Function.__proto__ === Function.prototype // true 这一点想必小伙伴们很困惑,Function 也是对象函数,也是通过new Function()创建。所以自己是由自己创建的?换个思路,人是由人生的,就能想明白了。

3 对象都继承自Object.prototype:
var a = {}; a.__proto__ === Object.prototype // true

4 Object.prototype是一个普通对象,原型链到Object.prototype.__proto__ 此处便结束了,   Object.prototype.__proto__ === null // true  

5 Js中对象和函数都有__proto__属性,但只有函数对象才有prototype

6 原型链是基于__proto__形成的,继承是通过prototype实现的.对象都有一个__proto__属性,原型链上的对象正是依靠这个__proto__属性连结在一起的! 对于原型链上的一个对象,那么访问某个属性(方法也是属性)的过程是: 如果自身有该属性,则访问它;如果没有,就通过__proto__属性找到其原型链的上一级原型对象,看它有没有该属性,如此递归查找,直至找到该属性或到了原型链顶端Object.prototype对象为止

如果有问题或者描述不清的朋友们,欢迎留言一起探讨,如果本文有给你们帮助请帮忙点个赞。

文章分类
前端
文章标签