JavaScriptを使用して開発する場合、多くの開発者はこの点に多少混乱しますが、実際、この点については、コアセンテンスを覚えておいてください。関数を呼び出すオブジェクトと、関数内のこれが指すオブジェクトです。
これのいくつかのモード:
- メソッド呼び出しモードでは、これは常にメソッドが呼び出されるオブジェクトを指し、この方向はメソッドの呼び出し位置に関連し、メソッドの宣言位置とは関係ありません(矢印関数は特別です) ;
- 関数呼び出しでは、これはウィンドウを指します。呼び出し元のメソッドに明確なオブジェクトがない場合、これはsetTimeout、無名関数などのウィンドウを指します。
- コンストラクター呼び出しモードでは、これは構築中のオブジェクトを指します。
- 適用、呼び出し、バインド呼び出しモードでは、これは最初のパラメーターを指します。
- 矢印関数。呼び出し場所に依存するのではなく、宣言時にこれをバインドします。
- 厳密モードでは、これが実行コンテキストによって定義されていない場合、これは未定義です。
以下に例を示し、これらの状況の原則を説明します。
1.メソッド呼び出しモード
// 声明位置
var test = function(){
console.log(this.x)
}
var x = "2";
var obj = {
x:"1",
fn:test,
}
// 调用位置
obj.fn(); // 1
test(); // 2
上記のコードでは、これはメソッドが呼び出されたオブジェクトを指し、testメソッドはobjオブジェクトの下にあるため、これはobjを指し、testはwindowオブジェクトの下にあるため、これはwindowを指していることがわかります。これは宣言の位置とは関係がなく、呼び出しの位置に関連していることもわかります。
ただし、以下の状況に注意してください
let obj1={
a:222
};
let obj2={
a:111,
fn:function(){
console.log(this.a);
}
}
obj1.fn = obj2.fn;
obj1.fn(); // 222
これは理解するのは難しいことではありません。obj1.fnはobj2.fnから割り当てられますが、呼び出し元の関数はobj1であるため、これはobj1を指します。
2.関数呼び出しモード
var a = 1;
function fn1(){
console.log(this.a); // 1
}
fn1();
window.b = 2;
function fn2(){
console.log(this.b); // 2
}
fn2();
//可以理解为 window.fn();
匿名関数、setTimeout:
(function(){
console.log(this); // window
})();
setTimeout(() => {
console.log(this); // window
}, 0);
setTimeout(function(){
console.log(this); // window
}, 0);
3.コンストラクターモード
var flag = undefined;
function Fn(){
flag = this;
}
var obj = new Fn();
console.log(flag === obj); // true
これはobjを指します。内部原則は、applyを使用してこれをobjを指すことです。JavaScriptの新しいオブジェクトプロセスの詳細な説明を思い出してください。
4.呼び出し、適用、バインド
callとapplyの関数はまったく同じですが、唯一の違いはパラメーターです。
呼び出しによって受信されるパラメーターは固定されていません。最初のパラメーターは関数本体のこのポイントであり、2番目のパラメーターは次のパラメーターです。順番に渡されます。
applyは2つのパラメーターを受け取ります。最初のパラメーターは、関数本体のこのポイントでもあります。2番目のパラメーターはコレクションオブジェクト(配列またはクラス配列)です
var obj = {
name:'111',
getName:function(){
console.log(this.name)
}
};
var otherObj = {
name:'222',
};
var name = '333';
obj.getName(); // 111
obj.getName.call(); // 333
obj.getName.call(otherObj); // 222
obj.getName.apply(); // 333
obj.getName.apply(otherObj); // 222
obj.getName.bind(this)(); // 333
obj.getName.bind(otherObj)();// 222
5.矢印関数
ES6の矢印関数に関して、公式の説明は次のとおりです。
矢印関数のthisはコンテキストであり、外側のスコープのthisは矢印関数のthisです。
矢印関数のこれを判断する:
ヒント:外層には機能がありません。これはウィンドウです。外層のこれが誰で、誰がこれであるかに応じて、外層に関数があります。
外側の関数は、通常の関数または矢印関数の場合があります。関数のタイプに応じて、
外側の関数を決定するためにさまざまな方法が使用されます。外側の関数は、外側の関数を呼び出した人に応じて通常の関数です。
外側の関数は、今に基づいた矢印機能判断するスキルを言います。
let obj={
a:222,
fn:function(){
setTimeout(()=>{
console.log(this.a)});
}
};
obj.fn(); // 222
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello(); // 输出的是window,根据刚才讲的规则就可以判断
// 那如何改造成永远绑定A呢:
var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s
}
}
var sayHello = A.sayHello();
sayHello();// 输出A
- call()、apply()、およびbind()メソッドは、パラメーターを矢印関数に渡すだけであり、これには影響しません。
- これが字句レベルであることを考慮すると、厳密モードでこれに関連するすべてのルールは無視されます(厳密モードであるかどうかは無視されます)。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
var obj = {
foo: foo};
console.log(foo.call(obj) === globalObject); // true
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
6.厳密モード
非厳密モードでは、これはデフォルトでグローバルオブジェクトウィンドウを指します。
// 非严格模式
function f1(){
return this;
}
console.log(f1() === window); // true
厳密モードでは、これは未定義です。
// 严格模式
"use strict";
var fn2 = function(){
return this
}
console.log(fn2() == undefined); // true