首頁 web前端 js教程 JS中this、apply、call、bind的相關介紹

JS中this、apply、call、bind的相關介紹

Sep 20, 2017 am 09:28 AM
apply bind javascript

JS中的this、apply、call、bind是一道經典面試題,最好還是了解一下 this 的指向和 call、apply、bind 三者的區別。以下就跟著腳本之家小編一起學習this、apply、call、bind的知識吧

這又是一個面試經典問題~/(ㄒoㄒ)/~~也是ES5中眾多坑中的一個,在ES6 中可能會極大避免this 產生的錯誤,但是為了一些老代碼的維護,最好還是了解一下this 的指向和call、apply、bind 三者的區別。

this 的指向

在ES5 中,其實this 的指向,總是堅持一個原理:this 永遠指向最後調用它的那個對象,來,跟著我朗讀三遍:this 永遠指向最後調用它的那個對象,this 永遠指向最後調用它的那個對象,this 永遠指向最後調用它的那個對象。記住這句話,this 你已經了解一半了。

下面我們來看一個最簡單的例子:

範例1:


#
 var name = "windowsName";
 function a() {
  var name = "Cherry";
  console.log(this.name);   // windowsName
  console.log("inner:" + this); // inner: Window
 }
 a();
 console.log("outer:" + this)   // outer: Window
登入後複製

這個相信大家都知道為什麼log 的是windowsName,因為根據剛剛的那句話“this 永遠指向最後調用它的那個對象”,我們看最後調用a 的地方a();,前面沒有調用的對像那麼就是全局對象window,這就相當於是window. a();注意,這裡我們沒有使用嚴格模式,如果使用嚴格模式的話,全域物件就是undefined,那麼就會報錯Uncaught TypeError: Cannot read property 'name' of undefined。

再看下這個例子:

範例2:


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 a.fn();
登入後複製

在這個例子中,函數fn 是物件a 呼叫的,所以列印的值就是a 中的name 的值。是不是有點清晰了呢~

我們做一個小小的改動:

範例3:


##

var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 window.a.fn();
登入後複製

這裡印Cherry的原因也是因為剛剛那句話“this 永遠指向最後調用它的那個對象”,最後調用它的對象仍然是對象a。

我們再來看這個範例:

範例 4:


 var name = "windowsName";
 var a = {
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // undefined
  }
 }
 window.a.fn();
登入後複製

這裡為什麼會印 undefined 呢?這是因為正如剛剛所描述的那樣,調用fn 的是a 對象,也就是說fn 的內部的this 是對象a,而對象a 中並沒有對name 進行定義,所以log 的this.name 的值是undefined 。

這個例子還是說明了:this 永遠指向最後調用它的那個對象,因為最後調用fn 的對像是a,所以就算a 中沒有name 這個屬性,也不會繼續向上一個對象尋找this. name,而是直接輸出undefined。

再來看一個比較坑的例子:

例5:


#

 var name = "windowsName";
 var a = {
  name : null,
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // windowsName
  }
 }
 var f = a.fn;
 f();
登入後複製

這裡你可能會有疑問,為什麼不是Cherry,這是因為雖然將a 物件的fn 方法賦值給變數f 了,但是沒有調用,再接著跟我念這句話:“this 永遠指向最後調用它的那個物件”,由於剛剛的f 並沒有調用,所以fn() 最後仍然是被window 呼叫的。所以 this 指向的就是 window。

由以上五個例子我們可以看出,this 的指向並不是在創建的時候就可以確定的,在 es5 中,永遠是this 永遠指向最後調用它的那個對象。

再來看一個例子:

範例6:


 var name = "windowsName";
 function fn() {
  var name = 'Cherry';
  innerFunction();
  function innerFunction() {
   console.log(this.name);  // windowsName
  }
 }
 fn()
登入後複製

讀到現在了應該能夠理解這是為什麼了(o゚▽゚)o。

怎麼改變this 的指向

改變this 的指向我總結有以下幾種方法:

使用ES6 的箭頭函數

在函數內部使用_this = this

使用apply、call、bind

new 實例化一個物件

範例7:


var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   },100);
  }
 };
 a.func2()  // this.func1 is not a function
登入後複製

在不使用箭頭函數的情況下,是會報錯的,因為最後呼叫setTimeout 的物件是window,但是在window 中並沒有func1 函數。

我們在改變 this 指向這一節將把這個例子當作 demo 來改造。

箭頭函數

眾所周知,ES6 的箭頭函數是可以避免 ES5 中使用 this 的坑的。箭頭函數的 this 總是指向函數定義時的 this,而非執行時。 ,箭頭函數需要記著這句話:「箭頭函數中沒有this 綁定,必須透過尋找作用域鏈來決定其值,如果箭頭函數被非箭頭函數包含,則this 綁定的是最近一層非箭頭函數的this,否則,this 為undefined」。

範例8 :


 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( () => {
    this.func1()
   },100);
  }
 };
 a.func2()  // Cherry
登入後複製

在函數內部使用_this = this

如果不使用ES6,那麼這種方式應該是最簡單的不會出錯的方式了,我們是先將呼叫這個函數的物件保存在變數_this 中,然後在函數中都使用這​​個_this,這樣_this 就不會改變了。

範例 9:


#

 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   var _this = this;
   setTimeout( function() {
    _this.func1()
   },100);
  }
 };
 a.func2()  // Cherry
登入後複製

这个例子中,在 func2 中,首先设置 var _this = this;,这里的 this 是调用 func2 的对象 a,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this(指向变量 a) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 a 了。

使用 apply、call、bind

使用 apply、call、bind 函数也是可以改变 this 的指向的,原理稍后再讲,我们先来看一下是怎么实现的:

使用 apply

例 10:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.apply(a),100);
  }
 };
 a.func2()   // Cherry
登入後複製

使用 call

例 11:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.call(a),100);
  }
 };
 a.func2()   // Cherry
登入後複製

使用 bind

例 12:


var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.bind(a)(),100);
  }
 };
 a.func2()   // Cherry
登入後複製

apply、call、bind 区别

刚刚我们已经介绍了 apply、call、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。

在 MDN 中定义 apply 如下;

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

语法:


fun.apply(thisArg, [argsArray])
登入後複製

thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。

apply 和 call 的区别

其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。

call 的语法为:


fun.call(thisArg[, arg1[, arg2[, ...]]])
登入後複製

所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

例 13:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.apply(a,[1,2])  // 3
登入後複製

例 14:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.call(a,1,2)  // 3
登入後複製

bind 和 apply、call 区别

我们先来将刚刚的例子使用 bind 试一下


 var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)
登入後複製

我们会发现并没有输出,这是为什么呢,我们来看一下 MDN 上的文档说明:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

所以我们可以看出,bind 是创建一个新的函数,我们必须要手动去调用:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)()   // 3
登入後複製

以上是JS中this、apply、call、bind的相關介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles