前言: 由於js 中this的指向受函數運行環境的影響,指向經常改變,使得開發變得困難和模糊,所以在封裝sdk,寫一些複雜函數的時候經常會用到this 指向綁定,以避免出現不必要的問題,call、apply、bind基本都能實現這一功能,現對這三種方法使用總結一下: 1、function.proto ...
前言:
由於js 中this的指向受函數運行環境的影響,指向經常改變,使得開發變得困難和模糊,所以在封裝sdk,寫一些複雜函數的時候經常會用到this 指向綁定,以避免出現不必要的問題,call、apply、bind基本都能實現這一功能,現對這三種方法使用總結一下:
1、function.prototype.call()
call 方法可以指定this 的指向(即函數執行時所在的的作用域),然後再指定的作用域中,執行函數
call 方法的參數,應該是對象obj,如果參數為空或null,undefind,則預設傳參全局對象
var obj = {}; var f = function(){ return this; }; console.log(f() === window); // this 指向window console.log(f.call(obj) === obj) //改變this 指向 obj
如果call 傳參不是以上類型,則轉化成對應的包裝對象,然後傳入方法。例如,5 轉成number 實例,綁定f 內部 this
var f = function () { return this; }; f.call(5) // Number {[[PrimitiveValue]]: 5}
call 可以接受多個參數,第一個參數是this 指向的對象,之後的是函數回調所需的入參
function add(a, b) { return a + b; } add.call(this, 1, 2) // 3
call
方法的一個應用是調用對象的原生方法。
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆蓋掉繼承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
上面代碼中hasOwnProperty 是 obj 繼承來的方法,用來判斷對象是否包含自身特點(非繼承)屬性,但是hasOwnProperty 並不是保留字,如果被對象覆蓋,會造成結果錯誤。
call
方法可以解決這個問題,它將hasOwnProperty
方法的原始定義放到obj
對象上執行,這樣無論obj
上有沒有同名方法,都不會影響結果。
hasOwnProperty 相關應用:https://www.cnblogs.com/weiqinl/p/8683207.html
2、Function.prototype.apply()
apply 和call 作用類似,也是改變this 指向,然後調用該函數,唯一區別是apply 接收數組作為函數執行時的參數
func.apply(thisValue, [arg1, arg2, ...])
apply
方法的第一個參數也是this
所要指向的那個對象,如果設為null
或undefined
,則等同於指定全局對象。
第二個參數則是一個數組,該數組的所有成員依次作為參數,傳入原函數。
原函數的參數,在call
方法中必須一個個添加,但是在apply
方法中,必須以數組形式添加。
function f(x, y){ console.log(x + y); } f.call(null, 1, 1) // 2 f.apply(null, [1, 1]) // 2
利用這一特性,可以實現很多小功能
比如,輸出數組的最大值
var a = [24,30,2,33,1] Math.max.apply(null,a) //33
將數組中的空值,轉化成undefined,主要應用在數組遍歷中,因為數組foreach 遍歷會跳過空值,而不會跳過undefined
var a = ['a',,'b']; Array.apply(null,a) //['a',undefind,'b']
將類似於數組的對象轉化成數組
另外,利用數組對象的slice
方法,可以將一個類似數組的對象(比如arguments
對象)轉為真正的數組。
Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
上面代碼的apply
方法的參數都是對象,但是返回結果都是數組,這就起到了將對象轉成數組的目的。
從上面代碼可以看到,這個方法起作用的前提是,被處理的對象必須有length
屬性,以及相對應的數字鍵。
3.Function.prototype.bind()
bind 用於將函數體內的this綁定到某個對象,然後返回一個新函數
var d = new Date(); d.getTime() // 1481869925657 var print = d.getTime; print() // Uncaught TypeError: this is not a Date object.
報錯是因為,d.getTime 賦值給 print 後,getTime 內部的this 指向方式變化,已經不再指向date 對象實例了
解決方法
var print = d.getTime.bind(d); print() // 1481869925657
bind 接收的參數就是所要綁定的對象
ar counter = { count: 0, inc: function () { this.count++; } }; var func = counter.inc.bind(counter); func(); counter.count // 1
綁定到其他對象
var counter = { count: 0, inc: function () { this.count++; } }; var obj = { count: 100 }; var func = counter.inc.bind(obj); func(); obj.count // 101
bind 還可以接收更多的參數,將這些參數綁定到原函數的參數
var add = function (x, y) { return x * this.m + y * this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5); newAdd(5) // 20
上面代碼中,bind
方法除了綁定this
對象,還將add
函數的第一個參數x
綁定成5
,然後返回一個新函數newAdd
,這個函數只要再接受一個參數y
就能運行了。
總結:
1. call 、 apply 、bind 均能改變this 指向
2. apply 每次執行產生一個新函數,call、apply 不會
3. call ,bind 接收多個參數綁定到函數,參數單一傳入,apply 接收方式為數組
更多詳細資料:
http://javascript.ruanyifeng.com/oop/this.html#toc7