This article mainly shares with you the detailed explanation of the JS prototype chain. Only functions (Function) have the prototype attribute, and objects (except Object) have __proto__. Hope it helps everyone.
##The so-called prototype chain refers to the # in the picture ##proto
This is a pointer chain! The top level of the prototype chain is Object.prototype, and this object has no prototype object.
can be entered in the chrome console:
Object.__proto__
function Empty() {}
The prototype is an object through which other objects can implement property inheritance.
1. The difference between prototype and __proto__<br/>
<br/>##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
Function instanceof Object;//true Object instanceof Function;//true
What is this? Let’s start with the operator instanceof. <br/>
1. What exactly does instanceof do?
我曾经简单理解instanceof只是检测一个对象是否是另个对象new出来的实例(例如var a = new Object(),a instanceof Object返回true),但实际instanceof的运算规则上比这个更复杂。
首先w3c上有官方解释(传送门,有兴趣的同学可以去看看),但是一如既往地让人无法一目了然地看懂……
知乎上有同学把这个解释翻译成人能读懂的语言(传送门),看起来似乎明白一些了:
<br/>
//假设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的关系
<br/>
<br/>
<br/>
我们再配合代码来看一下就明白了:<br/>
//①构造器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
我们回过头来看第一部分那个“奇怪的现象”,从上面那个图中我们可以看到:
<br/>
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
As for how to deduce the relationship between prototype and __proto__, you can refer to the previous blog I wrote "Three Pictures to Understand the Prototype Object and Prototype Chain of JavaScript"
This article Try to explain concepts such as prototype and prototype chain in JS and their working mechanisms. The previous article (Illustrating Javascript Context and Scope) introduced the related concepts of variable scope in JS. In fact, a core issue of concern is: "What variables can the JS interpreter obtain when executing the current line of code?" Prototypes and prototype chains are actually about this issue.
We know that everything in Js is an object (Object), but there is no class in Js; Js is an object-oriented (OOP) programming paradigm implemented based on prototype (prototype-based). , but not all objects have the prototype
attribute:
<br/>
<br/>
##1234567 8 | <br/>
|
prototype
is an attribute that comes with each function
definition, but function
itself in Js is also an object. Let’s take a look at the following concepts first. The difference:
function
, Function
, Object
and {}
function
is a keyword in JS, used to define variables of function type. There are two syntax forms:
<br/>
<br/>
1 2 3 4 5 6 7 8 9 | <br/>
|
If you use a more object-oriented approach to define functions, you can use Function
:
<br/>
<br/>
1 2 3 4 5 | <br/>
|
In factFunction
is a class used to construct function type variables, or the constructor (constructor) of function type instances; similar to Object
orString
, Number
, etc. are all constructors of Js built-in type instances. The more special one is Object
, which is used to generate object types. Its abbreviation is {}
:
<br/>
<br/>
1 2 3 4 5 6 7 | <br/>
|
prototype
VS __proto__
After understanding the above concepts, let’s look at prototype
:
Each function has two properties:
length
andprototype
##prototype and
length are every function The type has two attributes that come with it, but other non-function types do not (as shown in the example at the beginning). The reason why this is easily overlooked or misunderstood is because the constructors of all types are themselves functions, so they come with it.
prototypeAttributes:
<br/>
<br/>
2 3 4 |
|
Except prototype
, all objects in Js (except for special cases such as undefined
, null
) have a built-in [[ Prototype]]
attribute, pointing to the prototype
of its "parent class". This built-in attribute does not give a clear way to obtain it in the ECMA standard, but many Js implementations (such as Node, most Browsers, etc.) provide a __proto__
attribute to refer to this [[Prototype]]
. We use the following example to illustrate the __proto__
in the example. How to point to the prototype
of the constructor:
<br/>
<br/>
# #1234567 8 9 10 11 | <br/>
|
The above code example can be explained by the following picture:
Person
is a function type variable, so it comes with prototype
attribute, the constructor
in the prototype
attribute points to the Person
itself; the Person# generated by the
new keyword The instance of ## class
p1 points to the prototype of
Person through the
__proto__ attribute. The
__proto__ here is just to illustrate the relationship between the instance
p1 and the parent class when it is implemented internally (pointing to the prototype of the parent class). During the actual operation, the instance can be directly passed
.Get the attributes in the prototype of the parent class, thus realizing the function of inheritance.
prototype and
__proto__, we will understand the concept of "everything in Js is an object" Sentences have a deeper understanding. Then we will think that since
__proto__ is a built-in attribute of (almost) all objects and points to the prototype of the parent class, does that mean that we can "go upstream" and find the source? Let’s look at the following example:
<br/>
<br/>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <br/>
|
As can be seen from the above examples and illustrations, the prototype
object also has the __proto__
attribute, tracing back up to null
.
new
The function of the keyword is to complete the connection between the instance and the parent class prototype shown in the above figure and create a new object; instanceof
Key The function of the word can also be seen from the picture above. It is actually to determine whether the prototype of the parent class pointed to by __proto__
(and __proto__.__proto__
...) is:
<br/>
<br/>
1 2 3 4 5 6 7 8 9 10 | <br/>
|
<br/>
<br/>
As long as it is an object, it has a prototype
Prototypes are also objects
As long as it is an object, it has a prototype, and the prototype is also an object, so as long as an object is defined, its prototype can be found, and so on. Constituting a sequence of objects, this structure is called the prototype chain
Where is the head of the prototype chain?
What does a default prototype chain structure look like?
What modifications does the prototype chain structure have to known syntax structures?
Prototype chain inheritance is to use and modify the prototype chain structure (add, delete, modify members in the node), so that the instance object can use the entire prototype All members (properties and methods) in the chain
Using prototype chain inheritance must satisfy the property search principle
The so-called property search principle is that when an object accesses properties and methods, it first searches in the current object
If the current object is stored in a property or Method, stop searching and use the property and method directly
If the object has no changed members, then search in its prototype object
If the prototype If the object contains this member, then stop searching and directly use
. If the prototype does not exist yet, go to the prototype of the prototype to find
and so on. Until there is no Object.prototype, then return undefind.
If the method is called, an error will be included. The xxxx is not a function
Constructor object prototype chain structure diagram<br/>function Person (){}; var p = new Person();
<br/>
{} Object prototype chain structure diagram<br/>
[] Array prototype chain structure diagram<br/>
Object.prototype
Corresponding constructor <br/>
p Corresponding construct Function
var o = { appendTo: function ( dom ) { } }; function pTag() {} pTag.prototype = o; var p = new pTag();
在 js 中 使用 Function 可以实例化函数对象. 也就是说在 js 中函数与普通对象一样, 也是一个对象类型( 非常特殊 )
函数是对象, 就可以使用对象的动态特性
函数是对象, 就有构造函数创建函数
函数是函数, 可以创建其他对象(函数的构造函数也是函数)
函数是唯一可以限定变量作用域的结构
new Function( arg0, arg1, arg2, ..., argN, body );
Function 中的参数全部是字符串
该构造函数的作用是将 参数链接起来组成函数
如果参数只有一个, 那么表示函数体
如果参数有多个, 那么最后一个参数表示新函数体, 前面的所有参数表示新函数的参数
如果没有参数, 表示创建一个空函数
// 传统的 function foo () { console.log( '你好' ); } // Function var func = new Function( 'console.log( "你好" );' ); // 功能上, 这里 foo 与 func 等价
// 传统 function foo () {} // Function var func = new Function();
// 传统 function foo ( num ) { console.log( num ); } // Function var func = new Function ( "num" ,"console.log( num );" ); func();
var func = new Function( 'num1', 'num2', 'console.log( num1 + num2 );' );
练习: 利用 Function 创建一个函数, 要求允许函数调用时传入任意个数参数, 并且函数返回这些数字中最大的数字.<br/>练习: 利用 Function 创建一个求三个数中最大数的函数.
// 传统 function foo ( a, b, c ) { var res = a > b ? a : b; res = res > c ? res : c; return res; } // Function var func = new Function( 'a', 'b', 'c', 'var res = a > b ? a : b;res = res > c ? res : c;return res;' )
解决代码太长的办法:
利用 加法 连接字符串
var func = new Function( 'a', 'b', 'c', 'var res = a > b ? a : b;' + 'res = res > c ? res : c;' + 'return res;' );
利用字符串特性( 刚学 )
function foo ( a, b, c ) { var res = a > b ? a : b; res = res > c ? res : c; return res; } var func = new Function( 'a', 'b', 'c', 'return foo( a, b, c );' );
ES6 的语法( 少浏览器实现 )
使用 键盘左上角的 左单引号 表示可换行字符串的界定符
(最终)利用 DOM 的特性完成该方法
arguments 是一个伪数组对象. 它表示在函数调用的过程中传入的所有参数的集合.<br/>在函数调用过程中没有规定参数的个数与类型, 因此函数调用就具有灵活的特性, 那么为了方便使用,<br/>在 每一个函数调用的过程中, 函数代码体内有一个默认的对象 arguments, 它存储着实际传入的所有参数.
js 中函数并没有规定必须如何传参
定义函数的时候不写参数, 一样可以调用时传递参数
定义的时候写了参数, 调用的时候可以不传参
定义的时候写了一参数, 调用的时候可以随意的传递多个而参数
在代码设计中, 如果需要函数带有任意个参数的时候, 一般就不带任何参数, 所有的 参数利用 arguments 来获取.<br/>一般的函数定义语法, 可以写成:
function foo ( /* ... */ ) { }
function foo ( ) { // 所有的参数都在 arguments 中. 将其当做数组使用 // 问题而已转换成在有一个数组中求最大值 var args = arguments; var max = args[ 0 ]; for ( var i = 1; i < args.length; i++ ) { if ( max < args[ i ] ) { max = args[ i ]; } } return max; }
练习: 利用 Function 写一个函数, 要求传入任意个数字 求和
任意的一个函数, 都是相当于 Function 的实例. 类似于 {} 与 new Object() 的关系
function foo () {}; // 告诉解释器, 有一个对象叫 foo, 它是一个函数 // 相当于 new Function() 得到一个 函数对象
函数有 __proto__
属性
函数的构造函数是 Function
函数应该继承自 Function.prototype
Fucntion.prototype
继承自 Object.protoype
构造函数有prototype, 实例对象才有__proto__指向原型, 构造函数的原型才有 constructor 指向构造函数
array instanceof Array
判断 构造函数 Array 的原型 是否在 实例对象 array 的原型链存在
相关推荐:
The above is the detailed content of Detailed explanation of JS prototype chain. For more information, please follow other related articles on the PHP Chinese website!