Maison > interface Web > js tutoriel > le corps du texte

JavaScript : Cette fois, je comprends parfaitement le nouvel opérateur !

coldplay.xixi
Libérer: 2020-09-27 17:30:37
avant
1673 Les gens l'ont consulté

JavaScript : Cette fois, je comprends parfaitement le nouvel opérateur !

Préface

Dans le processus d'apprentissage du JavaScript, vous rencontrerez inévitablement l'opérateur new Cette fois, regardons de plus près. Après un certain temps, cela peut être considéré comme un approfondissement de la compréhension et de la mémoire.

Quel est le nouvel opérateur ?

L'opérateur new est défini dans mdn comme suit :

l'opérateur new crée une instance d'un type d'objet défini par l'utilisateur ou une instance d'un objet intégré avec un constructeur.

Dans cette phrase, regardons un mot-clé : 具有构造函数. Qu'est-ce que cela signifie? Jetons d'abord un coup d'œil à quelques exemples :

//例1let Animal1=function(){this.name=1};let animal=new Animal1; //这里不带()相当于不传参数//=>Animal1 {name: 1}//例2let TestObj={}let t1=new TestObj;//=>Uncaught TypeError: TestObj is not a constructor复制代码
Copier après la connexion

Nous pouvons voir que l'exemple 1 a exécuté avec succès l'instruction new et créé une instance. L'exemple 2 signale une erreur new lorsque {} est un objet TypeError: TestObj is not a constructor, indiquant que la cible n'est pas un constructor. Pourquoi les objets ordinaires ne peuvent-ils pas exécuter l'opérateur new ? Il y a une introduction pertinente dans la spécification ECMA :

Si Type(argument) n'est pas Object, retournez false.
Si l'argument a une [[Construct]] méthode interne, retournez true. Renvoie false.

signifie :

  • Le constructeur doit d'abord être un objet, sinon la condition n'est pas remplie
  • Deuxièmement, un objet doit avoir une [[Construct]] méthode interne avant de pouvoir être utilisé comme constructeur

Notre {} voici un objet, et s'il remplit la première condition , alors évidemment, ça doit l'être. Parce que {} n'a pas la méthode interne [[Construct]], il ne peut pas être construit en utilisant l'opérateur new.

Nous avons donc compris les objets exploitables de l'opérateur new, pouvons-nous jeter un œil à sa fonction ? La réponse est : NON ! Regardons un autre exemple :

//例3let testObj={
    Fn(){        console.log("构造成功!")
    }
}let t3=new testObj.Fn;//=>Uncaught TypeError: testObj.Fn is not a constructor复制代码
Copier après la connexion

quoi ? Pourquoi la fonction qui vient d'être construite avec succès ne peut-elle pas fonctionner comme méthode ? En fait, il est également directement introduit dans MDN :

Les méthodes ne peuvent pas être des constructeurs ! Elles généreront une TypeError si vous essayez de les instancier.

signifie, méthode Ne peut pas être un constructeur, une erreur de type sera générée si une tentative est faite pour créer une instance d'une méthode. Cela a du sens de le dire ainsi, mais ce n'est pas encore fini. Cette déclaration n'explique pas complètement le principe :

//例4const example = {  Fn: function() { console.log(this); },  Arrow: () => { console.log(this); },
  Shorthand() { console.log(this); }
};new example.Fn();        // Fn {}new example.Arrow();     // Uncaught TypeError: example.Arrow is not a constructornew example.Shorthand(); // Uncaught TypeError: example.Shorthand is not a constructor复制代码
Copier après la connexion

Par rapport à cet exemple, nous avons vérifié dans la spécification ECMA et trouvé. dont toutes les fonctions dépendent Dans FunctionCreate fonction :

FunctionCreate (kind, ParameterList, Body, Scope, Strict, prototype)

  1. Si l'argument prototype n'a pas été transmis , alors laissez prototype être l'objet intrinsèque %FunctionPrototype%.
  2. Si "kind" n'est pas Normal, laissez allocKind être "non-constructeur".

La définition de cette fonction est visible

  • Seulement lorsqu'une fonction de type Normal est créée, c'est une fonction constructible, sinon elle n'est pas constructible.

Dans notre exemple, le type de Arrow est Arrow, et le type de ShortHand est Method, ce ne sont donc pas des fonctions constructibles. Ceci est également expliqué. dans l'exemple 3, cette "méthode ne peut pas être utilisée comme constructeur". Après avoir déterminé les cibles sur lesquelles l'opérateur new peut opérer, je peux enfin jeter un œil à sa fonction l'esprit clair (pas facile TAT).

