javascript中的 prototype, __proto__, constructor 与 原型继承链
2016-09-16 21:44
676 查看
javascript中的 prototype, __proto__
, constructor 与 原型继承链
综述
三个值的含义
每个对象都有自己的的__proto__,这个属性指向自己的构造函数(
constructor)的
prototype,即
obj.__proto__ === obj.constructor.prototype
在javascript中只有函数有自己的
prototype
大部分对象并没有自己的
prototype,因为
prototype表示实例共享的属性,而只有函数可以生成实例,所以…
这里要格外强调一下constructor
constructor并不是实例自己的属性,每个实例的constructor都是一样的,指向构造函数
constructor是原型的属性,因此如果改动原型(重新给原型赋值),会导致constructor不正确
例如:
function a() {} function b() {} b.prototype = new a(); console.log((new a()).constructor); //a() console.log((new b()).constructor); //a()
那么,这个东西有什么用呢?
答:大部分情况是无用的,具体可参考知乎的讨论JavaScript 中对象的 constructor 属性的作用是什么?
javascript中什么是对象
javascript中所有非字面值都是对象字面值中函数和对象仍然是对象,可以使用
{} instanceof Object来验证
注意这里我强调了字面值这个概念,如下
// 文中所有测试环境均为 firefox 48 console.log("" instanceof Object); //false console.log(null instanceof Object); //false console.log(undefined instanceof Object); //false console.log(1 instanceof Object); //false console.log(true instanceof Object); //false function foo() {} console.log(foo instanceof Object); //true console.log({} instanceof Object); //true
字面值应使用
typeof去判断类型
instanceof测试一个对象在其原型链构造函数上是否具有prototype属性。
这与python是不同的,python中一切都是对象,包括字面值
具体可查阅相应的MDN文档
深入探讨
从上述中其实就可以对javascript的原型链略知一二,为了更好的看清各个属性的关系,我们来看看一些数据// print作用是将每个对象的属性直接用console.log输出 function foo() {} var ff = new foo(); var o = {}; print([ff, foo, Function, o, Object]); print([foo.prototype, Function.prototype, Object.prototype]);
整理得出的表格如下:
self | prototype | constructor | __proto__ |
---|---|---|---|
foo {} | undefined | foo() | foo {} |
foo() | foo {} | Function() | function() |
Function() | function() | Function() | function() |
Object {} | undefined | Object() | Object {} |
Object() | Object {} | Function() | function() |
ff是实例对象,所以无原型
函数的构造器是Function()
Function()也是自己的构造器,其
prototype等于
__proto__(代码并没有验证这一点,但是可以测试得出此结论)
普通对象由Object()函数生成,而Object()的构造器是Function()
可能会有几个问题
ff.__proto__是
foo {},也就是
foo.prototype的原型,这是什么?
Function()的原型function()究竟是个什么东西?
解答第一个问题:
当然,原型是个普通对象,所以第二行的
foo {}和第五行的
Object {}都是同一种对象,那为什么有一个是foo而另一个是Object呢?
可以做个小实践,用函数表达式赋值给一个变量,会生成一个匿名函数,检查这个变量的
__proto__发现也是Object{}
所以,其实foo就是这个对象的名字,用console.log输出出来就把名字附加上了
我们来直接来看看上述所有原型的这三个属性
self | prototype | constructor | __proto__ |
---|---|---|---|
foo {} | undefined | foo() | Object {} |
function() | undefined | Function() | Object {} |
Object {} | undefined | Object() | null |
函数原型是对象,函数原型的构造器就是函数本身
从这个表格,也看出了原型链,即:
ff.__proto__(foo {}) --> foo.prototype.__proto__(Object {}) --> foo.prototype.__proto__.__proto__(null)
foo.__proto__(function()) --> foo.__proto__.__proto__(Object {}) --> foo.__proto__.__proto__.__proto__(null)
o.__proto__(Object{}) --> o.__proto__.__proto__(null)
原型链的尽头(root)是Object.prototype。所有对象均从Object.prototype继承属性。
细心的人可能发现,上面出现了一个关于鸡和蛋的问题:
函数是对象:函数Function的原型链(与foo的原型链一致)上出现了Object{}(Object的原型)
对象由函数生成:Object本身就是一个函数(这从第一个表中Object的con
a770
structor就是Function可以看出)
你也可以用代码验证:
console.log(Function instanceof Object); //ture console.log(Object instanceof Function); //true
那么问题来了,究竟是先有Object还是Function呢?
很多语言里都存在一个鸡和蛋的问题
如何实现可以看知乎的讨论先有Class还是先有Object?,摘文中的前几段
简短答案:“鸡・蛋”问题通常都是通过一种叫“自举”(bootstrap)的过程来解决的。 其实“鸡蛋问题”的根本矛盾就在于假定了“鸡”或“蛋”的其中一个要先进入“完全可用”的状态。而许多现实中被简化为“鸡蛋问题”的情况实际可以在“混沌”中把“鸡”和“蛋”都初始化好,而不存在先后问题;在它们初始化的过程中,两者都不处于“完全可用”状态,而完成初始化后它们就同时都进入了可用状态。 打个比方,番茄炒蛋。并不是要先把番茄完全炒好,然后把鸡蛋完全炒好,然后把它们混起来;而是先炒番茄炒到半熟,再炒鸡蛋炒到半熟,然后把两个半熟的部分混在一起同时炒熟。
什么情况下会出现鸡和蛋的问题呢?
就是声明一个包含所有集合的集合啊!好了,你们知道这是罗素悖论,但并不妨碍PL中这样设计。
Function.prototype
Function.prototype是个不同于一般函数(对象)的函数(对象)(作为一个函数,并没有原型)从ECMAScript Specification的Function.prototype摘录几点:
The initial value of Function.prototype is the standard built-in Function prototype object (15.3.4). The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined. The value of the [[Prototype]] internal property of the Function prototype object is the standard built-in Object prototype object (15.2.4). The initial value of the [[Extensible]] internal property of the Function prototype object is true. The Function prototype object does not have a valueOf property of its own; however, it inherits the valueOf property from the Object prototype Object. The length property of the Function prototype object is 0.
图
一张比较经典的图是:近期,在知乎发现了画得非常好而且全面的图,可以参考此篇文章Javascript的原型链图(原创 知乎首发)
参考文章:
从proto和prototype来深入理解JS对象和原型链
相关文章推荐
- 深入理解JavaScript原型:prototype,__proto__和constructor
- javascript 对象及原型继承有关的属性:constructor、prototype、isPrototypeOf、instanceof、in 、hasOwnProperty 等等
- JS原型与原型链终极详解_proto_、prototype及constructor
- 原型链中的prototype、__proto__和constructor的关系
- 彻底理解原型、原型链、new操作符、prototype、__proto__、constructor等属性的概念
- javascript中的__proto__, prototype和constructor
- Javascript中的__proto__、prototype、constructor
- Javascript中的__proto__、prototype、constructor
- javascript对象中的constructor,prototype和__proto__
- 关于JavaScript的prototype、__proto__、constructor、this
- Javascript 原型中的哲学思想 __proto__和prototype
- 原型模式Prototype,constructor,__proto__详解
- Javascript原型(prototype)和原型链(__proto__)
- JavaScript精炼---类(class)、构造函数(constructor)、原型(prototype)
- Javascript中的__proto__、prototype、constructor
- 15条规则解析JavaScript对象布局(__proto__、prototype、constructor)
- JavaScript _proto_、prototype原型、原型链、constructor构造器、类式继承、原型继承
- javascript prototype 、_proto_和constructor之间的关系
- javascript原型——__proto_和prototype
- Javascript中的原型链、prototype、__proto__的关系