studyNotes icon indicating copy to clipboard operation
studyNotes copied to clipboard

JS原型、原型链深入理解

Open junhey opened this issue 8 years ago • 0 comments

前几天被阿里问到了一个原型和原型链的相关问题,其实大体上都懂,细节方面没有认识到,这里可以好好总结下了。

  1. ALL IN OBJECT

首先第一点需要知道的是All In Object,也就是说‘一切都是对象’,在javascript中我们认为任何值或变量都是对象,从对象划分等级来说,Object是第一级,Function是第二级,其他String,Array,Date,Number,Boolean,Math等内建对象是第三级,剩下的第四级。 当然你可以会看到如下代码:

function show(x) {
            console.log(typeof x);    // undefined
            console.log(typeof 10);   // number
            console.log(typeof 'abc'); // string
            console.log(typeof true);  // boolean

            console.log(typeof function () {});  //function

            console.log(typeof [1, 'a', true]);  //object
            console.log(typeof { a: 10, b: 20 });  //object
            console.log(typeof null);  //object
            console.log(typeof new Number(10));  //object
        }
        show();
        var fn = function () { };
        console.log(fn instanceof Object);  // true

从上面可以看出typeof来判断可以判断简单值类型:undefined, number, string, boolean,而要判断引用值类型:函数、数组、对象、null、new Number(10) 只能用instanceof来判断。 由于javascript是解析性的弱语言,所以最好的解析All In Object是一切(引用类型)都是对象,对象是属性的集合

  1. prototype

然后再来讲原型prototype,javascript中所有的函数都有prototype这个属性,Object对象本身是一个函数对象。既然是Object函数,就肯定会有prototype属性,所以可以看到Object.prototype的值就是Object {}这个原型对象。反过来,当访问Object.prototype对象的constructor这个属性的时候,就得到了Obejct函数。另外,当通过Object.prototype._proto_获取Object原型的原型的时候,将会得到null,也就是说Object {}原型对象就是原型链的终点了,所以Object就是第一级。

原型链是因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。来一张图可能更直观一点 object-prototype

从图中可以看出一个属性查找的过程,当查找一个对象的属性时,javaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 Object.prototype),如果仍然没有找到指定的属性,就会返回 undefined。

而对于还问到了对象创建方式影响原型链,其中比较典型的就是new的过程,new 的过程分为三步,如下代码:

var p = new Person('张三',20);//new创建对象方式

var p={}; //第一步:初始化一个对象p。
p._proto_=Person.prototype;//第二步:将对象p的 __proto__ 属性设置为 Person.prototype
Person.call(p,”张三”,20);//第三步:调用构造函数Person来初始化p。关于call/apply使用又可以讲一大堆了...

对于__proto__的解释:__proto__是一个指针,它指的是构造它的对象的对象的prototype

  1. constructor

忘了说构造函数了,constructor官方解析是这样的:在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中。这个 constructor 保存了指向 function 的一个引用。 也就是在我们定义一个function的时候会为该function添加一个原形(即 prototype)属性,然后为 prototype 对象额外添加一个 constructor 属性,并且该属性保存指向function的一个引用,这样当我们把function作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数。

// 比如一个构造函数:
function Foo() {  }
// 声明一个函数后,默认就生成下面这条语句。
Foo.prototype.constructor === Foo    // true
//修正后,new Foo.prototype.constructor()相当于new Foo()

综上: 所有的对象都有__proto__属性,该属性对应该对象的原型. 所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的_proto_属性. 所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例的构造函数. 函数对象和原型对象通过prototype和constructor属性进行相互关联.

参考文档: 深入理解javascript原型和闭包(完结) 原型与原型链的详细理解 ES5和ES6中的继承

junhey avatar Sep 23 '17 14:09 junhey