Que met en œuvre le nouvel opérateur ?

Prenons un exemple simple pour voir sa fonction en détail :

function Animal(name){    this.name=name;    console.log("create animal");
}let animal=new Animal("大黄");  //create animalconsole.log(animal.name);       //大黄Animal.prototype.say=function(){    console.log("myName is:"+this.name);
}
animal.say();                   //myName is:大黄复制代码
Copier après la connexion

Analysons-le à partir de cet exemple, regardons d'abord cette phrase :

let animal=new Animal("大黄");复制代码
Copier après la connexion

Vous pouvez voir. Ainsi, après avoir exécuté l'opérateur new, on obtient un objet animal, on sait alors que l'opérateur new doit créer un objet et renvoyer cet objet. Regardez à nouveau ce code :

function Animal(name){    this.name=name;    console.log("create animal");
}复制代码
Copier après la connexion

En même temps, nous voyons le résultat, et effectivement create animal est affiché. Nous savons que le corps de la fonction Animal est exécuté pendant ce processus, et les paramètres sont. transmis en même temps, nous venons donc d'exécuter notre instruction de sortie. Mais où se reflète la phrase this.name=name dans notre corps de fonction ? Voici la phrase :

console.log(animal.name);       //大黄复制代码
Copier après la connexion

Après avoir exécuté le corps de la fonction, nous constatons que la valeur name de l'objet renvoyé est la valeur que nous avons attribuée à this, il n'est donc pas difficile de juger cela dans ce processus, la valeur de this La valeur pointe vers l'objet nouvellement créé. Il y a un autre paragraphe à la fin : L'objet

Animal.prototype.say=function(){    console.log("myName is:"+this.name);
}
animal.say();                   //myName is:大黄复制代码
Copier après la connexion

animal appelle la méthode sur le prototype de la fonction Animal, ce qui signifie que Animal est sur la chaîne de prototypes de l'objet animal Donc. à quel niveau en est-on ? Vérifions :

animal.__proto__===Animal.prototype; //true复制代码
Copier après la connexion

Nous savons alors que le animal de __proto__ pointe directement vers le Animal de prototype. Au-delà de ça, voyons ce qui se passe si on renvoie une valeur dans le corps du constructeur :

function Animal(name){    this.name=name;    return 1;
}new Animal("test"); //Animal {name: "test"}复制代码
Copier après la connexion

可以看到,直接无视了返回值,那我们返回一个对象试试:

function Animal(name){    this.name=name;    return {};
}new Animal("test"); //{}复制代码
Copier après la connexion

我们发现返回的实例对象被我们的返回值覆盖了,到这里大致了解了new操作符的核心功能,我们做一个小结。

小结

new操作符的作用:

  • 创建一个新对象,将this绑定到新创建的对象
  • 使用传入的参数调用构造函数
  • 将创建的对象的_proto__指向构造函数的prototype
  • 如果构造函数没有显式返回一个对象,则返回创建的新对象,否则返回显式返回的对象(如上文的{}

模拟实现一个new操作符

说了这么多理论的,最后我们亲自动手来实现一个new操作符吧~

var _myNew = function (constructor, ...args) {    // 1. 创建一个新对象obj
    const obj = {};    //2. 将this绑定到新对象上,并使用传入的参数调用函数

    //这里是为了拿到第一个参数,就是传入的构造函数
    // let constructor = Array.prototype.shift.call(arguments);
    //绑定this的同时调用函数,...将参数展开传入
    let res = constructor.call(obj, ...args)

    //3. 将创建的对象的_proto__指向构造函数的prototype
    obj.__proto__ = constructor.prototype

    //4. 根据显示返回的值判断最终返回结果
    return res instanceof Object ? res : obj;
}复制代码
Copier après la connexion

上面是比较好理解的版本,我们可以简化一下得到下面这个版本:

function _new(fn, ...arg) {    const obj = Object.create(fn.prototype);    const res = fn.apply(obj, arg);    return res instanceof Object ? res : obj;复制代码
Copier après la connexion

大功告成!

总结

本文从定义出发,探索了new操作符的作用目标和原理,并模拟实现了核心功能。其实模拟实现一个new操作符不难,更重要的还是去理解这个过程,明白其中的原理。

更多相关免费学习推荐:javascript(视频)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal