时间:2021-07-01 10:21:17 帮助过:5人阅读
所谓原型链,指的就是图中的proto这一条指针链!
原型链的顶层就是Object.prototype,而这个对象的是没有原型对象的。
可在chrome的控制台里面输入:
Object.__proto__
输出是:
function Empty() {}
原型链,如此而已。
原型是一个对象,其他对象可以通过它实现属性继承。
一、prototype和__proto__的区别
var a = {}; console.log(a.prototype); //undefined console.log(a.__proto__); //Object {} var b = function(){} console.log(b.prototype); //b {} console.log(b.__proto__); //function() {}
/*1、字面量方式*/ var a = {}; console.log(a.__proto__); //Object {} console.log(a.__proto__ === a.constructor.prototype); //true /*2、构造器方式*/ var A = function(){}; var a = new A(); console.log(a.__proto__); //A {} console.log(a.__proto__ === a.constructor.prototype); //true /*3、Object.create()方式*/ var a1 = {a:1} var a2 = Object.create(a1); console.log(a2.__proto__); //Object {a: 1} console.log(a.__proto__ === a.constructor.prototype); //false(此处即为图1中的例外情况)
var A = function(){}; var a = new A(); console.log(a.__proto__); //A {}(即构造器function A 的原型对象) console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象) console.log(a.__proto__.__proto__.__proto__); //null
我在写一篇图解prototype和__proto__的区别时,搜资料搜到了一个有意思的现象,下面这两个运算返回的结果是一样的:
Function instanceof Object;//true Object instanceof Function;//true
这个是怎么一回事呢?要从运算符instanceof说起。
一、instanceof究竟是运算什么的?
我曾经简单理解instanceof只是检测一个对象是否是另个对象new出来的实例(例如var a = new Object(),a instanceof Object返回true),但实际instanceof的运算规则上比这个更复杂。
首先w3c上有官方解释(传送门,有兴趣的同学可以去看看),但是一如既往地让人无法一目了然地看懂……
知乎上有同学把这个解释翻译成人能读懂的语言(传送门),看起来似乎明白一些了:
//假设instanceof运算符左边是L,右边是R L instanceof R //instanceof运算时,通过判断L的原型链上是否存在R.prototype L.__proto__.__proto__ ..... === R.prototype ? //如果存在返回true 否则返回false
注意:instanceof运算时会递归查找L的原型链,即L.__proto__.__proto__.__proto__.__proto__...直到找到了或者找到顶层为止。
所以一句话理解instanceof的运算规则为:
instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型。
二、图解构造器Function和Object的关系
我们再配合代码来看一下就明白了:
//①构造器Function的构造器是它自身 Function.constructor=== Function;//true //②构造器Object的构造器是Function(由此可知所有构造器的constructor都指向Function) Object.constructor === Function;//true //③构造器Function的__proto__是一个特殊的匿名函数function() {} console.log(Function.__proto__);//function() {} //④这个特殊的匿名函数的__proto__指向Object的prototype原型。 Function.__proto__.__proto__ === Object.prototype//true //⑤Object的__proto__指向Function的prototype,也就是上面③中所述的特殊匿名函数 Object.__proto__ === Function.prototype;//true Function.prototype === Function.__proto__;//true
三、当构造器Object和Function遇到instanceof
我们回过头来看第一部分那个“奇怪的现象”,从上面那个图中我们可以看到:
Function.__proto__.__proto__ === Object.prototype;//true Object.__proto__ === Function.prototype;//true
所以再看回第一点中我们说的instanceof的运算规则,Function instanceof Object 和 Object instanceof Function运算的结果当然都是true啦!
如果看完以上,你还觉得上面的关系看晕了的话,只需要记住下面两个最重要的关系,其他关系就可以推导出来了:
1、所有的构造器的constructor都指向Function
2、Function的prototype指向一个特殊匿名函数,而这个特殊匿名函数的__proto__指向Object.prototype
至于prototype和__proto__的关系如何推导,可以参考我写的上一篇博客《三张图搞懂JavaScript的原型对象与原型链》
本文尝试阐述Js中原型(prototype)、原型链(prototype chain)等概念及其作用机制。上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关注的一个核心问题是:“在执行当前这行代码时Js解释器可以获取哪些变量”,而原型与原型链实际上还是关于这一问题。
我们知道,在Js中一切皆为对象(Object),但是Js中并没有类(class);Js是基于原型(prototype-based)来实现的面向对象(OOP)的编程范式的,但并不是所有的对象都拥有prototype
这一属性:
1 2 3 4 5 6 7 8 |
|
prototype
是每个function
定义时自带的属性,但是Js中function
本身也是对象,我们先来看一下下面几个概念的差别:
function
、Function
、Object
和{}
function
是Js的一个关键词,用于定义函数类型的变量,有两种语法形式:
1 2 3 4 5 6 7 8 9 |
|
如果用更加面向对象的方法来定义函数,可以用Function
:
1 2 3 4 5 |
|
实际上Function
就是一个用于构造函数类型变量的类,或者说是函数类型实例的构造函数(constructor);与之相似有的Object
或String
、Number
等,都是Js内置类型实例的构造函数。比较特殊的是Object
,它用于生成对象类型,其简写形式为{}
:
1 2 3 4 5 6 7 |
|
prototype
VS __proto__
清楚了上面的概念之后再来看prototype
:
Each function has two properties:
length
andprototype
prototype
和length
是每一个函数类型自带的两个属性,而其它非函数类型并没有(开头的例子已经说明),这一点之所以比较容易被忽略或误解,是因为所有类型的构造函数本身也是函数,所以它们自带了prototype
属性: