Heim >Web-Frontend >js-Tutorial >Detaillierte Erläuterung der JS-Prototypkette

Detaillierte Erläuterung der JS-Prototypkette

小云云
小云云Original
2018-03-13 14:54:092995Durchsuche

Dieser Artikel teilt Ihnen hauptsächlich die detaillierte Erklärung der JS-Prototypkette mit. Nur Funktionen (Funktion) haben das Prototypattribut und Objekte (außer Objekt) haben __proto__. Ich hoffe, es hilft allen.


Die sogenannte Prototypenkette bezieht sich auf die ProtoDies ist eine Zeigerkette!

Die oberste Ebene der Prototypkette ist Object.prototype, und dieses Objekt hat kein Prototypobjekt.

kann in der Chrome-Konsole eingegeben werden:


    Object.__proto__
Die Ausgabe ist:


    function Empty() {}
Prototypenkette, das ist alles.

Ein Prototyp ist ein Objekt, über das andere Objekte die Eigenschaftsvererbung implementieren können.

1. Der Unterschied zwischen Prototyp und __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
Als ich einen Artikel schrieb, der den Unterschied zwischen Prototyp und __proto__ erklärte, suchte ich nach Informationen und fand ein interessantes Phänomen. Die von den folgenden beiden Operationen zurückgegebenen Ergebnisse sind die gleichen:


Function instanceof Object;//true
Object instanceof Function;//true
Was ist los? Beginnen wir mit dem Operator „instanceof“.

1. Was genau macht „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的关系

<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

我们回过头来看第一部分那个“奇怪的现象”,从上面那个图中我们可以看到:


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

Informationen zur Ableitung der Beziehung zwischen Prototyp und __proto__ finden Sie in meinem vorherigen Blog „Drei Bilder zum Verständnis des Prototypobjekts und der Prototypkette von JavaScript“

In diesem Artikel wird versucht, Konzepte wie Prototypen und Prototypenketten in JS und ihre Arbeitsmechanismen zu erklären. Im vorherigen Artikel (Veranschaulichung des Javascript-Kontexts und -Bereichs) wurden die zugehörigen Konzepte des Variablenbereichs in Js vorgestellt. Tatsächlich ist ein Kernthema von Belang: „Welche Variablen kann der Js-Interpreter erhalten, wenn er die aktuelle Codezeile ausführt?“ Bei Ketten geht es tatsächlich um dieses Problem.

Wir wissen, dass alles in Js ein Objekt (Object) ist, aber es gibt keine Klasse in Js; Js ist ein objektorientiertes (OOP) Programmierparadigma, das auf Prototypen basiert. Ja, aber nicht alle Objekte das Attribut prototype haben:



1

2

3

4

5

6

7

8


var a = {}; 

console.log(a.prototype);  //=> undefined

 

var b = function(){}; 

console.log(b.prototype);  //=> {}

 

var c = 'Hello'

console.log(c.prototype);  //=> undefined

prototype ist ein Attribut, das in jeder function-Definition enthalten ist, aber function selbst ist in Js auch ein Objekt. Schauen wir uns zunächst die Unterschiede zwischen den folgenden Konzepten an:

1 . function, Function, Object und {}

function ist ein Schlüsselwort in JS, das zum Definieren von Variablen des Funktionstyps verwendet wird:



1

2

3

4

5

6

7

8

9


function f1(){ 

  console.log('This is function f1!');

}

typeof(f1);  //=> 'function'

 

var f2 = function(){ 

  console.log('This is function f2!');

}

typeof(f2);  //=> 'function'

Wenn Sie einen eher objektorientierten Ansatz zum Definieren von Funktionen verwenden, können Sie Function verwenden:



1

2

3

4

5


var f3 = new Function("console.log('This is function f3!');"); 

f3();        //=> 'This is function f3!' 

typeof(f3);  //=> 'function'

 

typeof(Function); //=> 'function'

