JavaScript関数における外部変数——thisの理解

4324 ワード

jsの中のthisは確かにピットを指して、ネット上である人はすさまじい勢いでそれを討論して、jsが閉じて包むことを討論して、実はそんなに玄学ではありませんて、私達に少しずつそのベールをはがします.
多くの内容は邱桐城の『JavaScriptの中のthis』からの啓発で、彼の文章に基づいて、私は私の総括を書きました.
グローバルスコープで
ブラウザ環境で:
console.log(this);
// Window { .. }
this === window;
// true
グローバルスコープでは、thisはWindowオブジェクトを指しています.これはよく理解されています.依然として伝統的なjsの結果です.
nodeの環境で:
console.log(this);
// global
this === global;
// true
グローバルスコープでは、thisはglobalオブジェクトを指します.
厳格なモードは、nodeの環境で:
'use strict';
console.log(this);
// {}
厳密なパターンの仕様に従い、thisは全体のオブジェクトを指しません.
関数オブジェクトのスコープで
function foo() {
    console.log(this);
}
foo();
// global / Window
厳格なモードは、nodeの環境で:
'use strict';
function foo() {
    console.log(this);
}
foo();
// undefined
私のテストを経て、仕様要求を満たしましたが、node 7.2.0の下では依然として上記のような不一致の結果が現れました.
対象方法のスコープ内
let obj = {
    foo: function() {
        console.log(this);
    }
};
obj.foo();
// { foo: [Function] }
// obj              ,foo            
対象とする方法の場合、thisはそのオブジェクトを指します.
function func() {
    console.log(this);
}
let obj = {
    foo: func
};
obj.foo();
// { foo: [Function func] }

let foo1 = obj.foo;
foo1();
// global
関数内で使用される関数の外部で定義される変数(宣言)は、 であることに留意されたい.
この例が印象的かもしれません.
var foos = [];
for (var i = 0; i < 3; ++i) {
    foos.unshift(function () {
        console.log(i);
    });
}
console.log(i);
// 3
for (var j in foos) {
    ++i;
    console.log(i);
    // 4 5 6
    foos[j]();
    // 4 5 6
}
i変数は関数内で外部変数の参照であるため、関数外のi値が変化すると関数内のi値も一緒に変化します.
このような外部変数参照を回避するのも簡単であり、constletのような新しいキーワードを使用するのは最も簡単であり、これは従来のvarよりも厳密に定義されたドメインであり、その変数が実行されないときにコンテキストでアクセスできないようにして、その値が置換されないことを保証する.
const foos = [];
for (let i = 0; i < 3; ++i) {
    foos.unshift(function () {
        console.log(i);
    });
}
for (let i in foos) {
    foos[i]();
}
// 0 1 2
新しいキーワードがこの問題を解決したのではなく、新しいキーワードがより厳密な作用領域を持っています.この変数が実行中のコンテキストでまだアクセスできる場合、その問題は元の通りです.
const foos = [];
let i;
for (i = 0; i < 3; ++i) {
    foos.unshift(function () {
        console.log(i);
    });
}
for (let j in foos) {
    foos[j]();
}
// 3 3 3
上記の例を見たら、関数内のthisもこのような外部変数の参照であることが分かります.従来のfunctionキーワードを使用する文法では、確かにそうである.ES 6に導入された新しい=>文法では、事情が違っています.このような疑似コードが関数に挿入されたと考えられます.
//        js   
const this = outer.this;
一例を見てみます
'use strict';

const obj1 = {
    foo: function() {
        console.log(this);
        return () => {
            console.log(this);
        };
    }
};
const foo1 = obj1.foo();
// { foo: [Function: foo] }
foo1();
// { foo: [Function: foo] }

const obj2 = {
    foo: function() {
        console.log(this);
        return function () {
            console.log(this);
        };
    }
};
const foo2 = obj2.foo();
// { foo: [Function: foo] }
foo2();
// undefined
=>構文で定義された関数オブジェクトは、functionキーワードで定義された関数オブジェクトとは異なり、定義されたコンテキストのthisを指し、外部thisの変化に従って変化する.
コンストラクタオブジェクトのスコープ(newキーワードを使用)
'use strict';

function A() {
    console.log(this);
}

var a = new A();
// A {}
console.log(a);
// A {}

var b = A();
// undefined
console.log(b);
// undefined
構造関数のthisは、その構成されたオブジェクトを指すが、newキーワードを使用することを忘れないでください.
call/appy/bind
jsの関数オブジェクトは、そのプロトタイプに以下の3つの関数が定義されています.
func.call(thisArg[, arg1[, arg2[, ...]]]);
実行関数funcは、最初のパラメータをthisとし、他のパラメータをfuncの実参として一対一に対応します.
func.apply(thisArg[, [arg1, arg2, ...]]);
関数funcを実行して、最初のパラメータをthisとして使用して、第二のパラメータは配列であり、配列中の各要素はfuncの実パラメータとして一対一に対応しています.
var foo = func.bind(thisArg[, arg1[, arg2[, ...]]]);
Fncを結合したthisとすべてのパラメータは、新しい関数を返しますが、実行しません.
Bindのthisはnewキーワードに対して無効であるが、他のパラメータは有効である:
function A(name) {
    console.log(this.name);
    this.name = name;
    console.log(this.name);
}
var obj = {
    name: "obj"
};
var B = A.bind(obj, "B");
var b = new B('b');
// undefined B
console.log(obj.name);
// obj
=>構文でのthisは影響を受けないので、この構文ではthisはconst変数と見なされ、修正を受け付けない.