JS中this的指向問題
阿新 • • 發佈:2020-11-18
this:當前執行上下文(global、function、eval)的一個屬性,在非嚴格模式下總是指向一個物件;在嚴格模式下可以為任意值。
全域性上下文環境: 在全域性執行環境(在任何函式體外部)中,無論是否為嚴格模式,this都指向全域性物件(在瀏覽器中全域性物件為window;在Node環境中全域性物件為globalThis); 函式上下文環境: 在函式內容,this的值取決於函式被呼叫的方式。 在非嚴格模式下,直接呼叫f1函式,此時this的指向為全域性物件,因為在瀏覽器中直接呼叫f1函式,相當於window.f1(); 在嚴格模式下直接呼叫f2函式,此時this的值為undefined,因為在直接呼叫f2函式進入f2函式執行環境時沒有設定this的值; 類上下文環境: this在類中的表現與函式中相似,需注意的是:在類的建構函式中,this是一個常規物件;類中所有非靜態方法都會被新增到this的原型中。
在非嚴格模式下使用call()和apply()時,如果指定this的值(即call和apply方法中的第一個引數)不是物件,則會被嘗試的轉化為物件(如:7-->NewNumber(7)),null和undefined會被轉化為全域性物件。 call()和apply()方法的區別:call()方法傳引數時直接寫值,apply()方法傳引數時需以陣列的形式傳遞
箭頭函式中的this 在箭頭函式中,this與封閉詞法環境中的this保持一致,不再取決於函式被呼叫時的環境,而是取決於箭頭函式被建立時的環境. 箭頭函式中的this會被永久繫結到它外層函式的this。
當函式作為物件裡的方法被呼叫時,this被設定為呼叫該函式的物件,且this的繫結只受最接近的成員引用的影響
當一個函式用作建構函式時(使用new關鍵字),它的this被繫結到正在構造的新物件
全域性上下文環境: 在全域性執行環境(在任何函式體外部)中,無論是否為嚴格模式,this都指向全域性物件(在瀏覽器中全域性物件為window;在Node環境中全域性物件為globalThis); 函式上下文環境: 在函式內容,this的值取決於函式被呼叫的方式。 在非嚴格模式下,直接呼叫f1函式,此時this的指向為全域性物件,因為在瀏覽器中直接呼叫f1函式,相當於window.f1(); 在嚴格模式下直接呼叫f2函式,此時this的值為undefined,因為在直接呼叫f2函式進入f2函式執行環境時沒有設定this的值; 類上下文環境: this在類中的表現與函式中相似,需注意的是:在類的建構函式中,this是一個常規物件;類中所有非靜態方法都會被新增到this的原型中。
在非嚴格模式下使用call()和apply()時,如果指定this的值(即call和apply方法中的第一個引數)不是物件,則會被嘗試的轉化為物件(如:7-->NewNumber(7)),null和undefined會被轉化為全域性物件。 call()和apply()方法的區別:call()方法傳引數時直接寫值,apply()方法傳引數時需以陣列的形式傳遞
箭頭函式中的this 在箭頭函式中,this與封閉詞法環境中的this保持一致,不再取決於函式被呼叫時的環境,而是取決於箭頭函式被建立時的環境. 箭頭函式中的this會被永久繫結到它外層函式的this。
當函式作為物件裡的方法被呼叫時,this被設定為呼叫該函式的物件,且this的繫結只受最接近的成員引用的影響
當一個函式用作建構函式時(使用new關鍵字),它的this被繫結到正在構造的新物件
function f1() { console.log(this); } f1(); // Window -- 瀏覽器中,相當於 window.f1(); globalThis -- Node中 function f2() { 'use strict'; // 採用嚴格模式 console.log(this); } console.log('直接呼叫f2'); f2(); // undefined console.log('採用window.f2()'); window.f2(); // Window console.log('===================================='); var obj = {a: 'Custom'}; var a = 'Global'; function whatsThis() { return this.a; } console.log(whatsThis()); // Global console.log(whatsThis.call(obj)); // Custom console.log(whatsThis.apply(obj)); // Custom console.log('===================================='); function add(c, d) { return this.a + this.b + c + d; } var o = {a: 1, b: 3}; console.log(add.call(o, 5, 7)); // 1+3+5+7 = 16 console.log(add.apply(o, [10, 20])); // 1+3+10+20 = 34 console.log('===================================='); function f(){ return this.a; } var g = f.bind({a:"azerty"}); // 變數 g 為一個函式,方法體內容同函式 f 一致,this被永久指向{a:"azerty"}物件 console.log(g()); // azerty var h = g.bind({a:'yoo'}); // 變數 h 為一個函式,方法體內容同函式 g 一致 console.log(h()); // azerty -- bind只生效一次! var o = {a:37, f:f, g:g, h:h}; console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty console.log('===================================='); var globalObject = this; var foo = (() => this); console.log(foo() === globalObject); // true var obj = {foo: foo}; console.log(obj.foo() === globalObject); // true console.log(foo.call(obj) === globalObject); // true foo = foo.bind(obj); console.log(foo() === globalObject); // true console.log('===================================='); var obj = { bar: function() { var x = (() => this); return x; } }; var fn = obj.bar(); // fn 為箭頭函式(() => this) console.log(fn() === obj); // true var fn2 = obj.bar; // fn2 為函式function() {var x = (() => this); return x;} console.log(fn2()() == window); // true console.log('===================================='); var o = { a: 10, b: 20, f: function() { return this.a + this.b; } }; var p = Object.create(o); p.a = 1; p.b = 4; console.log(p.f()); // 5 console.log('===================================='); function sum() { return this.a + this.b + this.c; } var o = { a: 1, b: 2, c: 3, get average() { return (this.a + this.b + this.c) / 3; } }; Object.defineProperty(o, 'sum', { get: sum, enumerable: true, configurable: true}); console.log(o.average, o.sum); // 2, 6