Maison >interface Web >js tutoriel >L'explication détaillée ultime des prototypes JavaScript et des compétences de prototypes chains_javascript
L'explication détaillée ultime des prototypes et chaînes de prototypes JavaScript
1. Objets ordinaires et objets fonctionnels
En JavaScript, tout est objet ! Mais les objets sont également différents. Il est divisé en objets ordinaires et objets fonction. Object et Function sont les objets fonction fournis avec JS. Voici quelques exemples
function f1(){}; var f2 = function(){}; var f3 = new Function('str','console.log(str)'); var o3 = new f1(); var o1 = {}; var o2 =new Object(); console.log(typeof Object); //function console.log(typeof Function); //function console.log(typeof o1); //object console.log(typeof o2); //object console.log(typeof o3); //object console.log(typeof f1); //function console.log(typeof f2); //function console.log(typeof f3); //function
Dans l'exemple ci-dessus, o1 o2 o3 sont des objets ordinaires et f1 f2 f3 sont des objets fonction. Comment faire la différence est en fait très simple. Tous les objets créés via new Function() sont des objets fonction, et les autres sont des objets ordinaires. f1, f2, sont tous créés via new Function() en dernière analyse. Les objets de fonction sont également créés via New Function().
2. Objet prototype
En JavaScript, chaque fois qu'un objet (fonction) est défini, l'objet contiendra des propriétés prédéfinies. L'une des propriétés de l'objet fonction est l'objet prototype. Remarque : les objets ordinaires n'ont pas de prototype, mais ont l'attribut __proto__.
Les objets prototypes sont en fait des objets ordinaires (sauf Function.prototype, qui est un objet fonction, mais il est très spécial. Il n'a pas d'attribut prototype (comme mentionné précédemment, les objets fonction ont tous des attributs prototype)). Regardez l'exemple ci-dessous :
function f1(){}; console.log(f1. prototype) //f1 {} console.log(typeof f1. prototype) //Object console.log(typeof Function. prototype) // Function console.log(typeof Object. prototype) // Object console.log(typeof Function. prototype. prototype) //undefined
D'après le résultat de cette phrase console.log(f1. prototype) //f1 {}, nous pouvons voir que f1 prototype est un objet instance de f1. Lorsque f1 est créé, un objet instance est créé et attribué à son prototype. Le processus de base est le suivant :
var temp = new f1(); f1. prototype = temp;
Il est donc facile de comprendre pourquoi Function.prototype est un objet fonction. Comme mentionné ci-dessus, tous les objets générés par new Function () sont des objets fonction, donc temp est un objet fonction.
var temp = new Function (); Function. prototype = temp;
A quoi sert l'objet prototype ? Principalement utilisé pour l'héritage. Donnez un exemple :
var person = function(name){ this.name = name }; person.prototype.getName = function(){ return this.name; } var zjh = new person(‘zhangjiahao'); zjh.getName(); //zhangjiahao
从这个例子可以看出,通过给person.prototype设置了一个函数对象的属性,那有person实例(例中:zjh)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。
三.原型链
JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:
console.log(zjh.__proto__ === person.prototype) //true
同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
console.log(Object.prototype.__proto__) //null
我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:
四.内存结构图
为了更加深入和直观的进行理解,下面我们画一下上面的内存结构图:
画图约定:
疑点解释:
1.Object.__proto__ === Function.prototype // true
Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function. prototype。
2.Function.__proto__ === Function.prototype // true
Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function. prototype。
自己是由自己创建的,好像不符合逻辑,但仔细想想,现实世界也有些类似,你是怎么来的,你妈生的,你妈怎么来的,你姥姥生的,……类人猿进化来的,那类人猿从哪来,一直追溯下去……,就是无,(NULL生万物)
正如《道德经》里所说“无,名天地之始”。
3.Function.prototype.__proto__ === Object.prototype //true
其实这一点我也有点困惑,不过也可以试着解释一下。
Function.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。
JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object. prototype。Object. prototype.__proto__ === null,保证原型链能够正常结束。
五.constructor
原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用
person.prototype. constructor === person //true Function.prototype.constructor === Function //true Object.prototype.constructor === Object //true
完善下上面的内存结构图:
有两点需要注意:
1.注意Object.constructor===Function;//true 本身Object就是Function函数构造出来的
2.如何查找一个对象的constructor,就是在该对象的原型链上寻找碰到的第一个constructor属性所指向的对象
六.总结
1.原型和原型链是JS实现继承的一种模型。
2.原型链的形成是真正是靠__proto__ 而非prototype
要深入理解这句话,我们再举个例子,看看前面你真的理解了吗?
var animal = function(){}; var dog = function(){}; animal.price = 2000;// dog.prototype = animal; var tidy = new dog(); console.log(dog. price) //undefined console.log(tidy.price) // 2000
Pourquoi ? Dessinez un schéma de mémoire :
Qu'est-ce que cela signifie ? Lors de l'exécution de dog.price, il a été constaté qu'il n'y avait pas d'attribut price. Bien que l'animal pointé par prototype ait cet attribut, il ne recherche pas le long de cette "chaîne". De même, lorsque spice.price est exécuté, un tel attribut n'existe pas, mais __proto__ pointe vers animal, et il recherchera le long de cette chaîne. Animal a l'attribut price, donc spice.price génère 2000. Il s'ensuit que la véritable formation de la chaîne de prototypes repose sur __proro__, et non sur le prototype.
Donc si dog.__proto__ = animal est spécifié comme ceci. Ce chien.prix = 2000.
437fcc348f7b1c54dc1b8f8cb5743cbc1.
Père (objet fonctionnel) a donné naissance à un fils aîné (prototype), qui est votre frère aîné. Votre père a acheté beaucoup de jouets pour votre frère aîné. Quand vous êtes né, le lien familial entre vous (__proto__) va se développer. faites en sorte que vous soyez automatiquement propriétaire des jouets de votre grand frère. De même, si vous avez d'abord un fils aîné et que vous lui achetez beaucoup de jouets, lorsque vous aurez un autre fils, votre plus jeune fils aura naturellement tous les jouets de votre fils aîné. Qu’ils se battent ou non ne nous regarde pas.
Donc, vous l'avez hérité de votre frère aîné, ce qui prouve le dicton "Un frère est comme un père"