var,letとconstの深い解析(一)

7119 ワード

Es 6には素晴らしい特性がたくさんあります.この言語全体に詳しいかもしれませんが、内部でどのように働いているか知っていますか.内部の原理を知っておくと、もっと安心して使えます.ここで私たちは徐々にあなたを導いて、あなたにもっと深く、もっと浅い認識を持ってもらいたいと思っています.まずes 6の変数から始めましょう.

letとconst


es 6では、変数を明らかにするために2つの方法が新たに導入されました.私たちは依然として広く朗読されているvar変数を使用することができます(しかし、それを使用し続けるべきではありません.その理由を理解するために読み続けます).しかし、今ではletとconstの2つのより牛のツールが使用されています.

let


letはvarと非常に似ています.使用上は、変数を宣言するために完全に同じ方法を使用することができます.たとえば、次のようにします.
let myNewVariable = 2;
var myOldVariable = 3;

console.log(myNewVariable); // 2
console.log(myOldVariable); // 3


しかし、実際には、彼らの間にはいくつかの明らかな違いがあります.彼らはキーワードが変わっただけでなく、実際には私たちのいくつかの仕事を簡素化し、奇妙なバグを防ぐことができます.これらの違いは次のとおりです.
letはブロック状の役割ドメイン(私は文章の後ろで役割ドメインに関するものを再説明します)であり、varは関数の役割ドメインです.
letは定義する前に変数にアクセスできません(varは可能で、js世界の多くのバグと悩みの源です).
letは再定義できません.
これらの違いを説明する前に、まずもっとクールな変数を見てみましょう.const

const


constとletは非常に似ています(varに比べて、彼らの間には多くの同じ点があります)が、letは再付与できますが、constはできません.したがってconst定義の変数には1つの値しかありません.この値は宣言時に付与されます.そこで、次の例を見てみましょう.
const myConstVariable = 2;
let myLetVariable = 3;

console.log(myConstVariable); // 2
myLetVariable = 4;  // ok
myConstVariable = 5;  //wrong - TypeError thrown


しかしconstは全く可変ではありませんか?
変数を再割り当てすることはできませんが、本当に可変な状態にすることはできません.const変数に値として配列またはオブジェクトがある場合は、次のコードのように値を変更する可能性があります.
const myConstObject = {mutableProperty: 2};

// myConstObject = {}; - TypeError
myConstObject.mutableProperty = 3; //ok
console.log(myConstObject.mutableProperty); // 3
const myConstArray = [1];

// myConstArray = []; - TypeError
myConstArray.push(2) //ok
console.log(myConstArray); // [1, 2]

もちろん、string、number、booleanなどの元のデータ型の値は使用できません.彼らは本質的に可変ではないからです.

真の不変


私たちの変数を本当に可変にしたいならObjectを使ってもいいです.freeze()は、オブジェクトを可変に保つことができます.残念なことに、彼は浅いだけで可変ではありません.もしあなたのオブジェクトにオブジェクトがネストされているならば、それは依然として可変です.
const myConstNestedObject = {
  immutableObject: {
    mutableProperty: 1
  }
};

Object.freeze(myConstNestedObject);

myConstNestedObject.immutableObject = 10; // won't change
console.log(myConstNestedObject.immutableObject); // {mutableProperty: 1}
myConstNestedObject.immutableObject.mutableProperty = 10; // ok
console.log(myConstNestedObject.immutableObject.mutableProperty); // 10


変数の役割ドメイン


いくつかの基礎知識を紹介した後、次はもっと高級な話題に入ります.次に、es 5変数とes 6変数の最初の異なる役割ドメインについて説明します.
注意:次の例はletを使用します.そのルールはconstにも適用されます.

グローバル変数と関数の役割ドメイン変数


jsでは,いったい何が役割ドメインなのか.本論文では,役割ドメインに関する完全な解釈は与えられない.簡単に言えば、変数の役割ドメインは変数の使用可能な位置を決定します.異なる観点から、役割ドメインは、特定の領域で使用できる変数(または関数)の宣言と言える.役割ドメインはグローバル(したがって、グローバル役割ドメインで定義された変数は、コードの任意の部分にアクセスできます)またはローカルです.
ローカル役割ドメインは内部でしかアクセスできないことは明らかです.ES 6以前は、局所的な役割ドメインfunctionを定義する方法を1つしか許可していませんでしたが、次の例を見てみましょう.
// global scope
var globalVariable = 10;

function functionWithVariable() {
  // local scope
  var localVariable = 5;
  console.log(globalVariable);  // 10
  console.log(localVariable);   // 5
}

functionWithVariable();

//global scope again
console.log(globalVariable);  // 10
console.log(localVariable);   // undefined


上記の例では、変数globalVariableはグローバル変数なので、私たちのコードの関数内または他の領域でアクセスできますが、変数localVariableは関数内で定義されているので、関数内でのみアクセスできます.
したがって、関数内で作成されたすべてのコンテンツは、関数内のすべてのネストされた関数(ネストされた多層)を含む関数内にアクセスできます.ここでは閉鎖に感謝するかもしれませんが、文章では紹介するつもりはありません.しかし、今後のブログでは、より多くの紹介があるので、引き続き注目してください.

