该文章来自于最详尽的 JS 原型与原型链终极详解,没有「可能是」的学习总结
一:对象的分类
- JS中对象分为两种,函数对象和普通对象。也称为Function Object和Object。通过typeof 可以查看具体的对象类型。
- JS中的函数对象,在和new结合的时候,可以创建新的对象。JS提供了两个最基本的函数对象 Function 和 Object。其他所有的对象都由这两个函数对象演进而来
- JS中的函数对象,有两个方法可以创建,一个是通过new Function(),一个是通过
function() {}
声明。 - JS中的普通对象,也有两个方法可以创建,一个是通过
new (非Function函数对象/**Object**)
,一个是通过{ }
等各类语法声明。Array也可视为一个普通对象,可以通过new Array(),也可以通过[] - 另外,还有一个特殊的
Object.create()
方法,可以由一个普通对象创建一个新的普通对象。此时第一个普通对象起到类似函数对象的作用,不同之处在于,新建对象的__proto__指向第二个普通对象自身。因为普通函数没有prototype属性(这个可以看完下面的回头再理解下)。
var o1 = {};
var o2 =new Object();
var o3 = new f1();
var o4 = Object.create(o2)
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
console.log(typeof o4); //object
二:prototype 和 __proto__
- JS中的任意一个对象都包括一个 __proto__属性。该属性在ES2015之前,并没有在标准中明确定义,而是一个大多数浏览器默认支持的一个属性,也称为[[prototype]]
- JS中的任意一个函数对象都包括了一个prototype属性。该属性相当于是当前函数对象的一个特殊实例。一般为普通对象。
- JS中任意一个对象的__proto__属性,根据new的特性,都指向创建该对象的函数对象的prototype属性。即
(普通对象).__proto__ == (创建它的函数对象).prototype
(函数对象).__proto__ == Function.prototype // 函数对象都由 new Function()创建
Function和Object都是函数对象,都是通过new Function()
创建,所以
Function.__proto__ == Function.prototype
Object.__proto__ == Function.prototype
- JS中的函数对象的prototype一般都为普通对象即
typeof A.prototype == 'Object' // A
但Function除外,因为Function的新建实例还是一个函数对象,所以
typeof Function.prototype == 'function'
但是该prototype是一个特殊的函数对象。它没有prototype,另外,它的__proto__指向了Object.prototype,而不是Function的prototype,即
typeof Function.prototype == 'function'
Function.prototype.__proto__ == Object.prototype
- JS中的所有函数对象的prototype都有一个constructor函数,称为构建函数,该构建函数指向当前函数对象。即
function f1() {}
f1.prototype.constructor == f1
Function.prototype.constructor == Function
-
prototype,__proto__以及constructor的关系图
其中的person1.constructor其实是通过原型链继承在Person.prototype中寻得。
三:原型链继承
JS中的原生继承是通过原型链完成的。以下面的代码为例子
var Person = function(name){
this.name = name;
};
Person.prototype.getName = function(){
return this.name; // tip: 当函数执行时这个 this 指的是谁?
}
var person1 = new person('Mick');
person1.getName(); //Mick
person1.name; //Mick
person1.toString(); // [object Object]
- 当person1执行getName方法的时候,先在person1的自身属性中寻找。此时自有属性只有name属性,未找到,则继续在person1的__proto__属性中寻找
- 因为
person1.__proto__ = Person.prototype
。此时在Person.prototype中寻找getName属性,此时寻找得到,将Person.prototype.getName返回作为person1.getName,进行执行。 - 当person1执行toString方法的时候,在Person.prototype中未能找到,则继续在Person.prototype.__proto__中寻找。
- Person.prototype作为Person的一个特殊实例,它是普通对象。普通对象都由new Object创建。因此Person.prototype.__proto__ = Object.prototype。因此继续在Object.prototype中寻找,发现了toString方法,将Object.prototype.toString返回作为person1.toString,进行执行。
- 需要注意,JS中的原型链继承,指的是新建对象和创建函数对象的prototype之间的关系,而不是和创建函数的关系。能够在原型链继承上传递下去的只有原型对象prototype上的函数。比如Object拥有geOwnPropertyNames方法,但Object.prototype却不包含,所以person1也无法拥有getOwnPropertyNames 方法。同样的,如果新建一个函数对象Student,让它继承Person函数对象,那么new Stuednet()新建的对象也只能继承Person.prototype.getName,而不能继承person.name属性
四:JS中原型链继承链路
- Function函数对象
Function.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
- Object函数对象
Object.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
- 自定义函数对象
function f1() {}
f1.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
Object.prototype.__proto__ == null
- 自定义函数对象实例--也是普通对象
function f1() {}
o1 = new f1()
o1.__proto__ = f1.prototype
f1.prototype__proto__ == Object.prototype
Object.prototype.__proto__ == null
- 自定义函数对象继承--继承自某一个自定义对象
function f1() {}
function f2() {} // 设定f2继承自f1,具体如何实现继承,可以查看另一篇文章
o2 = new f2()
o2.__proto__ = f2.prototype
f2.prototype.__proto__ = f1.prototype
f1.prototype__proto__ == Object.prototype
Object.prototype.__proto__ == null
五:总结
- 所有的普通对象,都会继承(1)创建它的函数对象的prototype上的属性(2)函数对象继承自其它函数对象prototype上的属性(3)Object函数对象的prototype上的属性
- 所有的函数对象,都会继承(1)Function.prototype上的属性(2)Object函数对象的prototype上的属性
- 最后所有的对象的原型链都会追溯到null标识符上
六:Function和Object自带属性
参考链接
//www.greatytc.com/p/dee9f8b14771
//www.greatytc.com/p/652991a67186
//www.greatytc.com/p/a4e1e7b6f4f8