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.
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复制代码
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 :
[[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复制代码
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复制代码
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)
- Si l'argument prototype n'a pas été transmis , alors laissez prototype être l'objet intrinsèque %FunctionPrototype%.
- Si "kind" n'est pas Normal, laissez allocKind être "non-constructeur".
La définition de cette fonction est visible
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).
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:大黄复制代码
Analysons-le à partir de cet exemple, regardons d'abord cette phrase :
let animal=new Animal("大黄");复制代码
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"); }复制代码
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); //大黄复制代码
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:大黄复制代码
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复制代码
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"}复制代码
可以看到,直接无视了返回值,那我们返回一个对象试试:
function Animal(name){ this.name=name; return {}; }new Animal("test"); //{}复制代码
我们发现返回的实例对象被我们的返回值覆盖了,到这里大致了解了new
操作符的核心功能,我们做一个小结。
new
操作符的作用:
this
绑定到新创建的对象_proto__
指向构造函数的prototype
{}
)说了这么多理论的,最后我们亲自动手来实现一个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; }复制代码
上面是比较好理解的版本,我们可以简化一下得到下面这个版本:
function _new(fn, ...arg) { const obj = Object.create(fn.prototype); const res = fn.apply(obj, arg); return res instanceof Object ? res : obj;复制代码
大功告成!
本文从定义出发,探索了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!