この記事では Javascript での this の使用法を詳しく説明します。一定の参考価値があります。困っている友人は参考にしてください。お役に立てれば幸いです。
これを JavaScript で理解する前に、まずスコープを理解してください。
スコープは 2 つのタイプに分類されます:
1. 字句スコープ: エンジンは、現在のスコープまたはネストされたサブスコープ内で名前識別子を持つ変数を検索します。 (エンジンが検索する方法と場所。定義プロセスはコード作成フェーズで発生します)
2. 動的スコープ: 実行時に動的に決定されるスコープ。
字句スコープと動的スコープの違いは次のとおりです:字句スコープはコードまたは定義の作成時に決定され、動的スコープは実行時に決定されます。
このバインディング ルール
これは、関数の呼び出し位置に応じて、呼び出されたときにバインドされます。このことから、通常の状況 (非厳密モード) では、関数呼び出しのコンテキスト (呼び出しスタック) に従ってオブジェクトがバインドされることがわかります。
1. デフォルトのバインディング
デフォルトのバインディング: デフォルトのバインディングは、非厳密モードで他のバインディング ルールが使用されないことを意味し、これは関数 (コール スタック) バインドするコンテキストに従って呼び出されます。オブジェクト (グローバル オブジェクト)。 (厳密モードでは、未定義はバインドされます)
例:
function foo() { console.log(this.a); }; function bar() { var a = 3; foo(); } var a = 2; bar(); //调用栈在全局作用域,this绑定全局对象 运行结果为: 2 //加上"use strict"运行结果则会变成this is undefined
ここで関数が呼び出されるとき、デフォルトのバインディングが使用され、関数呼び出しのコンテキスト (コール スタック) は次のようになります。グローバル スコープなので、これはグローバル オブジェクト (global) にバインドされます。
eg2: function foo() { console.log(this.a) }; var a = 2; (function() { "use strict" foo(); })(); 运行结果为: 2
ここで注意してください: デフォルトのバインディングの場合、このバインディング オブジェクトを決定するのは、呼び出し場所が厳密モードであるかどうかではなく、関数本体が厳密モードであるかどうかです (関数本体が厳密モードの場合は、このバインディングは未定義です。それ以外の場合、これはグローバル オブジェクトにバインドされます)。さらに: 厳密モードと非厳密モードをバインドすることは可能ですが、これらを混合しないことをお勧めします。
間接参照には通常、デフォルトのバインディング ルールが適用されます。
eg: function foo() { console.log(this.a); }; var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); //3 (p.foo = o.foo)(); //2
代入式 p.foo = o.foo の戻り値は、ターゲット関数 foo を直接参照します。
2. 暗黙的バインディング
暗黙的バインディング: コンテキスト オブジェクトによって呼び出され、コンテキスト オブジェクトにバインドされます。
例:
function foo() { console.log(this.a); }; var obj = { a: 2, foo: foo }; obj.foo(); //2 foo(); //undefined
このコードでは、foo() が参照属性として obj オブジェクトに追加され、obj がこの参照属性関数を呼び出すと、参照属性コンテキストが使用されます。これは obj オブジェクトにバインドされます。 (厳密に言えば、この関数は obj オブジェクトに属さず、参照属性としてのみ機能します)。暗黙的なバインディングに属します。
以下の foo() 関数の直接実行は obj オブジェクトへの参照ではないため、コンテキスト オブジェクトはグローバル オブジェクトです。したがって、これは未定義にバインドされます。デフォルトのバインディングに属します。
オブジェクト参照チェーンの上位層または最後の層のみが呼び出し位置で役割を果たします。
暗黙的にバインドされた関数は、バインドされたオブジェクトを失います。 現時点では、デフォルトのバインディングが適用され、厳密モードかどうかに応じて、これをグローバル オブジェクトまたは未定義にバインドします。
例:
function foo() { console.log(this.a); }; var obj = { a: 2; foo: foo } var bar = obj.foo; var a = 'biubiubiu'; bar(); 运行结果:"biubiubiu"
分析: bar は obj.foo への参照であるようです。実際、bar は単純な関数呼び出しである関数 foo を直接参照しているため、実際にはデフォルトのバインディングです。 。
パラメータの受け渡しは暗黙的な代入なので、関数に渡されると暗黙的に代入されます。
例:
function foo() { console.log(this.a); }; var obj = { a: 2, foo: foo }; function bar(fn) { fn(); }; var a = "biubiubiu"; bar(obj.foo); 运行结果: "biubiubiu"
分析: 実際、パラメーターも暗黙的に割り当てられますが、パラメーターは関数に渡され、関数内で実行されます。このとき、関数 foo も直接参照されているため、これもデフォルトのバインディングを使用した単純な関数呼び出しです。
関数を言語の組み込み関数に渡します。 (基本的には上記と同様ですが、自己宣言した関数を言語の組み込み関数に変更します) コールバック関数でこれが失われ、コールバック関数を呼び出す関数が失われるのが一般的です。これを変更することもできます。明示的なバインディング: これを指定されたオブジェクトに直接バインドします。 JavaScript のほとんどの関数と作成した関数は、これら 2 つの明示的なバインディング メソッドを使用できます。
1、.call()
2、.apply()
これら 2 つのバインド メソッド、最初のパラメータは、これにバインドされたオブジェクトです。 (渡されたパラメータがプリミティブ値(文字列型、ブール型、数値型)の場合、プリミティブ値はオブジェクト形式(new String、new Boolean、new Number)に変換されます。これは、コールド:パッキング)
例:
function foo() { console.log(this.a); }; var obj = { a: 2 }; foo.call(obj); 运行结果: 2
ただし、バインディングを表示してもバインディング損失の問題は解決されません。このとき、新しい友達がやって来ます - ハードバインディング(バインド)。
3. .bind() (ハード バインディングは一般的なシナリオであるため、es5 は組み込みメソッド Function.prototype.bind を提供します。)
bind() will 新しいエンコード関数を返し、これを指定されたパラメーターにバインドし、関数を呼び出します。
栗をあげる:
function foo(e) { console.log(this.a + e); return this.a + e; }; var obj = { a: 2 } var bar = foo.bind(obj); //新编码函数 var b = bar(3); // 2 3 console.log(b); // 5
bind() 関数 もあります: は、最初の 1 つ目 これにバインドされているパラメータ以外のパラメータは、基になる関数 に渡されます ( は、「currying」の一種である を部分的に適用します)。
这里涉及到一个概念:把null或者undefined作为this的绑定对象传入call、apply、bind,这些值在调用的时候会被忽略,实际应用默认绑定规则。
应用场景:
1、使用apply()展开一个数组,并作为参数传递给一个函数。
2、bind()对参数进行柯里化(预先设置一些参数)。
举个栗子:
function foo(a,b) { console.log("a:" + a + ",b:" + b); }; //数组“展开”成参数 foo.apply(null,[2,3]); //a:2,b:3 //bind()柯里化 var bar = foo.bind(null,2); bar(3); //a:2,b:3
解析:传入一个参数作为this绑定对象,如果不传则使用占位符(null),此时会使用默认绑定规则。
上面这个例子可能会产生一定的副作用,如果需要运用这种场景并且更加安全。可以创建一个空对象(可以用任意喜欢的名字来命名)。
var ∅ = Object.create(null); //上面这个例子就可以改写为: foo.apply(∅,[2,3]); //a:2,b:3 var bar = foo.bind(∅,2); bar(3); //a:2,b:3
注意:硬绑定之后不能使用隐式绑定和显式绑定对this进行修改
在这里介绍一种软绑定的方法softBind(),检查this绑定到全局对象或者undefined后,绑定this到指定的默认对象。绑定后效果和硬绑定一样,但是保留隐式绑定或者显式绑定修改this的能力。
Javascript中的new机制与面向类语言的完全不同。在Javascript中,构造函数只是一些使用new操作符时被调用的函数,不属于一个类,也不会实例化一个类。称为对函数的“构造调用”。
举个栗子:
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); //2
使用new的过程会创建一个全新的对象,this会绑定这个新对象。如果函数没有返回其他对象,则new表达式函数调用会返回该新对象。(这个新对象会连接prototype)
箭头函数是根据外层作用域(函数或全局)来决定this。(词法作用域取代this机制)
箭头函数this会绑定调用时的对象,且箭头函数的绑定无法修改(new也不行)。
其实可以理解为,箭头函数的this在词法上继承的是它所在的作用域(函数或全局)的this,而它继承的函数作用域的this绑定的是在该函数调用上下文对象,所以箭头函数的this间接的绑定在调用上下文对象。
简述: 箭头函数this(绑定作用域this)-- 作用域this(绑定在调用上下文对象)。
故:箭头函数this == 调用的上下文对象
举个栗子:
function foo() { setTimeout(function() { //这里的this在词法上继承自foo() console.log(this.a); },100); }; var obj = { a: 2 }; foo.call(obj); //2
其实这个栗子也等价于:
function foo() { var that = this; //lexical capture of this setTimeout(function() { console.log(self.a) },100); } ...与上面一样
所以,有两种风格:this风格(四种规则)和词法作用域风格(that = this和箭头函数)可供使用。使用时尽量避免混用,否则会造成难以维护的后果。
本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!
以上がJavascriptでの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。