Tatsächlich ist Function eine Klasse, die zum Erstellen von Funktionstypvariablen verwendet wird, oder ein ähnlicher Konstruktor von Funktionstypinstanzen. Es gibt Object oder String, Number usw. Sie sind alle Konstruktoren von in Js integrierten Typinstanzen. Das speziellere ist Object, das zum Generieren von Objekttypen verwendet wird: {}



1

2

3

4

5

6

7


var o1 = new Object(); 

typeof(o1);      //=> 'object'

 

var o2 = {}; 

typeof(o2);     //=> 'object'

 

typeof(Object); //=> 'function'

2. prototype VS __proto__

Nachdem wir die oben genannten Konzepte geklärt haben, schauen wir uns prototype an:

Jede Funktion hat zwei Eigenschaften: length und prototype

prototype und length sind zwei Attribute, die bei jedem Funktionstyp vorhanden sind, andere Nicht-Funktionstypen jedoch nicht (das Beispiel am Anfang hat den Grund bereits erklärt). Für diesen Vergleich kann es leicht ignoriert oder missverstanden werden, da alle Arten von Konstruktoren selbst Funktionen sind und daher das Attribut prototype haben:



1

2

3

4


// Node

console.log(Object.prototype);  //=> {} 

console.log(Function.prototype);//=> [Function: Empty] 

console.log(String.prototype);  //=> [String: '']

Mit Ausnahme von prototype verfügen alle Objekte in JS (mit Ausnahme von Sonderfällen wie undefined und null) über ein integriertes [[Prototype]]-Attribut, das auf das prototype seiner „Elternklasse“ verweist. . Es gibt keine klare Möglichkeit, integrierte Eigenschaften im ECMA-Standard zu erhalten, aber viele Js-Implementierungen (wie Node, die meisten Browser usw.) stellen ein __proto__-Attribut bereit, um darauf zu verweisen [[Prototype]] Das folgende Beispiel soll veranschaulichen, wie __proto__ in der Instanz auf prototype des Konstruktors zeigt:



1

2

3

4

5

6

7

8

9

10

11


var Person = function(){}; 

Person.prototype.type = 'Person'

Person.prototype.maxAge = 100;

 

var p = new Person(); 

console.log(p.maxAge); 

p.name = 'rainy';

 

Person.prototype.constructor === Person;  //=> true 

p.__proto__ === Person.prototype;         //=> true 

console.log(p.prototype);                 //=> undefined

Das obige Codebeispiel kann durch die folgende Abbildung erklärt werden:

Person ist eine Funktionstypvariable und wird daher mit dem prototype-Attribut Das prototype im Attribut verweist auf constructor selbst; die Instanz Person der Klasse new, die durch das Schlüsselwort Person generiert wird, verweist auf den Prototyp von p1 durch das Attribut __proto__. Das Person dient hier nur zur Veranschaulichung der Beziehung zwischen der Instanz __proto__ und der übergeordneten Klasse, wenn sie intern implementiert wird (wobei auf den Prototyp der übergeordneten Klasse verwiesen wird). Während des tatsächlichen Vorgangs kann die Instanz direkt abgerufen werden Der Prototyp der übergeordneten Klasse wird über p1-Attribute verwendet, wodurch die Funktion der Vererbung realisiert wird. .

3. Prototypenkette

Nachdem wir die Konzepte und Beziehungen zwischen

und prototype geklärt haben, werden wir den Satz „Alles in Js ist ein Objekt“ besser verstehen. Dann denken wir: Da __proto__ ein eingebautes Attribut (fast) aller Objekte ist und auf den Prototyp der übergeordneten Klasse verweist, bedeutet das, dass wir „stromaufwärts“ gehen und die Quelle finden können? Schauen wir uns das folgende Beispiel an: __proto__



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17


// Node

var Obj = function(){}; 

var o = new Obj(); 

o.__proto__ === Obj.prototype;  //=> true 

o.__proto__.constructor === Obj; //=> true

 

