JavaScript を学習する過程で、new
演算子に遭遇することは避けられません。よく見て、理解と記憶を深めてください。
new
演算子は、mdn で次のように定義されます。
new 演算子は、ユーザー定義のオブジェクト タイプまたは組み込みオブジェクトのインスタンスを作成します。コンストラクターインスタンス。
この文では、キーワード にはコンストラクターがある
を見てみましょう。これはどういう意味ですか?まず、いくつかの例を見てみましょう。
//例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复制代码
例 1 では、new
ステートメントが正常に実行され、インスタンスが作成されたことがわかります。例 2 では、エラー TypeError: TestObj is not aconstructor
in new
a {}
object が報告され、ターゲットが constructor## ではないことを示しています。 #。通常のオブジェクトでは
new 演算子を実行できないのはなぜですか? ECMA 仕様には関連する導入部分があります:
If Type(argument) is not Object, return false.# 意味:If argument has a
[[Construct]]Internalメソッドは true を返します。 false を返します。
私たちの {} に内部メソッド
[[Construct]] がないためであるに違いありません。したがって、
new 演算子は構築時に使用できません。
ということで、
new
//例3let testObj={ Fn(){ console.log("构造成功!") } }let t3=new testObj.Fn;//=>Uncaught TypeError: testObj.Fn is not a constructor复制代码
what? 先ほど正常に構築された関数がメソッドとして機能しないのはなぜでしょうか?実際、これは MDN にも直接導入されています:
メソッドをコンストラクターにすることはできません! インスタンス化しようとすると、TypeError がスローされます。
は、 ## を意味します。 #methods コンストラクター
にすることはできません。メソッドのインスタンスを作成しようとすると、型エラーがスローされます。これを言うのは理にかなっていますが、まだ終わっていません。この文では原理が完全に説明されていません。別の例を見てみましょう:
//例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复制代码
この例とは対照的に、ECMA 仕様をチェックインしたところ、すべての関数がIn FunctionCreateFunction:
FunctionCreate (kind, ParameterList, Body, Scope, Strict,prototype)
プロトタイプ引数がそうでなかった場合に依存します渡された場合、プロトタイプを組み込みオブジェクト %FunctionPrototype% にします。「kind」が Normal でない場合は、allocKind を「非コンストラクター」にします。
- 定義この関数の
は、型
Normal
この例では、Arrow、ShortHand
のタイプは です。したがって、Method
は構築可能な関数ではありません。これは、例 3 で「メソッドはコンストラクターとして使用できない」と述べていることの説明にもなります。
new
演算子が操作できるターゲットを把握したら、ようやくその機能を明確な頭で見ることができます (TAT は簡単ではありません)。 新しいオペレーターは何を実装しますか?
関数を詳しく見るために簡単な例を見てみましょう:
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:大黄复制代码
let animal=new Animal("大黄");复制代码
したがって、
new演算子を実行すると、
animal オブジェクトが取得されます。その後、new
演算子がオブジェクトを作成し、これを変換する必要があることがわかります。オブジェクトが返されます。 。このコードをもう一度見てください: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">function Animal(name){ this.name=name; console.log("create animal");
}复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div>
同時に、結果が表示されます。create Animal
が実際に出力され、
関数本体が実行されたことがわかります。このプロセス中にパラメータが同時に渡されたため、出力ステートメントが実行されました。しかし、文 this.name=name
は関数本体のどこにあるのでしょうか?これは文です: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">console.log(animal.name); //大黄复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div>
関数本体を実行すると、返されたオブジェクトの name
値が
に割り当てた値であることがわかります。このプロセス中、this
の値は新しく作成されたオブジェクトを指します。最後に別の段落があります: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Animal.prototype.say=function(){ console.log("myName is:"+this.name);
}
animal.say(); //myName is:大黄复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div>
animal
オブジェクトは
関数プロトタイプのメソッドを呼び出し、Animal
がanimal
オブジェクトのプロトタイプチェーン上で、それはどの層にありますか?検証しましょう: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">animal.__proto__===Animal.prototype; //true复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div>
これで、 animal
の
が Animal
の prototype
を直接指していることがわかります。
さらに、コンストラクターの関数本体で値を返すと、何が起こるか見てみましょう: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">function Animal(name){ this.name=name; return 1;
}new Animal("test"); //Animal {name: "test"}复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div><p>可以看到,直接无视了返回值,那我们返回一个对象试试:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">function Animal(name){ this.name=name; return {};
}new Animal("test"); //{}复制代码</pre><div class="contentsignin">ログイン後にコピー</div></div><p>我们发现返回的实例对象被我们的返回值覆盖了,到这里大致了解了<code>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(视频)
以上がJavaScript: 今回は新しい演算子について完全に理解しました!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。