最初にコード スニペットを見てください:
var f = function foo(){
Return typeof foo; // foo は内部スコープで有効です
};
// foo は外部で使用される場合には見えません
typeof foo; "unknown"
f(); // "function"
ここで言いたいのは、関数式内の foo は関数内でのみ参照でき、関数外では参照できないということです。
json
多くの JavaScript 開発者は、誤って JavaScript オブジェクト リテラル (JSON オブジェクト) と呼んでいます。 JSON はデータ交換形式を記述するように設計されており、JavaScript のサブセットである独自の構文も備えています。
{ "prop": "val" } このような宣言は、使用されるコンテキストに応じて、JavaScript オブジェクト リテラルまたは JSON 文字列の場合があります。文字列コンテキスト (一重引用符または二重引用符で囲まれるか、テキスト ファイルから読み取られる) で使用される場合、それは JSON 文字列です。オブジェクト リテラル コンテキストで使用される場合、それはオブジェクト リテラルです。
// これは JSON 文字列です
var foo = '{ "prop": "val" }';
// これはオブジェクト リテラルです
var bar = { "prop": "val" };
また知っておくべきことの 1 つは、JSON.parse は JSON 文字列をオブジェクトに逆シリアル化するために使用され、JSON.stringify はオブジェクトを JSON 文字列にシリアル化するために使用されるということです。古いバージョンのブラウザはこのオブジェクトをサポートしていませんが、json2.js を通じて同じ機能を実現できます。
Prototype
function Animal (){
// ...
}
function cat (){
// ...
}
cat.prototype = new Animal();//このメソッドは継承します関数内のコンストラクター。
cat.prototype = Animal.prototype;//このメソッドはコンストラクターを継承しません。
//もう 1 つ注意すべき重要な点は、独自のプロトタイプ チェーンを保守する必要があるということです。初心者はこれを常に忘れてしまいます。
cat.prototype.constructor = cat;
(新しいオブジェクトを割り当てることによって) 関数のプロトタイプ プロパティを完全に変更すると、作成するオブジェクトにはコンストラクター プロパティが含まれないため、元のコンストラクターへの参照が失われます。
function A() {}
A.prototype = {
x: 10
};
var a = new A();
alert(a.x) // 10
alert(a.constructor === A) ) ; // false!
MDN のコンストラクターの説明を見てみましょう: プロトタイプ: インスタンスのプロトタイプを作成したオブジェクト関数への参照を返します。 したがって、関数へのプロトタイプ参照は手動で復元する必要があります。
function A() {}
A.prototype = {
コンストラクター: A,
x: 10
};
var a = new A();
alert(a.x) // 10
alert(a.constructor) === A); // true
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10
A.prototype = {
コンストラクター: A,
x: 20
y: 30
};
// オブジェクト a は、暗黙的な [[Prototype]] 参照を通じて原油のプロトタイプから取得された値です
alert(a.x) // 10
alert(a.y) // unknown
; var b = new A();
// ただし、新しいオブジェクトは新しいプロトタイプから取得された値です
alert(b.x); // 20
alert(b.y) // 30
// 宣言された関数パラメーターの数 argument (x, y, z)
alter(foo.length); // 3
// 実際に渡されるパラメーターの数 (x, y のみ)
alter(arguments.length) // 2
// パラメーターの呼び出し先は関数自体です
alter(arguments.callee ==) = foo); // true
}
すべての変数宣言 (var, VariableDeclaration);
もう 1 つの典型的な例:alert(x) // function
var x = 10;
x = 20 ;
関数 x() {};
alert(x) // 20
;
仕様によれば、コンテキストに入るときに関数宣言が入力され、コンテキストに入るときに変数宣言「x」もあり、上で述べたように、変数宣言は関数宣言と仮パラメータ宣言の後に続きます。その後、このコンテキスト入力フェーズ中に、変数宣言は、VO 内に既に存在する同じ名前の関数宣言または仮パラメーター宣言を妨げません。単純な属性と比較して、変数には {DontDelete} という属性があります。この属性の意味は、変数属性を delete 演算子を使用して直接削除できないことです。
a = 10;
alert(window.a); // 10
alert(window.a); // 未定義
var b = 20;
alert(window.a); b); // 20
alert(delete b); // false
alert(window.b); // 20 のままです。 b はプロパティではなく変数です!
var a = 10; // グローバル コンテキストの変数
(function () {
var b = 20; // 関数コンテキストのローカル変数
})();
alert(a ); // 10
alert(b); // グローバル変数 "b" は宣言されていません。
(function () {
alert(this); // null => global
})();
この例では、関数オブジェクトはありますが、参照型のオブジェクトはありません (識別子ではなく、プロパティ アクセサーでもありません)、したがって、この値は最終的にグローバル オブジェクトに設定されます。
var foo = {
bar: function () {
alert(this);
}
};
foo.bar() // 参照、OK => foo
(foo.bar)(); // 参照、OK => foo
(foo.bar = foo.bar)(); // global
(false || foo.bar)(); // global
(foo.bar, foo.bar); ); // global
2 番目の例では、グループ演算子は適用されません。GetValue など、参照型からオブジェクトの実際の値を取得する上記のメソッドを考えてください。同様に、グループ操作の戻りでも参照型を取得します。これが、 this 値がベース オブジェクト (foo) に再度設定される理由です。
3 番目の例では、グループ演算子とは異なり、代入演算子は GetValue メソッドを呼び出します。返される結果は関数オブジェクト (参照型ではありません) です。つまり、これは null に設定され、結果はグローバル オブジェクトになります。
4 番目と 5 番目も同様です。コンマ演算子と論理演算子 (OR) が GetValue メソッドを呼び出し、それに応じて参照が失われ、関数が取得されます。そして、再度グローバルに設定します。
ご存知のとおり、ローカル変数、内部関数、仮パラメータは、特定の関数のアクティベーション オブジェクトに格納されます。
function bar() {
alert(this); // global
}
bar(); // AO.bar() と同じ
}
アクティブなオブジェクトは常にこれとして返されます。値は null - (つまり、擬似コードの AO.bar() は null.bar() と同等です)。ここで、これをグローバル オブジェクトに設定して、上で説明した例に戻ります。
function foo() {
var y = 20;
function barFD() { // 関数宣言
alert(x);
alert(y);
}
var barFn = Function('アラート(x); アラート(y);');
barFD() // 10, 20
barFn() // 10, "y" が定義されていません
}
また:
var x = 10, y = 10;
with ({x: 20}) { var x = 30, y = 30;
//x = 30 ここでは x = 20 をカバーします。 // 30
alert(y); // 30
}
alert(y); // 30
コンテキストに入ると何が起こるか?識別子「x」と「y」が変数オブジェクトに追加されました。さらに、コードの実行フェーズ中に次の変更を加えます:
x = 10, y = 10;
オブジェクト {x:20} がスコープの先頭に追加されます
with 内で var 宣言が検出されますが、入力時にすべての変数が解決されているため、もちろん何も作成されません。コンテキストの追加
2 番目のステップでは、変数 "x" のみが変更され、実際にはオブジェクト内の "x" が解析されてスコープ チェーンの先頭に追加され、"x" は 20 でしたが 30 になります。同じように、変数オブジェクト「y」の変更もあります。解析された後、その値は 10 から 30 に変更されます
さらに、with 宣言が完了すると、その特定のオブジェクトがスコープ チェーンから削除されます。変数 "x "--30 もそのオブジェクトから削除されます)、つまり、スコープ チェーンの構造が強化される前の状態に戻ります。
最後の 2 つのアラートでは、現在の変数オブジェクトの "x" は同じままですが、"y" の値は 30 に等しくなりますが、これは with ステートメントの実行中に変更されました。
関数
...
}();
//
function foo() { という名前であっても
...
}();
// "foo" はコンテキストに入るときに作成される関数宣言です
alert(foo) // function
function foo(x) {
alert(x);
} (1); // これは単なるグループ化演算子であり、関数呼び出しではありません。
foo(10); // これは実際の関数呼び出しであり、結果は 10 です
(function foo(x) {
alert(x);
})(1); / これは呼び出しであり、グループ化演算子ではありません
bar: function (x) {
return x % 2 != 0 ? 'はい' : 'いいえ';
}(1)
};
alert(foo.bar); / 'yes'
関数が式の位置にない場合、グループ化演算子の括弧が必要です。つまり、関数を手動で FE に変換します。
パーサーが FE を扱っていることを認識している場合は、括弧を使用する必要はありません。
var localVar = 10;//innerFn 関数の場合、localVar は自由変数です。
function innerFn(innerParam) {
alert(innerParam + localVar);
}
return innerFn;
}
function foo() {
alert( z) ;
}
foo(); // 10 – 静的スコープと動的スコープを使用する場合
(function () {
var z = 20;
foo(); // 10 – 静的スコープを使用する場合、20 – 動的スコープを使用する
})();
// fooをパラメータとして使う場合も同様です
(function (funArg) {
var z = 30;
funArg(); // 10 – 静的スコープ、30 – 動的スコープ
})(ふー);
理論: スコープ チェーンのため、すべての関数はクロージャです (関数の種類に関係なく、匿名関数、FE、NFE、FD はすべてクロージャです)。実用的な観点から: 以下の関数はクロージャとみなされます: * 作成されたコンテキストが破棄されても存在します (たとえば、内部関数が親関数から返される)