一つの難しいJavaScript問題
5147 ワード
原文のリンク:https://segmentfault.com/a/1190000007979730
前回一つの問題を共有しました.反応がいいです.自分で書いたものを時間をかけて見に行きたいという人もいます.自分に大きな励ましを与えました.実は問題を作るのは本物のプログラミングとは比べものになりませんが、あなたの前に気づかなかった言語レベルの問題を発見することができます.ですから、今回はちょっと難しいJavaScriptのテーマを共有します.
まず、演算子優先かっこがnewより高いことを見ます.実際には(new Foo().getName()として実行されます.まずFoo関数を実行します.
上記の説明は問題があると思います.上記の2つの実施形態と比較して、1つ目は
前回一つの問題を共有しました.反応がいいです.自分で書いたものを時間をかけて見に行きたいという人もいます.自分に大きな励ましを与えました.実は問題を作るのは本物のプログラミングとは比べものになりませんが、あなたの前に気づかなかった言語レベルの問題を発見することができます.ですから、今回はちょっと難しいJavaScriptのテーマを共有します.
function Foo() {
getName = function () {
console.log('1');
};
return this;
}
Foo.getName = function () {
console.log('2');
};
Foo.prototype.getName = function () {
console.log('3');
};
var getName = function () {
console.log('4');
};
function getName() {
console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
上記のコードはブラウザの環境下で、出力結果はいくらですか?最終的な答えを発表します.2 4 1 1 2 3 3
前の4つの難しさはそんなに大きくないです.主に後の3つの道です.基本的には全軍壊滅しました.感嘆は本当に回りくどいです.後はゆっくり分析して、一つずつ話してください.まず一つの問題に注意しなければならない.function Foo() {
getName = function () {
console.log('1');
};
return this;
}
関数内部宣言のgetName
変数は、前にvar
、let
、const
を持っていないので、実はLHS(この紹介で行くことができる私のブログでLHSとRHSに関するまとめを見てください)によると、声明のgetName
は大域的な範囲内にある(window
でもあります).次に下記のコードがブラウザで実行された結果を知る必要がありますか?var getName = function () {
console.log('4');
};
function getName() {
console.log(5);
}
getName();
上記コードの実行結果は、4
です.理由は、var
によって宣言された変数および関数宣言function
はいずれも向上されるが、関数宣言のレベルはvar
よりも高いので、上のコードの実際の実行結果は以下の通りである.function getName() {
console.log(5);
}
var getName = function () {
console.log('4');
};
getName();
後の関数式getName
は、前の関数ステートメントgetName
をカバーしています.実際には関数式が実行されています.まず、下記のコードに必要なコメントを追加します.//
function Foo() {
//
getName = function () {
console.log('1');
};
return this;
}
// getName, Function, ,Function Object
Foo.getName = function () {
console.log('2');
};
// Foo getName
Foo.prototype.getName = function () {
console.log('3');
};
var getName = function () {
console.log('4');
};
function getName() {
console.log(5);
}
最初のステートメントを実行します.Foo.getName();
関数4
自体は実行されていません.関数の属性Foo
が実行されます.もちろん出力はgetName
です.次に実行されます.getName();
これは、大域的に2
を実行したもので、2つの対応するgetName()
の声明があり、前述のように、レベルアップされたレベルから実際に実行されるのは、関数式である.var getName = function () {
console.log('4');
};
したがって、出力はgetName
です.次に実行します.Foo().getName();
まず、JavaScriptのオペレータ優先度を見てください.高い順に並べ替えられていることから、4
は()
と同じ優先度であることが分かります.したがって、.
は左から右にかけて実行されます.まずFoo().getName()
を実行し、大域のFoo()
は出力getName
に覆われ、console.log('1')
はこのときに表されるthis
である.次に実行されるwindow
に相当すると、出力の実際はwindow.getName()
である.下に着きましたgetName();
これはもちろん、実行します.1
です.次は三つの一番難しい部分に着きました.new Foo.getName();
このステートメントの実行には、2つの可能性があります.(new Foo).getName()
またはnew (Foo.getName)()
しかし、実際には1
よりも優先度が高いので、実際に実行されるのは第二の種類であることが分かります.Foo.getName = function () {
console.log('2');
};
関数は.
動作を実行し、もちろん出力はnew
です.以下は実行しますnew Foo().getName();
この文の可能性は2つあります.(new Foo()).getName();
またはnew (Foo().getName)();
そんなはずですか?もともとは第二種類の実行方式だと思っていましたが、後はブラウザで試運転して、実際に実行する方法は第一です.テーマを見た作者はこう説明しています.まず、演算子優先かっこがnewより高いことを見ます.実際には(new Foo().getName()として実行されます.まずFoo関数を実行します.
上記の説明は問題があると思います.上記の2つの実施形態と比較して、1つ目は
new
を実行してから2
を実行してから実行します.第二に、new
が先に実行され、.
が実行され、最後に()
オペレータが実行される.本当に引用によって優先度で判別するなら、第一ではなく第二の方法で実行すべきです.その後、ようやく原因を見つけました.以前に発生した多くのJavaScript優先度の表は完全ではなく、万能MDNが最も権威のあるJavaScript優先度表演算子優先度を与えています.一番重要な部分を挙げました.実行順は確かに第一です.()
に従って実行すれば、状況は簡単であり、.
は新たに生成されたオブジェクトを返し、new
の方法がないので、new
に(new Foo()).getName();
の方法が見つかった.したがって、出力は(new Foo())
です.勝利は目の前にあります.最後の質問を見てみます.new new Foo().getName();
前のステップと同じ方法で、優先表に従ってこの文がどのように実行されているかを分析します.まず、パラメータ付きgetName()
は、オペレータの優先度が最も高く、第1のステップは、次のように分割される.new (new Foo().getName)();
二番目のステップは、次のステップに分けられます.new ((new Foo()).getName)();
したがって、prototype
を実行するという関数は、対応するFoo.prototype.get Nameであるので、getName()
を実行すると、必ず出力されるのは3
である.ハハハ、せっかくの問題がやっと解決しました.楽しいです.まとめてください.まずJavaScript知識はMDNに行って調べたほうがいいです.もし他のところが間違っていたら、本当に大変です.第二に、コードを書く時には操作者優先度というものをあまり使わないと、明確でないところではすぐにnew
を使うことができます.コードの読み取り可能性は本当に重要です.大事です大事ですコードはやはり人に見せます.正しくないところがあれば、指摘してください.経歴が浅いので、よろしくお願いします.私のブログを見に行きませんか?http://mrerhu.github.io