Obj.__proto__ === Function.prototype; //=> true 

Obj.__proto__.constructor === Function; //=> true

 

Function.__proto__ === Function.prototype; //=> true 

Object.__proto__ === Object.prototype;     //=> false 

Object.__proto__ === Function.prototype;   //=> true

 

Function.__proto__.constructor === Function;//=> true 

Function.__proto__.__proto__;               //=> {} 

Function.__proto__.__proto__ === o.__proto__.__proto__; //=> true 

o.__proto__.__proto__.__proto__ === null;   //=> true

Wie aus den obigen Beispielen und Abbildungen ersichtlich ist, verfügt das prototype-Objekt auch über das __proto__-Attribut, das auf null zurückgeführt wird. Die Funktion des Schlüsselworts

new besteht darin, die Verbindung zwischen der im obigen Bild gezeigten Instanz und dem Prototyp der übergeordneten Klasse zu vervollständigen und ein neues Objekt zu erstellen Wie aus dem obigen Bild hervorgeht, ist es tatsächlich der Prototyp, der bestimmt, ob instanceof (und __proto__...) auf die übergeordnete Klasse zeigt: __proto__.__proto__



1

2

3

4

5

6

7

8

9

10


var Obj = function(){}; 

var o = new Obj();

 

instanceof Obj; //=> true 

instanceof Object; //=> true 

instanceof Function; //=> false

 

o.__proto__ === Obj.prototype; //=> true 

o.__proto__.__proto__ === Object.prototype; //=> true 

o.__proto__.__proto__ === Function;  //=> false

JS-objektorientierte Prototypenkette



Objektorientierte JS-Prototypkette

Objektprototypkette

  1. Solange es ein Objekt ist, hat es einen Prototyp

  2. Prototypen sind auch Objekte

  3. Solange es ein Objekt ist, hat es einen Prototyp, und ein Prototyp ist auch ein Objekt, also solange ein Das Objekt ist definiert, sein Prototyp kann gefunden werden usw. Diese Struktur stellt eine Folge von Objekten dar und wird als Prototypenkette

  4. Wo ist der Kopf von die Prototypenkette?

  5. Wie sieht eine standardmäßige Prototypenkettenstruktur aus?

  6. Welche Änderungen weist die Prototypenkettenstruktur gegenüber bekannten Syntaxstrukturen auf? ?

Prototypkette Die Struktur der

  1. Prototypkettenvererbung besteht darin, die Prototypkettenstruktur zu verwenden und zu ändern (hinzufügen , löschen, ändern Sie Mitglieder im Knoten), sodass das Instanzobjekt den gesamten Prototyp verwenden kann. Alle Mitglieder (Eigenschaften und Methoden) in der Kette

  2. Bei Verwendung der Prototypkettenvererbung muss das Attribut erfüllt sein Suchprinzip

Attributsuchprinzip

  1. Das sogenannte Attributsuchprinzip besteht darin, dass ein Objekt beim Zugriff auf Attribute und Methoden zunächst nach sucht

  2. im aktuellen Objekt, wenn es in einem Attribut oder einer Methode gespeichert ist, beenden Sie die Suche und verwenden Sie das Attribut und die Methode direkt

  3. Wenn Das Objekt hat keine geänderten Mitglieder, dann suchen Sie in seinem Prototypobjekt

  4. Wenn der Prototyp Das Objekt dieses Mitglied enthält, dann beenden Sie die Suche und verwenden Sie

  5. direkt. Wenn der Prototyp noch nicht existiert, gehen Sie zum Prototyp des Prototyps und suchen Sie nach

  6. und so weiter, bis kein Object.prototype vorhanden ist, und geben Sie dann undefind zurück.

  7. Wenn es sich um einen Methodenaufruf handelt, enthält er einen Fehler. Das xxxx ist keine Funktion

