apply , call , bind
我们先来明确一下this。this 是指当前代码的运行环境。 如果一段代码是直接运行在浏览器的,比如说在浏览器的控制台。this就是当前的浏览器window,如果是在node 中,this就指向global。如果是在一个对象 a,那么对象中的一个方法打印this 的时候,this就是这个对象a。其实window 就是一个对象。那我们就可以记住,this 就是指向对象。
1. call , apply, bind 都是为了改变某个函数运行时的上下文(context)而存在的
换句话说,就是为了改变函数体内部 this 的指向。要知道只有方法才能调用call,apply,bind。
bala.. ,bala 一大堆。
但是也可以这样想,这三个就是正常的js 方法。的确,本来也就是正常的js 方法,只不过我们用的少。不熟悉。 那接着来看下面很常用的一个方式
Math.max(9,1,2,3)
Math.max.call(null,9,1,2,3);
Math.max.apply(null,[9,1,2,3]);
Math.max.bind(null,9,1)(2,3)
抛开刚才所有的解释,忘记刚才所有的话,call 和applay 的用法就是。
fn.call(obj,1,2,3,4);
fn.apply(obj,[1,2,3,4]);
// 其实就像这样
obj.fn(1,2,3,4)
解释就是
call和apply 让obj 这个对象能调用fn 这么一个方法。告诉浏览器,这个对象下
有fn 的这个方法,obj 可以调用fn
这就是call 和apply 的作用,不要去想改变了this 的指向。改变this指向是它们的实现方法。call 方法的第二个位置参数就是很多数字,apply 第二个位置参数就是一个数组。
bind 的用法和call 一样,第一个参数都是传一个obj,第二个位置参数是很多数字。只不过它的返回值是一个方法。
位置参数就是给fn 的参数,只不过apply 接受参数,是接受一个数组 需要注意的是:apply 的第二个数组参数,整个数组里面的元素是fn 的参数。,call 和bind 是接受散装参数。
2.怎么手写一个类似的call ,或者apply 呢?
call ,apply,bind 都是只有方法才能调用所以我们在 方法的原型上直接定义
Function.prototype._call=function($this,...args){
// 在call 方法中,这个时候的this,就是指向 调用call 的那个方法
$this.fn = this;
reurn $this.fn(...args);
}
这个是最简单的call 方法我们需要完善它
Function.prototype._call=function($this,...args){
// 这一步,如果$this = null ,则可以这样直接挂载到window 上
$this=$this||window||global;
// 定义一个唯一变量 symbol,这样可以防止我们要调用的方法和自定义的方法重命名
const fn = Symbol('fn');
// 将要调用的方法挂载到我们的实例上
$this[fn] = this;
// 获取结果
const result = $this[fn](...args);
// 删除,防止重命名和污染变量
delete $this[fn];
return result;
}
同样的手写 apply
Function.prototype._apply=function($this,args){
$this=$this||window||global;
let fn = Symbol('fn');
$this[fn] = this;
const result = $this[fn](...args);
delete $this[fn];
return result;
}
同样的手写 bind
知道bind 与call 的区别就是bind 返回了一个方法,所以。。。
Function.prototype._bind = function ($this, ...args) {
var fn = this;
$this = $this || global || window;
var res = function () {
return fn.apply(this instanceof fn ? this : $this, args.concat(Array.prototype.slice.call(arguments)));
}
if (fn.prototype) {
res.prototype = Object.create(fn.prototype);
}
return res;
}