首頁 >web前端 >js教程 >JavaScript中的this,call,apply使用及區別詳解

JavaScript中的this,call,apply使用及區別詳解

PHPz
PHPz原創
2016-05-16 15:17:091328瀏覽

在之前的JavaScript學習中,this,call,apply總是讓我感到迷惑,但是他們的運用又非常的廣泛。遂專門花了一天,來弄清楚JavaScript的this,call,apply。

中途參考的書籍也很多,以《JavaScript設計模式與開發實踐》為主,《JavaScript高級程式設計》、《你不知道的JavaScript》為輔。這三本書對我理解this,call,apply都起了很大的幫助。

首先,我們先講述this。

在《JavaScript設計模式與開發實踐》關於this的描述中,我認為有一句話切中了this的核心要點。那就是:

JavaScript的this總是指向一個物件
具體到實際應用中,this的指向又可以分為以下四種:

  1. 作為物件的方法呼叫

  2. 作為普通函數呼叫

  3. 構造器呼叫

  4. 構造器呼叫

構造器呼叫

構造器呼叫


/**
 * 1.作为对象的方法调用
 *
 * 作为对象方法调用时,this指向该对象。
 */

var obj = {
 a: 1,
 getA: function() {
  console.log(this === obj);
  console.log(this.a);
 }
};

obj.getA(); // true , 1
接下來我們去剖析前3點,至於第4點的apply和call調用,會在call和apply部分詳細講解。

1.作為物件的方法呼叫


說明:作為物件方法呼叫時,this指向該物件。

舉例:
/**
 * 2.作为普通函数调用
 *
 * 不作为对象属性调用时,this必须指向一个对象。那就是全局对象。
 */

window.name = 'globalName';

var getName = function() {
 console.log(this.name);
};

getName(); // 'globalName'

var myObject = {
 name: "ObjectName",
 getName: function() {
  console.log(this.name)
 }
};

myObject.getName(); // 'ObjectName'

// 这里实质上是把function() {console.log(this.name)}
// 这句话赋值给了theName。thisName在全局对象中调用,自然读取的是全局对象的name值
var theName = myObject.getName;

theName(); // 'globalName'

2.當普通函數呼叫


說明:當以普通函數呼叫時,this總是指向全域物件(瀏覽器中是window)。

舉例:
/**
 * 3.作为构造器调用
 * 
 * 作为构造器调用时,this指向返回的这个对象。
 */

var myClass = function() {
 this.name = "Lxxyx";
};

var obj = new myClass();

console.log(obj.name); // Lxxyx
console.log(obj) // myClass {name: "Lxxyx"}


3.構造器呼叫
var myClass = function() {
 this.name = "Lxxyx";
 // 加入return时,则返回的是别的对象。this不起作用。
 return {
  name:"ReturnOthers"
 }
};

var obj = new myClass();
console.log(obj.name); // ReturnOthers
說明:當構造器呼叫時,this指向返回的這個對象。

舉例:

但是如果構造函數中手動指定了return其它對象,那麼this將不起作用。

如果return的是別的資料類型,就沒有問題。


4.Call和Apply

Call和Apply的用途一樣。都是用來指定函數體內this的指向。


Call和Apply的區別

var name = "GlobalName"

var func = function() {
 console.log(this.name)
};

func(); // "GlobalName"

var obj = {
 name: "Lxxyx",
 getName: function() {
  console.log(this.name)
 }
};

obj.getName.apply(window) // "GlobalName" 将this指向window
func.apply(obj) // "Lxxyx" 将this指向obj
Call:第一個參數為this的指向,要傳給函數的參數得一個一個的輸入。
Apply:第一個參數為this的指向,第二個參數為數組,一次把所有參數傳入。

如果第一個參數為null,則this指向呼叫的本身。

1.改變this指向
(function(a, b) {
 console.log(arguments) // 1,2
 // 调用Array的原型方法
 Array.prototype.push.call(arguments, 3);
 console.log(arguments) // 1,2,3
})(1,2)
說明:這是call和apply最常使用的用途了。用於改變函數體內this的指向。
舉例:



2.借用其它物件的方法
function ArrayPush() {
 var n = TO_UINT32(this.length); // 被push对象的长度
 var m = % _ArgumentsLength(); // push的参数个数
 for (var i = 0; i < m; i++) {
  this[i + n] = % _Arguments(i); // 复制元素
 }
 this.length = n + m; //修正length属性
 return this.length;
}
這兒,我們先以一個立即執行匿名函數做開頭:

函數具有arguments屬性,而arguments是一個類別數組。 但是arguments是不能直接呼叫數組的方法的,所以我們要用call或apply來呼叫Array物件的原型方法。 原理也很容易理解,例如剛才呼叫的是push方法,而push方法在谷歌的v8引擎中,原始碼是這樣的:

它只與this有關,所以只要是類別數組對象,都可以呼叫相關方法去處理。

這部分內容比較複雜,再加上自己水平也不太夠。所以推薦有條件的同學去買相關書籍,或是等我的後續部落格文章。

感想
透過對這部分的學習,算是加深了對JavaScript的理解。最直覺的表現就是,去看一些優秀框架的原始碼時,不再是被this,call,apply,bind繞的暈乎乎的。還是很開心的~
下一段時間,準備深入探索日常學習和使用的CSS。畢竟JavaScript學了,HTML和CSS也不能落下。

【相關教學推薦】1. JavaScript影片教學2. JavaScript線上手冊3. bootstrap教學
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn