Maison > Article > interface Web > Analyse complète de ces compétences, constructeur, prototype de js cliché_javascript
Avant-propos
Ceci, le constructeur et le prototype en JavaScript sont tous des problèmes courants, et il est crucial de comprendre leur signification en profondeur. Ici, révisons-le à nouveau, passons en revue le passé et apprenons le nouveau !
ce
Ceci représente l'objet actuel. Si this est utilisé dans la portée globale, il fait référence à la fenêtre de l'objet de page actuelle ; si this est utilisé dans une fonction, ce à quoi this fait référence est basé sur l'objet sur lequel cette fonction est appelée ; au moment de l'exécution. Nous pouvons également utiliser les deux méthodes globales apply et call pour changer le pointeur spécifique de this dans la fonction.
Regardons d'abord un exemple d'utilisation de ceci dans une portée globale :
console.log(this === window); // true console.log(window.alert === this.alert); // true console.log(this.parseInt("021", 10)); // 10
Ceci dans la fonction est déterminé au moment de l'exécution, et non lorsque la fonction est définie, comme suit :
// 定义一个全局函数 function foo() { console.log(this.fruit); } // 定义一个全局变量,等价于window.fruit = "apple"; var fruit = "apple"; // 此时函数foo中this指向window对象 // 这种调用方式和window.foo();是完全等价的 foo(); // "apple" // 自定义一个对象,并将此对象的属性foo指向全局函数foo var pack = { fruit: "orange", foo: foo }; // 此时函数foo中this指向window.pack对象 pack.foo(); // "orange"
Les fonctions globales apply et call peuvent être utilisées pour changer le pointeur de this dans la fonction, comme suit :
// 定义一个全局函数 function foo() { console.log(this.fruit); } // 定义一个全局变量 var fruit = "apple"; // 自定义一个对象 var pack = { fruit: "orange" }; // 等价于window.foo(); foo.apply(window); // "apple" // 此时foo中的this === pack foo.apply(pack); // "orange"
Remarque : les fonctions apply et call ont la même fonction. La seule différence est que les définitions des paramètres des deux fonctions sont différentes.
Parce que les fonctions sont aussi des objets en JavaScript, nous pouvons voir les exemples intéressants suivants :
// 定义一个全局函数 function foo() { if (this === window) { console.log("this is window."); } } // 函数foo也是对象,所以可以定义foo的属性boo为一个函数 foo.boo = function() { if (this === foo) { console.log("this is foo."); } else if (this === window) { console.log("this is window."); } }; // 等价于window.foo(); foo(); // this is window. // 可以看到函数中this的指向调用函数的对象 foo.boo(); // this is foo. // 使用apply改变函数中this的指向 foo.boo.apply(window); // this is window.
prototype
Le prototype est essentiellement un objet JavaScript.
Et chaque fonction a un attribut de prototype par défaut. Si cette fonction est utilisée dans le cadre de la création d'un objet personnalisé, on appelle cette fonction un constructeur. Par exemple, la scène simple suivante :
// 构造函数 function Person(name) { this.name = name; } // 定义Person的原型,原型中的属性可以被自定义对象引用 Person.prototype = { getName: function() { return this.name; } } var hao= new Person("haorooms"); console.log(hao.getName()); // "haorooms"
Par analogie, considérons les types de données en JavaScript : chaîne, nombre, tableau, objet, date, etc.
Nous avons des raisons de croire que ces types sont implémentés en tant que constructeurs dans JavaScript, tels que :
// 定义数组的构造函数,作为JavaScript的一种预定义类型 function Array() { // ... } // 初始化数组的实例 var arr1 = new Array(1, 56, 34, 12); // 但是,我们更倾向于如下的语法定义: var arr2 = [1, 56, 34, 12];
Dans le même temps, de nombreuses méthodes d'opération sur les tableaux (telles que concat, join, push) doivent également être définies dans l'attribut prototype. En fait, tous les types de données intrinsèques JavaScript ont un attribut prototype en lecture seule (cela est compréhensible : si vous modifiez l'attribut prototype de ces types, les méthodes prédéfinies disparaissent), mais on peut y ajouter sa propre méthode d'extension.
// 向JavaScript固有类型Array扩展一个获取最小值的方法 Array.prototype.min = function() { var min = this[0]; for (var i = 1; i < this.length; i++) { if (this[i] < min) { min = this[i]; } } return min; }; // 在任意Array的实例上调用min方法 console.log([1, 56, 34, 12].min()); // 1
Remarque : il y a un piège ici. Après avoir ajouté une méthode d'extension au prototype de Array, cette méthode d'extension sera également mise en boucle lors de l'utilisation de for-in pour boucler le tableau. Le code suivant illustre cela (en supposant que la méthode min ait été étendue au prototype Array) :
var arr = [1, 56, 34, 12]; var total = 0; for (var i in arr) { total += parseInt(arr[i], 10); } console.log(total); // NaN
La solution est également très simple :
var arr = [1, 56, 34, 12]; var total = 0; for (var i in arr) { if (arr.hasOwnProperty(i)) { total += parseInt(arr[i], 10); } } console.log(total); // 103
constructeur
constructor pointe toujours vers le constructeur qui a créé l'objet actuel. Par exemple, l'exemple suivant :
// 等价于 var foo = new Array(1, 56, 34, 12); var arr = [1, 56, 34, 12]; console.log(arr.constructor === Array); // true // 等价于 var foo = new Function(); var Foo = function() { }; console.log(Foo.constructor === Function); // true // 由构造函数实例化一个obj对象 var obj = new Foo(); console.log(obj.constructor === Foo); // true // 将上面两段代码合起来,就得到下面的结论 console.log(obj.constructor.constructor === Function); // true
Mais lorsque le constructeur rencontre le prototype, quelque chose d'intéressant se produit. Nous savons que chaque fonction possède un prototype d'attribut par défaut, et le constructeur de ce prototype pointe vers cette fonction par défaut. Comme le montre l'exemple suivant :
function Person(name) { this.name = name; }; Person.prototype.getName = function() { return this.name; }; var p = new Person("haorooms"); console.log(p.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true // 将上两行代码合并就得到如下结果 console.log(p.constructor.prototype.constructor === Person); // true
Lorsque nous avons redéfini le prototype de la fonction (note : la différence avec l'exemple ci-dessus, il ne s'agit pas d'une modification mais d'un remplacement), le comportement du constructeur était un peu étrange, comme le montre l'exemple suivant :
function Person(name) { this.name = name; }; Person.prototype = { getName: function() { return this.name; } }; var p = new Person("haorooms"); console.log(p.constructor === Person); // false console.log(Person.prototype.constructor === Person); // false console.log(p.constructor.prototype.constructor === Person); // false
Pourquoi ? Il s'avère que lors de la substitution de Person.prototype, cela équivaut à effectuer l'opération de code suivante :
Person.prototype = new Object({ getName: function() { return this.name; } });
Le constructeur pointe toujours vers le constructeur qui se crée, donc à ce moment-là Person.prototype.constructor === Objet, c'est-à-dire :
function Person(name) { this.name = name; }; Person.prototype = { getName: function() { return this.name; } }; var p = new Person("haorooms"); console.log(p.constructor === Object); // true console.log(Person.prototype.constructor === Object); // true console.log(p.constructor.prototype.constructor === Object); // true
Comment résoudre ce problème ? La méthode est également très simple, il suffit de remplacer Person.prototype.constructor :
function Person(name) { this.name = name; }; Person.prototype = { getName: function() { return this.name; } }; Person.prototype.constructor = Person; var p = new Person("haorooms"); console.log(p.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true console.log(p.constructor.prototype.constructor === Person); // true
peut aussi s'écrire ainsi :
function Person(name) { this.name = name; }; Person.prototype = { constructor:Person,//指定constructor getName: function() { return this.name; } };
L'analyse complète ci-dessus de ce constructeur et du prototype de clichés js est tout le contenu partagé par l'éditeur. J'espère qu'elle pourra vous donner une référence, et j'espère également que tout le monde soutiendra Script Home.