無論在 javascript 的日常使用中還是前端面試過程中,this 的出鏡率都極高。這無疑說明了,this 的重要性。但 this 非常靈活,導致許多人覺得 this 的行為難以理解。本文從為什麼要有 this 作為切入點,總結了 this 的六大規則,希望能幫助你解答困惑。
簡介
this 實際上相當於一個參數,這個參數可能是開發中手動傳入的,也可能是 JS 或第三方傳入的。
這個參數,通常指向的是函數執行時的「擁有者」。 this 的機制,可以讓函數設計的更簡潔,而且多用性更好。
this 是在函數執行時進行綁定的,綁定規則一共六條,分別是:
●new 綁定:使用 new 關鍵字建立物件時,this 會綁定到已建立的物件上。
●明確綁定:使用 call、apply 或 bind 方法明確綁定時, this 為其第一個參數。
●隱式綁定:當函數掛在物件上執行時,系統會隱含地將 this 綁定到該物件上。
●預設綁定:當函數獨立執行時,嚴格模式 this 的預設綁定值為 undefined,否則為全域物件。
●箭頭函數綁定:使用箭頭函數時,this的綁定值等於其外層的普通函數(或全域物件本身)的this。
●系統或第三方綁定:當函數作為參數,傳入系統或第三方提供的介面時,傳入函數中的 this 是由系統或第三方綁定的。
this 的作用
this 的機制提供了一個優雅的方式,隱式地傳遞一個對象,這可以讓函數設計的更加簡潔,並且復用性更好。
考慮下面一個例子,有兩個按鈕,點擊後將其背景改為紅色。
function changeBackgroundColor(ele) { ele.style.backgroundColor = 'red'; } btn1.addEventListener('click',function () { changeBackgroundColor(btn1); }); btn2.addEventListener('click',function () { changeBackgroundColor(btn2); });
在這裡,我們明確地將被點擊的元素傳遞給了 changeBackgroundColor 函數。但實際上,這裡可以利用 this 隱式傳遞上下文的特點,直接在函數取得目前被點擊的元素。如下:
function changeBackgroundColor() { this.style.backgroundColor = 'red'; } btn1.addEventListener('click',changeBackgroundColor); btn2.addEventListener('click',changeBackgroundColor);
在第一個例子中,被點擊元素是透過 ele ,這個形式參數來取代的。而在第二個例子中,是透過一個特殊的關鍵字 this 來取代。 this 它的作用和形式參數類似,其本質上是一個物件的引用,它的特殊性在於不需要手動傳值,所以使用起來會更加簡單和方便。
六大規則
在實際使用中, this 究竟指向哪個物件是最令人困惑的。本文歸類了六類情景,總結六條 this 的綁定規則。
1.new 綁定
使用 new 建立物件的時候,類別中的 this 指的是什麼?
class Person { constructor(name){ this.name = name; } getThis(){ return this } } const xiaoMing = new Person("小明"); console.log(xiaoMing.getThis() === xiaoMing); // true console.log(xiaoMing.getThis() === Person); // false console.log(xiaoMing.name === "小明"); // true
在上面範例中,使用了 ES6 的語法建立了 Person 類別。在使用 new 關鍵字建立物件的過程中,this 會由系統自動綁定到已建立的物件上,也就是 xiaoMing。
規則一:在使用 new 關鍵字建立物件時,this 會綁定到已建立的物件上。
2.明確綁定
情景二,使用 call、apply 和 bind 方法,明確綁定 this 參數。
以 call 為例,call 方法的第一個傳入的參數,是 this 所引用的物件。
function foo() { console.log( this === obj ); // true console.log( this.a === 2 ); // true}const obj = { a: 2}; foo.call( obj );
在明確傳遞的情況下,this 指向的物件很明顯,就是 call、apply 或 bind 方法的第一個參數。
規則二:使用 call、apply 或 bind 方法明確綁定時, this 為其第一個參數。
3.隱式綁定
隱式綁定和明確綁定不同的地方在於,明確綁定由開發者來指定this;而隱式綁定時,函數或方法綁定不同的地方在於,明確綁定由開發者來指定this;而隱式綁定時,函數或方法綁定時,函數或方法綁定都會有一個“擁有者”,這個“擁有者”指的是直接呼叫的函數或方法物件。
例一
先看一個最簡單的例子。
function bar() { console.log( this === obj ); }const obj = { foo: function () { console.log( this === obj ); }, bar: bar }; obj.foo(); // trueobj.bar(); // true
函數 foo 是直接掛在物件 obj 裡面的,函數 bar 是在外面定義的,然後掛在物件 obj 上的。無論函數是在何處定義,但最後函數呼叫時,它的「擁有者」是 obj。所以 this 指向的是函數呼叫時的「擁有者」 obj。
例二
為了更深入的理解,再考慮函數重新賦值到新的物件上的情況,來看看下面的例子。
function bar() { console.log( this === obj1 ); // false console.log( this === obj2 ); // true}const obj1 = { foo: function () { console.log( this === obj1 ); // false console.log( this === obj2 ); // true }, bar: bar };const obj2 = { foo: obj1.foo, bar: obj1.bar }; obj2.foo(); obj2.bar();
在這個例子中,將 obj1 中的 foo 和 bar 方法賦值給了 obj2。函數呼叫時,「擁有者」是 obj2,而不是 obj1。所以 this 指向的是 obj2。
例三
物件可以多層嵌套,在這種情況下執行函數,函數的「擁有者」是誰呢?
const obj1 = { obj2: { foo: function foo() { console.log( this === obj1 ); // false console.log( this === obj1.obj2 ); // true } } }; obj1.obj2.foo()
foo 方法/函數中的直接呼叫者是 obj2,而不是 obj1,所以函數的「擁有者」指向的是離它最近的直接呼叫者。
例四
如果一个方法/函数,在它的直接对象上调用执行,又同时执行了 call 方法,那么它是属于隐式绑定还是显式绑定呢?
const obj1 = { a: 1, foo: function () { console.log(this === obj1); // false console.log(this === obj2); // true console.log(this.a === 2); // true } };const obj2 = { a: 2}; obj1.foo.call(obj2); // true
由上,可以看出,如果显式绑定存在,它就不可能属于隐式绑定。
规则三:如果函数是挂在对象上执行的,这个时候系统会隐式的将 this 绑定为函数执行时的“拥有者”。
4.默认绑定
前一小段,讨论了函数作为对象的方法执行时的情况。本小段,要讨论的是,函数独立执行的情况。
在函数直接调用的情况下,this 绑定的行为,称之为默认绑定。
例一
为了简单起见,先讨论在浏览器的非严格模式的下绑定行为。
function foo() { console.log( this === window); // true} foo();
在上面的例子中,系统将 window 默认地绑定到函数的 this 上。
例二
在这里,先介绍一种我们可能会在代码中见到的显式绑定 null 的写法。
function foo() { console.log( this == window ); // true} foo.apply(null);
将例一默认绑定的情况,改为了显式绑定 null 的情况。
在实际开发中,我们可能会用到 apply 方法,并在第一个参数传入 null 值,第二个参数传入数组的方式来传递数组类型的参数。这是一种传统的写法,当然现在可以用 ES6 的写法来代替,但是这不在本文的讨论范围内。
在本例最需要关注的是,this 竟然指向的 window 而不是 null。个人测试的结果是,在函数独立调用时,或者显式调用,传入的值为 null 和 undefined 的情况下,会将 window 默认绑定到 this 上。
在函数多次调用,形成了一个调用栈的情况下,默认绑定的规则也是成立的。
例三
接着,探讨下严格模式下,this 的默认绑定的值。
"use strict"; function foo() { console.log( this === undefined ); } foo(); // true foo.call(undefined); // true foo.call(null); // false
在严格模式下,this 的默认绑定的值为 undefined。
规则四:在函数独立执行的情况下,严格模式 this 的默认绑定值为 undefined,否则默认绑定的值为 window。
5.箭头函数绑定
箭头函数实际上,只是一个语法糖,实际上箭头函数中的 this 实际上是其外层函数(或者 window/global 本身)中的 this。
// ES6 function foo() { setTimeout(() => { console.log(this === obj); // true }, 100); } const obj = { a : 1 } foo.call(obj); // ES5 function foo() { var _this = this; setTimeout(function () { console.log(_this === obj); // true }, 100); } var obj = { a : 1 } foo.call(obj);
规则五:使用箭头函数时,this 的绑定值和其外层的普通函数(或者 window/global 本身) this 绑定值相同。
6.系统或第三方绑定
在 JavaScript 中,函数是第一公民,可以将函数以值的方式,传入任何系统或者第三方提供的函数中。现在讨论,最后一种情况。当将函数作为值,传入系统函数或者第三方函数中时,this 究竟是如何绑定的。
我们在文章一开始提到的,两个按钮例子,系统自动将 this 绑定为点击的按钮。
function changeBackgroundColor() { console.log(this === btn1); // true} btn1.addEventListener('click',changeBackgroundColor);
接着测试系统提供的 setTimeout 接口在浏览器和 node 中绑定行为。
// 浏览器 setTimeout(function () { console.log(this === window); // true },0) // node setTimeout(function () { console.log(this === global); // false console.log(this); // Timeout },0)
很神奇的是,setTimeout 在 node 和浏览器中的绑定行为不一致。如果我们将 node 的中的 this 打印出来,会发现它绑定是一个 Timeout 对象。
如果是第三发提供的接口,情况会更加复杂。因为在其内部,会将什么值绑定到传入的函数的 this 上,事先是不知道的,除非查看文档或者源码。
系统或者第三方,在其内部,可能会使用前面的五种规则一种或多种规则,对传入函数的 this 进行绑定。所以,规则六,实际上一条在由前五条规则上衍生出来的规则。
规则六:调用系统或者第三方提供的接口时,传入函数中的 this 是由系统或者第三方绑定的。

vscode自身是支持vue文件组件跳转到定义的,但是支持的力度是非常弱的。我们在vue-cli的配置的下,可以写很多灵活的用法,这样可以提升我们的生产效率。但是正是这些灵活的写法,导致了vscode自身提供的功能无法支持跳转到文件定义。为了兼容这些灵活的写法,提高工作效率,所以写了一个vscode支持vue文件跳转到定义的插件。

JavaScript 不提供任何内存管理操作。相反,内存由 JavaScript VM 通过内存回收过程管理,该过程称为垃圾收集。

Node 19已正式发布,下面本篇文章就来带大家详解了解一下Node.js 19的 6 大特性,希望对大家有所帮助!

选择一个Node的Docker镜像看起来像是一件小事,但是镜像的大小和潜在漏洞可能会对你的CI/CD流程和安全造成重大的影响。那我们如何选择一个最好Node.js Docker镜像呢?

本篇文章给大家整理和分享几个前端文件处理相关的实用工具库,共分成6大类一一介绍给大家,希望对大家有所帮助。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)