アップグレード


簡単に言えば、昇格はすべての変数と関数が役割ドメインに「移動」することを宣言する最前線のメカニズムです.次の例を見てみましょう.
function func() {
  console.log(localVariable);   // undefined
  var localVariable = 5;

  console.log(localVariable);   // 5
}

func();


なぜ正常に機能しているのでしょうか?私たちはまだこの変数を定義していませんが、consoleを通じています.log()はundefinedを印刷します.なぜ変数が定義されていないエラーが報告されないのですか?もう一度よく見てみましょう.

変数のコンパイル


Javascript解析器はこのコードを2回巡回します.初めてコンパイル状態と呼ばれますが、今回はコードに定義されている変数がアップします.彼の後、私たちのコードは次のようになりました(私はいくつかの簡略化をして、関連する部分だけを示しました).
function func() {
  var localVariable = undefined;

  console.log(localVariable); // undefined
  localVariable = 5;

  console.log(localVariable); // 5
}

func();


我々が見た結果,我々の変数localVariableはfunc関数の役割ドメインの先頭に移動した.厳密には、私たちの変数の宣言は、宣言された関連コードではなく、位置を移動しました.この変数を使用して印刷します.これはundefinedです.私たちはまだその値を定義していないので、デフォルトで使用されています.

アップグレードの例-どのような問題が発生しますか


嫌な例を見てみましょう.私たちの役割ドメインの範囲は私たちにとって、利益よりも弊害が大きいです.関数の役割ドメインが悪いというわけではありません.昇進による陥落を警戒しなければならないということです次のコードを見てみましょう.
var callbacks = [];
for (var i = 0; i < 4; i++) {
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();


出力の値はいくらだと思いますか?0 1 2 3かもしれないと思いますか.もしそうなら、あなたにとって、サプライズがあるかもしれません.実際、彼の本当の結果は4 4 4 4です.待って何があったの?コードを「コンパイル」してみましょう.コードはこのように見えます.
var callbacks;
var i;

callbacks = [];
for (i = 0; i < 4; i++) {
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();


問題の所在を見ましたか.変数iは、役割ドメイン全体でアクセスでき、再定義されません.その値は反復のたびに絶えず変化するだけです.その後、関数呼び出しで印刷する価値を考えたとき、彼は実際には1つの値しかありませんでした.最後のループで与えられた値です.
私たちはこのようにするしかありませんか?いいえ

LetとConstの救い


変数を定義する新しい方法に加えて,ブロックレベルの役割ドメインという新しい役割ドメインが導入された.ブロックは括弧で囲まれたすべての内容です.したがって、if、while、またはfor宣言のカッコであってもよいし、単独のカッコであってもよいし、関数(はい、関数の役割ドメインはブロックの役割ドメイン)であってもよい.letとconstはブロック役割ドメインです.ブロック内でどの変数を定義しても、いつ定義されても、ブロックの役割ドメインの外には行かないことを意味します.次の例を見てみましょう.
function func() {
  // function scope
  let localVariable = 5;
  var oldLocalVariable = 5;

  if (true) {
    // block scope
    let nestedLocalVariable = 6;
    var oldNestedLocalVariable = 6;

    console.log(nestedLocalVariable); // 6
    console.log(oldNestedLocalVariable); // 6
  }

  // those are stil valid
  console.log(localVariable); // 5
  console.log(oldLocalVariable); // 5
  // and this one as well
  console.log(oldNestedLocalVariable); // 6
  // but this on isn't
  console.log(nestedLocalVariable); // ReferenceError: nestedLocalVariable is not defined

違いが見えますか?letをどのように使って以前に問題を提起したのか見ることができますか?私たちのforループにはカッコのセットが含まれているので、ブロックの役割ドメインです.したがって,ループ変数を定義する際にvarの代わりにletやconstを用いると,コードは次の形式に変わる.注意:私は実際に多くのことを簡略化しましたが、私はあなたが私の意味を理解できることを確信しています.
let callbacks = [];
for (; i < 4; i++) {
  let i = 0 //, 1, 2, 3
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();


現在のサイクルごとに独自の変数定義があるので、変数は書き換えられません.このコードは彼にやらせることができると確信しています.
これはこの部分の終わりの例ですが、次の例を見てみましょう.印刷された値の原因と、対応する表現が何なのかを知っていると信じています.
function func() {
  var functionScopedVariable = 10;
  let blockScopedVariable = 10;

  console.log(functionScopedVariable);  // 10
  console.log(blockScopedVariable);  // 10
  if (true) {
    var functionScopedVariable = 5;
    let blockScopedVariable = 5;

    console.log(functionScopedVariable);  // 5
    console.log(blockScopedVariable);  // 5
  }

  console.log(functionScopedVariable);  // 5
  console.log(blockScopedVariable);  // 10
}

func();


翻訳:
https://blog.pragmatists.com/...
この記事は以下のとおりです.http://www.lht.ren/article/15/