フロントノート(一)変数、実行環境とスコープ、this
8229 ワード
ECMAScriptの変数値の種類基本タイプ:Number、String、Boolean、Unidefined、Null 引用タイプ:Object、Aray、Funct、Date、RegExp 1つの値を変数に割り当てるときは、この値がベースタイプの値か参照タイプの値かを判定しなければなりません.
基本データタイプは、変数に格納されている実際の値を操作できるので、値によってアクセスします.
引用のタイプは違っています.その値はヒープメモリに保存されているオブジェクトです.JavaScriptはメモリの位置に直接アクセスすることができません.
したがって、オブジェクトを操作するときは、実際には操作対象の参照であり、参照の種類の値は参照でアクセスされます.
基本タイプの特徴:
1.値は変わらない2.属性と方法を追加してはいけません.
1.値を変更することができます.2.属性と方法を追加することができます.
パラメータの転送
ECMAScriptで規定されているすべての関数のパラメータは値によって伝達されます.
検出タイプ typeofは、基本タイプ を検出するために使用されます. instance ofは、参照タイプを検出するとき、どのタイプのオブジェクトかを判断するために使用される(すべての参照タイプの値がObjectの例であるため).
実行環境は実行コンテキストとも呼ばれ、各実行環境には関連する変数オブジェクトがあり、環境で定義されたすべての変数と関数がこのオブジェクトに保存されます.
Javascriptには三つのコードの実行環境があります.グローバル実行環境---デフォルトの最周辺の実行環境は、ブラウザ内のその関連変数オブジェクトをwindowオブジェクト と見なしている.関数実行環境---関数を呼び出すたびに、新しい実行コンテキストが作成されます. Eval---文字列をパラメータとして受け入れ、Javascriptコードとして実行します.eval関数は新しい作用領域 を作成しません.
新たに作成された実行コンテキストは、スコープの上部に追加され、実行または呼び出しスタックと呼ばれる場合がある.ブラウザは、常にアクティブドメインチェーンの先頭にある現在の実行コンテキストを実行します.完了すると、現在の実行コンテキストはスタックのトップから取り除かれ、前の実行コンテキストに制御権を返す.
以下では、関数実行環境の構築過程を詳しく説明します.確立段階 アーグメンントオブジェクト、パラメータ、関数、変数(作成順序に注意!) を作成します.作用分域チェーン を確立する.は、thisの値 を決定する.
コードの実行段階 変数割り当て 関数参照 他のコード を実行します.
スコープチェーンとクローズド
コードが一つの環境で実行されると、変数オブジェクトの作用ドメインチェーンが作成されます.その用途は、実行環境にアクセスできるすべての変数と関数に関する規則的なアクセスを保証することです.スコープの先端は常に現在実行されているコードの環境の変数オブジェクトであり、グローバル実行環境の変数オブジェクトは常にスコープ内の最後のオブジェクトです.変数検索を行うときは、フィールドチェーンのレベルを1つ上に検索します.閉ループの一部の特性は,作用ドメイン鎖という重要な特性によって決定される.
!すなわち、内部環境は、フィールドチェーンを介してすべての外部環境にアクセスできますが、外部環境は内部環境の変数と関数にアクセスできません.
PS:また、いくつかの紛らわしい、あるいは分かりにくい概念を説明します.変数オブジェクトとアクティビティオブジェクト 変数オブジェクトは、実行環境の確立段階に作成され、実行フェーズに入る前に属性がアクセスできなくなり、実行フェーズに入ると変数オブジェクトがアクティブオブジェクトになり、次に実行フェーズ中のステップが実行されます. 作用分域と作用分域チェーン スコープと実行環境は全く異なる概念であり、javascriptコードが実行するプロセスは実は二つの段階でコードコンパイル段階とコード実行段階があり、スコープはコンパイル段階で作成された規則であり、エンジンが現在のスコープおよびネストされているサブスコープの中で識別子名に基づいて変数を検索する方法を管理するために使用される.実行コンテキストの作成は、コードの実行段階で行われます.スコープチェーンは一連の変数オブジェクトから構成されています.この一方向チャネルで変数オブジェクトの識別子を照会することができます.これにより、前の階層のスコープ内の変数にアクセスすることができます. this詳細
thisのバインディングプロセスを理解する前に、コールスタックと呼び出し位置という2つの概念を理解しなければならない.呼び出し位置は、現在実行中の関数の前の呼び出しにあります.は、現在実行されている位置に到達するために呼び出されたすべての関数を呼び出すスタックを呼び出す. 呼び出し位置:関数がコード内で呼び出された位置(ステートメントの位置ではなく). デフォルトバインディング 暗黙的バインディング はバインディング を表示します. newバインディング デフォルトバインディング 関数が独立して呼び出される場合、すなわち、修飾されていない関数参照を直接使用して呼び出しを行う場合、thisはデフォルトのバインディングを使用し、このときthisはグローバルオブジェクトに向けられます.暗黙的バインディング 関数がコンテキストオブジェクトを参照すると、このコンテキストオブジェクトに関数呼び出し中のthisをバインドします.
陰でなくします
暗黙的に結合された関数が明示的または暗黙的に割り当てられた場合、バインディングされたオブジェクトは失われ、したがって、thisをグローバルオブジェクトまたは明示バインディング Function.prototypeのcall,apply,bindにより直接にthisのバインディングオブジェクトを指定します.
callとappyは、すぐに実行される関数であり、パラメータの受け入れ形式が異なります.
bindは新しい包装関数を作成して返します.実行ではありません. newバインディング JavaScriptにおいて、構造関数はnewオペレータを使用する時に呼び出される普通の関数です.つまり、構造関数の呼び出しが発生した時には、以下の操作が行われます.新たなオブジェクト を作成します.新しいオブジェクトが実行されます. 新しいオブジェクトは、関数呼び出しのthis に結び付けられます.関数がオブジェクトに戻っていない場合、new式の関数呼び出しは自動的にこの新しいオブジェクト に戻ります.優先度 newバインディング>明示的バインディング>陰的バインディング>標準バインディング thisと矢印関数 ES 6の矢印関数は、外層(関数または大域)の作用領域に基づいてthisを決定する4つの標準原則を使用しない.
まず次の一般的なthisバインディングの失われた状況を見てください.
参考書:「JavaScript高級プログラム設計」「あなたの知らないJavaScript」(上)
基本データタイプは、変数に格納されている実際の値を操作できるので、値によってアクセスします.
引用のタイプは違っています.その値はヒープメモリに保存されているオブジェクトです.JavaScriptはメモリの位置に直接アクセスすることができません.
したがって、オブジェクトを操作するときは、実際には操作対象の参照であり、参照の種類の値は参照でアクセスされます.
基本タイプの特徴:
1.値は変わらない2.属性と方法を追加してはいけません.
var name = "BarryAllen";
name.substring(5); //"Allen"
console.log(name) //BarryAllen
name.identity = "Flash";
console.log(name.identity) //undefined
name.skill = function() {
console.log("Running very fast.")
}
name.skill(); //name.skill is not a function
引用タイプの特徴:1.値を変更することができます.2.属性と方法を追加することができます.
var obj = {};
obj.name = "BarryAllen";
var change = obj;
change.name = "OliverQueen";
console.log(obj.name); //OliverQueen
obj.identity = "Flash";
console.log(obj.identity) //Flash
obj.skill = function() {
console.log("Running very fast.")
}
obj.skill(); //Running very fast.
上のコードからは、コピー変数を行う際の基本型はコピー作成のような動作であることが分かりますが、参照タイプはオブジェクトを指すポインタのコピーですので、コピー操作の終了後に同じオブジェクトを参照します.したがって、変数の一つを変更すると他の変数に影響を与えます.パラメータの転送
ECMAScriptで規定されているすべての関数のパラメータは値によって伝達されます.
function setAge(obj) {
obj.age = 18;
obj = {};
obj.age = 25;
}
var person = {}
setAge(person);
console.log(person.age) //18
関数内部でオブジェクトを再宣言し、obj.age
の値を修正したが、パラメータ伝達が参照伝達によるものであればperson.age
は25
を出力すべきであるが、事実はそうではない.この時点でオブジェクトは値で伝達されますので、元の参照は変わりません.実際には、関数が実行された後、この新規作成された局部オブジェクトはすぐに廃棄されます.検出タイプ
var num = 786;
var bol = true;
var name = "Violet";
console.log(typeof num +"~"+ typeof bol +"~"+ typeof name); //number~boolean~string
var arr = [];
var func = new Function();
console.log(arr instanceof Array) //true
console.log(func instanceof Function) //true
実行環境(Execution Contect)と作用領域実行環境は実行コンテキストとも呼ばれ、各実行環境には関連する変数オブジェクトがあり、環境で定義されたすべての変数と関数がこのオブジェクトに保存されます.
Javascriptには三つのコードの実行環境があります.
新たに作成された実行コンテキストは、スコープの上部に追加され、実行または呼び出しスタックと呼ばれる場合がある.ブラウザは、常にアクティブドメインチェーンの先頭にある現在の実行コンテキストを実行します.完了すると、現在の実行コンテキストはスタックのトップから取り除かれ、前の実行コンテキストに制御権を返す.
以下では、関数実行環境の構築過程を詳しく説明します.
(function (obj) {
console.log(typeof obj); //number
console.log(typeof foo); //function
console.log(typeof boxer); //undefined
var foo = "Mashics";
function foo() {
document.write("This is a function.");
}
var boxer = function() {
document.write("I am a boxer.");
}
})(666);
このコードは、関数が環境確立を実行してから実行するプロセス、すなわち、まずパラメータの作成、そして関数の体内で関数を探しに行くという宣言を十分に示しています.最後に変数宣言です.特に、javascriptエンジンが関数宣言を探している間に、まずfoo
という関数を見つけたので、その後に定義された変数は属性を上書きしません.エンジンは次に具体的なコードセグメント内の変数宣言を検索し、関連変数のイメージ属性に追加し、undefined
としてその割当てを開始します.したがって、変数のような古典的な問題は、環境作成プロセスを実行する観点から答えられ、解決されます.スコープチェーンとクローズド
コードが一つの環境で実行されると、変数オブジェクトの作用ドメインチェーンが作成されます.その用途は、実行環境にアクセスできるすべての変数と関数に関する規則的なアクセスを保証することです.スコープの先端は常に現在実行されているコードの環境の変数オブジェクトであり、グローバル実行環境の変数オブジェクトは常にスコープ内の最後のオブジェクトです.変数検索を行うときは、フィールドチェーンのレベルを1つ上に検索します.閉ループの一部の特性は,作用ドメイン鎖という重要な特性によって決定される.
var outer = "Margin";
function foo() {
var mider = "Padding";
function baz() {
var inner = "Content";
console.log( "Gotcha! " + outer + " and " + mider + " . " );
}
return baz;
}
var fn = foo();
fn(); //Gotcha! Margin and Padding .
console.log(inner); //inner is not defined.
このコードは簡単なクローズドですが、スコープ内の最も重要な特性を示しています.!すなわち、内部環境は、フィールドチェーンを介してすべての外部環境にアクセスできますが、外部環境は内部環境の変数と関数にアクセスできません.
PS:また、いくつかの紛らわしい、あるいは分かりにくい概念を説明します.
thisのバインディングプロセスを理解する前に、コールスタックと呼び出し位置という2つの概念を理解しなければならない.呼び出し位置は、現在実行中の関数の前の呼び出しにあります.
function head() {
// head
console.log("first");
body(); //body --> head
}
function body() {
// head -> body
console.log("second");
footer(); //footer --> body
}
function footer() {
// head -> body -> footer
console.log("third");
}
head(); //head -->
thisバインディング規則:var a = 2;
function foo() {
console.log( this.a );
}
foo(); // 2
var obj = {
a : 2,
foo : foo
}
function foo() {
console.log( this.a );
}
obj.foo(); //2
foo()
を呼び出すと、thisはobj
に結合されるので、ここのthisはobj
に相当する.陰でなくします
暗黙的に結合された関数が明示的または暗黙的に割り当てられた場合、バインディングされたオブジェクトは失われ、したがって、thisをグローバルオブジェクトまたは
undefined
にバインディングする.コールバック関数でのthisバインディングが失われるのは、パラメータ伝達が実は暗黙的な割当てであるからです.var a = "Global";
var obj = {
a : 2,
foo : foo
}
function foo() {
console.log( this.a );
}
var bar = obj.foo;
bar(); //Global ->
function doFoo(fn) {
fn();
}
doFoo( obj.foo ); //Global ->
setTimeout(obj.foo, 1000); //Global -> ,
function setTimeout(fn, delay) {
// delay
fn();
}
callとappyは、すぐに実行される関数であり、パラメータの受け入れ形式が異なります.
bindは新しい包装関数を作成して返します.実行ではありません.
var obj = {
a : 2
}
function foo() {
console.log( this.a );
}
var bar = function() {
foo.call(obj);
}
bar(); //2 -->
function calculate(b, c) {
console.log(this.a, b, c);
return (this.a * b) + c;
}
var excute = function() {
return calculate.apply(obj, arguments); //apply
}
excute(5,10); //2 5 10 20
var baz = calculate.bind(obj); //bind this obj
baz(8,5); //2 8 5 21
function Foo(a) {
this.a = a;
}
var bar = new Foo(6);
console.log( bar.a ); //6
まず次の一般的なthisバインディングの失われた状況を見てください.
function foo() {
setTimeout(function() {
console.log( this.a );
},1000);
}
var obj = {
a : 2
}
foo.call(obj); //undefined
ここでは、setTimeoutで発生した暗黙的な損失のために、thisはデフォルト規則を適用し、出力undefined
が行われる.thisをどのように私たちが欲しいobjオブジェクトに結び付けますか?var obj = {
a : 2
}
function foo() {
setTimeout( () => {
console.log( this.a );
},1000);
}
foo.call(obj) //2
矢印関数のthisは語法的にfoo
を継承しているので、呼び出し時foo
のthis、すなわちthisはobj
オブジェクトに結合される.参考書:「JavaScript高級プログラム設計」「あなたの知らないJavaScript」(上)