studyNotes
studyNotes copied to clipboard
JS原型、原型链深入理解
前几天被阿里问到了一个原型和原型链的相关问题,其实大体上都懂,细节方面没有认识到,这里可以好好总结下了。
- 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是一切(引用类型)都是对象,对象是属性的集合。
- prototype
然后再来讲原型prototype,javascript中所有的函数都有prototype这个属性,Object对象本身是一个函数对象。既然是Object函数,就肯定会有prototype属性,所以可以看到Object.prototype的值就是Object {}这个原型对象。反过来,当访问Object.prototype对象的constructor这个属性的时候,就得到了Obejct函数。另外,当通过Object.prototype._proto_获取Object原型的原型的时候,将会得到null,也就是说Object {}原型对象就是原型链的终点了,所以Object就是第一级。
原型链是因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。来一张图可能更直观一点

从图中可以看出一个属性查找的过程,当查找一个对象的属性时,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
- 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属性进行相互关联.