Prototyp-Kettenstrukturdiagramm

  1. Konstruktor-Objekt-Prototyp-Kettenstrukturdiagramm
    function Person (){}; var p = new Person();

  2. {} Objekt-Prototyp-Kettenstrukturdiagramm

  3. [] Array-Prototyp-Kettenstrukturdiagramm

  4. Object.prototype Entsprechender Konstruktor

  5. p Entsprechender Konstruktor

  6. p -> pTag.prototype( is o ) -> Object.prototype ->

var o = {
    appendTo: function ( dom ) {
    }
};
function pTag() {}
pTag.prototype = o;

var p = new pTag();

函数的构造函数 Function

在 js 中 使用 Function 可以实例化函数对象. 也就是说在 js 中函数与普通对象一样, 也是一个对象类型( 非常特殊 )

  1. 函数是对象, 就可以使用对象的动态特性

  2. 函数是对象, 就有构造函数创建函数

  3. 函数是函数, 可以创建其他对象(函数的构造函数也是函数)

  4. 函数是唯一可以限定变量作用域的结构

函数是 Function 的实例

new Function( arg0, arg1, arg2, ..., argN, body );
  1. Function 中的参数全部是字符串

  2. 该构造函数的作用是将 参数链接起来组成函数

  • 如果参数只有一个, 那么表示函数体

  • 如果参数有多个, 那么最后一个参数表示新函数体, 前面的所有参数表示新函数的参数

  • 如果没有参数, 表示创建一个空函数

创建一个打印一句话的函数

    // 传统的
    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();

利用 Function 创建一个函数, 要求传入两个数字, 打印其和

    var func = new Function( 'num1', 'num2', 'console.log( num1 + num2 );' );

练习: 利用 Function 创建一个函数, 要求允许函数调用时传入任意个数参数, 并且函数返回这些数字中最大的数字.
练习: 利用 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;' )

解决代码太长的办法:

  1. 利用 加法 连接字符串

    var func = new Function( 'a', 'b', 'c',
            'var res = a > b ? a : b;' +
            'res = res > c ? res : c;' +
            'return res;' );
  2. 利用字符串特性( 刚学 )

    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 );' );
  3. ES6 的语法( 少浏览器实现 )

  • 使用 键盘左上角的 左单引号 表示可换行字符串的界定符

  • (最终)利用 DOM 的特性完成该方法

  • arguments 对象

    arguments 是一个伪数组对象. 它表示在函数调用的过程中传入的所有参数的集合.
    在函数调用过程中没有规定参数的个数与类型, 因此函数调用就具有灵活的特性, 那么为了方便使用,
    在 每一个函数调用的过程中, 函数代码体内有一个默认的对象 arguments, 它存储着实际传入的所有参数.

    js 中函数并没有规定必须如何传参

    1. 定义函数的时候不写参数, 一样可以调用时传递参数

    2. 定义的时候写了参数, 调用的时候可以不传参

    3. 定义的时候写了一参数, 调用的时候可以随意的传递多个而参数

    在代码设计中, 如果需要函数带有任意个参数的时候, 一般就不带任何参数, 所有的 参数利用 arguments 来获取.
    一般的函数定义语法, 可以写成:

        function foo ( /* ... */ ) {
        }

    利用 Function 创建一个函数, 要求允许函数调用时传入任意个数参数, 并且函数返回这些数字中最大的数字.

        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() 得到一个 函数对象
    1. 函数有 __proto__ 属性

    2. 函数的构造函数是 Function

    3. 函数应该继承自 Function.prototype

    4. Fucntion.prototype 继承自 Object.protoype

    5. 构造函数有prototype, 实例对象才有__proto__指向原型, 构造函数的原型才有 constructor 指向构造函数

    intanceof

    array instanceof Array
    判断 构造函数 Array 的原型 是否在 实例对象 array 的原型链存在

    相关推荐:

    关于js原型链的7篇文章推荐

    js原型链继承的几个细节问题

    js原型链原理看图说明_javascript技巧

    Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der JS-Prototypkette. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn