目录
- function基础
- apply(context,[arg1,arg2])
- 获取数组中最大的值
- 使用push合并数组
- 模拟
construct
构造器方法
- call(context,arg1,arg2)
- 类数组对象的数组方法操作
- uncurrying 反柯里化
- bind(context)
function基础
在ECMAScript中函数是对象,因此函数也有属性和方法。[1]
1.属性
- length
参数数量 - prototype
指向函数的所有实例方法,换句话说,诸如toString()
和valueOf()
(返回函数的代码) 都保存在prototype
名下
2.方法
每个函数都包含两个非继承而来(即不在prototype
名下)的方法apply()
和call()
apply(context,[arg1,arg2,...])
apply()
方法接收两个参数:一个是在其中运行的函数作用域,另一个可以是arguments
也可以是自定义Array
的实例。
经典案例
- 获取数组中最大的值
var arr = [1,2,3,4,9,8,7,5]
var result = Math.max.apply(null,a rr)
- 使用push合并数组
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
构造器方法
Function.prototype.construct = function(){
var oNew = Object.create(this.prototype);
this.apply(oNew, arguments);
return oNew;
}
call(context,arg1,arg2,arg3,...)
call()
与apply()
用法相同,只是除了第一个都是作用域之外,其余参数必须逐个列举出来,即 使用call()
方法时必须明确要传多少参数,同样也可以先创建函数之后再利用call
确定参数。
经典案例
- 对类数组对象进行一系列数组的方法操作
类数组对象{0:'asd',1:123,2:{},length:3}
,最经典的就是arguments
对象
[].shift.call(arguments) //删除arguments中的第一个参数并返回这个参数
//详情解释
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
调用父构造函数实现继承
function Parent(name, age){
this.name = name;
this.age = age;
}
function Son(name, age, weight){
Parent.call(name, age) //继承Parent函数的name和age属性
this.weight = weight //私有属性
}
var son = new Son('Niko', 24, 140)
console.log(son) // Son {name:'Niko', age:24, weight:140}
- 使用call
调用匿名函数
const arr = [0,1,2,3,4]
for(let i=0; i
- 修改上下文this
指向
var name = 'Niko'
function func(){ console.log(this.name) }
var obj = {
name : 'Bellic'
}
func.call(obj) // Bellic
func(); // Niko
- uncurrying
反柯里化 [2]
我们常常让类数组对象去借用Array.prototype的方法,这是call和apply最常用的应用场景之一:
(function(){
Array.prototype.push.call( arguments, 4 ); // arguments借用Array.prototype.push方法
console.log( arguments ); // [1, 2, 3, 4]
})(1, 2, 3)
在我们的预期中,Array.prototype上的方法原本只能用来操作array对象。但用call和apply可以把任意对象当作this传入某个方法,这样一来,方法中用到this的地方就不再局限于原来规定的对象,而是加以泛化并得到更广的适用性。
那么如何将泛化this过程提取出来呢?
uncurrying()函数实现
Function.prototype.uncurrying = function(){
var self = this;
return function(){
var obj = Array.prototype.shift.call( arguments );
return self.apply( obj, arguments )
}
}
bind(context)
bind()
方法会创建一个函数的实例,其this
值会被绑定传递给bind()
函数的值。
Function.prototype.bind = function(context){
var self = this; //保存原函数
return function(){ // 返回一个新函数
return self.apply( context, arguments )
}
}
总结
它们真正强大的地方是能够扩充函数赖以运行的作用域
参考
- [1]《JavaScript高级程序设计》(第3版) p.116 函数属性和方法
- [2] 《JavaScript设计模式与开发实践》 p.51 高阶函数
- 上述部分案例参考自https://developer.mozilla.org/