Appearance
call、apply和bind的联系和区别
js
众所周知:
call,apply,bind函数的作用是改变this指向问题。但是具体三者的区别在于哪呢?
call,apply,bind函数挂载在Function.prototype。
apply用来改变this指向,然后传递参数的时候是以数组的形式进行传递;apply把传参方式,改由数组的方式传参,接受的时候是单个参数;
1. 首先传参的问题上:
fn.call(this, arg1, arg2, arg3);
fn.apply(this, [arg1, arg2, arg3]);
fn.bind(this, arg1, arg2, arg3);
我们可以发现,call和apply除了在传参形式不同,没有什么区别。而call,apply和bind到底有什么区别呢?
2. 返回值的问题上:
fn.call(this, arg1, arg2, arg3);
fn.apply(this, [arg1, arg2, arg3]);
fn.bind(this, arg1, arg2, arg3)();
fn.bind(this, arg1, arg2, arg3);bind方法改变完this指向后,并不能直接调用函数,而是返回一个改变this指向后全新的函数。
fn.bind(this, arg1, arg2, arg3)(); ---> var fn2 = fn.bind(this, arg1, arg2, arg3);
fn2();
而call和apply在改变this指向后,会直接调用执行函数。
重写bind
- 首先要满足bind函数不立即执行。
- 其次要满足bind(this, 'zhansan')(), bind(this, 'zhansan')('male')传参方式。
- 最后要处理new Fn()绑定失效的问题。
js
Function.prototype.myBind = function (/* thisArg, thisArgList */) {
// 保存当前this指向,也就是谁调用的myBind函数
var context = this,
// 处理参数thisArg
thisArg = arguments[0] == undefined ? window : arguments[0],
// 处理参数问题
outSideArgList = Array.prototype.slice.call(arguments, 1)
var internalFn = function () {
var internalArgList = Array.prototype.slice.call(arguments),
argsCollect = outSideArgList.concat(internalArgList),
// 保存this指向
_self = this
context.apply(_self instanceof context ? _self : thisArg, argsCollect)
}
// 圣杯继承
var inherit = (function () {
var Buffer = function () {}
return function (Origin, Target) {
Buffer.prototype = Origin.prototype
Target.prototype = new Buffer()
Target.prototype.constructor = Target
Target.prototype.super_class = Origin
}
})()
inherit(context, internalFn)
return internalFn
}
// 测试
var fn = Person.myBind(obj, '张三', 'male')
new fn()