call、apply、bind 相同点
都可以用来改变 this 对象的指向,第一个参数都是 this 要指向的对象,也就是想指定的上下文,三者都可以利用后续参数传参。
call、apply、bind 不同点
apply 和 call 传参方式不同,apply 第二个参数是数组,call 则是 arg1,arg2...这种形式。
bind 是改变 this 作用域会返回一个新的函数,这个函数不会马上执行。参数可以拼接。
function fn () {
console.log(arguments) // [1, 2, 3, 4]
}
var obj = {}
// call 使用
fn.call(obj, 1, 2, 3, 4)
// apply 使用
fn.apply(obj, [1, 2, 3, 4])
// bind 使用
var newFn = fn.bind(obj, 1, 2)
newFn(3, 4)
实现 call 方法
思路
- 将函数设为对象的属性
- 执行 & 删除这个函数
- 指定 this 到函数,并传入给定参数执行函数
- 如果不传入参数,默认指向 window
Function.prototype.myCall = function (context) {
var context = context || window;
context.fn = this;
var args = [];
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i])
}
}
var result = context.fn(...args)
delete context.fn;
return result
}
实现 apply 方法
Function.prototype.myApply = function(context, arr) {
var context = context || window;
context.fn = this;
if (!arr.length) {
return context.fn();
} else {
var result = context.fn(...arr);
delete context.fn;
return result;
}
}
实现 bind 方法
思路
- 返回一个函数,并绑定this,传递预设的参数
- bind 返回的函数可以作为构造函数使用。故作为构造函数时应使得 this 失效,但是传入的参数依然有效
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw Error('this is not a function')
}
var context = context || window;
var Fn = function () {}
var _this = this;
var args = Array.prototype.slice.call(arguments, 1);
var result = function () {
return _this.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
)
}
if (this.prototype) Fn.prototype = this.prototype
result.prototype = new Fn()
return result;
}