目錄
- function基礎(chǔ)
- apply(context,[arg1,arg2])
- 獲取數(shù)組中最大的值
- 使用push合并數(shù)組
- 模擬
construct構(gòu)造器方法
- call(context,arg1,arg2)
- 類數(shù)組對象的數(shù)組方法操作
- uncurrying 反柯里化
- bind(context)
function基礎(chǔ)
在ECMAScript中函數(shù)是對象,因此函數(shù)也有屬性和方法。[1]
1.屬性
-
length
參數(shù)數(shù)量 -
prototype
指向函數(shù)的所有實(shí)例方法,換句話說,諸如toString()和valueOf()(返回函數(shù)的代碼) 都保存在prototype名下
2.方法
每個函數(shù)都包含兩個非繼承而來(即不在prototype名下)的方法apply()和call()
apply(context,[arg1,arg2,...])
apply()方法接收兩個參數(shù):一個是在其中運(yùn)行的函數(shù)作用域,另一個可以是arguments也可以是自定義Array的實(shí)例。
經(jīng)典案例
- 獲取數(shù)組中最大的值
var arr = [1,2,3,4,9,8,7,5]
var result = Math.max.apply(null,a rr)
- 使用push合并數(shù)組
var arr1 = [1,2,3]
var arr2 = [4,5,6]
Array.prototype.push.apply(arr2,arr1);
console.log(arr2) //[4,5,6,1,2,3]
- 模擬construct構(gòu)造器方法
Function.prototype.construct = function(){
var oNew = Object.create(this.prototype);
this.apply(oNew, arguments);
return oNew;
}
call(context,arg1,arg2,arg3,...)
call()與apply()用法相同,只是除了第一個都是作用域之外,其余參數(shù)必須逐個列舉出來,即 使用call()方法時必須明確要傳多少參數(shù),同樣也可以先創(chuàng)建函數(shù)之后再利用call確定參數(shù)。
經(jīng)典案例
- 對類數(shù)組對象進(jìn)行一系列數(shù)組的方法操作
類數(shù)組對象{0:'asd',1:123,2:{},length:3},最經(jīng)典的就是arguments對象
[].shift.call(arguments) //刪除arguments中的第一個參數(shù)并返回這個參數(shù)
//詳情解釋
var a = {0:1,1:2,2:3,length:3};
console.log([].shift.call(a)) // 1
console.log( a ) // {0: 2, 1: 3, length: 2}
- 使用call調(diào)用父構(gòu)造函數(shù)實(shí)現(xiàn)繼承
function Parent(name, age){
this.name = name;
this.age = age;
}
function Son(name, age, weight){
Parent.call(name, age) //繼承Parent函數(shù)的name和age屬性
this.weight = weight //私有屬性
}
var son = new Son('Niko', 24, 140)
console.log(son) // Son {name:'Niko', age:24, weight:140}
- 使用call調(diào)用匿名函數(shù)
const arr = [0,1,2,3,4]
for(let i=0; i<arr.length; i++){
(function(i){
//...
console.log(i) // 0,1,2,3,4
}).call(arr, i)
}
- ??修改上下文this指向
var name = 'Niko'
function func(){ console.log(this.name) }
var obj = {
name : 'Bellic'
}
func.call(obj) // Bellic
func(); // Niko
- uncurrying反柯里化 [2]
我們常常讓類數(shù)組對象去借用Array.prototype的方法,這是call和apply最常用的應(yīng)用場景之一:
(function(){
Array.prototype.push.call( arguments, 4 ); // arguments借用Array.prototype.push方法
console.log( arguments ); // [1, 2, 3, 4]
})(1, 2, 3)
在我們的預(yù)期中,Array.prototype上的方法原本只能用來操作array對象。但用call和apply可以把任意對象當(dāng)作this傳入某個方法,這樣一來,方法中用到this的地方就不再局限于原來規(guī)定的對象,而是加以泛化并得到更廣的適用性。
那么如何將泛化this過程提取出來呢?
uncurrying()函數(shù)實(shí)現(xiàn)
Function.prototype.uncurrying = function(){
var self = this;
return function(){
var obj = Array.prototype.shift.call( arguments );
return self.apply( obj, arguments )
}
}
bind(context)
bind()方法會創(chuàng)建一個函數(shù)的實(shí)例,其this值會被綁定傳遞給bind()函數(shù)的值。
Function.prototype.bind = function(context){
var self = this; //保存原函數(shù)
return function(){ // 返回一個新函數(shù)
return self.apply( context, arguments )
}
}
總結(jié)
它們真正強(qiáng)大的地方是能夠擴(kuò)充函數(shù)賴以運(yùn)行的作用域
參考
- [1]《JavaScript高級程序設(shè)計(jì)》(第3版) p.116 函數(shù)屬性和方法
- [2] 《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 p.51 高階函數(shù)
- 上述部分案例參考自https://developer.mozilla.org/