call,apply,bind有什么区别?手写一个bind,call实现

115 阅读2分钟

call,apply,bind的区别?

  1. 这三个方法都是用来改变函数执行时的上下文,也就是改变函数执行时的this指向;
let obj = {
    name: 'mike',
    age: 18
};

function fn1(x, y) {
    console.log(this)
    return X + y
};

fn1() //严格模式下this指向undefined; 非严格模式下this指向window;

fn1.call(obj, 10, 20) //this指向obj

fn1.bind(null, 10, 20) //严格模式下this指向null, 非严格模式下this指向window

fn1.bind(undefined, 10, 20) //严格模式下this指向undefined, 非严格模式下this指向window

fn1.bind('str', 10, 20) //严格模式下this指向字符串类型的‘str’, 非严格模式下this指向object类型的String {'str'}

2.call和apply的区别主要是call方法接受一个参数列表,而apply方法第二个参数只接受一个数组;

const arr1 = ['a', 'b', 'c']
const arr2 = [1, 2, 3]
arr1.push.apply(arr1, arr2) //['a', 'b', 'c', 1, 2, 3]
  1. call,apply会立即执行,返回函数执行的结果;bind返回一个函数;
//html
//<button id="submit">点击</button>

function fn3(x, y) {
    console.log(this)
    return x + y
}

const btn = document.getElementById('submit');

btn.onclick = fn3.bind(obj, 10, 20) //this指向obj

实现call方法

function _call(context, ...params) {

    //执行方法之前先做一些约束条件
    
    //context不传或则为null, undefined的情况
    if (context == null) { //null == nul -->true;
       context = window    //null == undefined --> true
    }
    
    //context为原始数据类型时的情况
    if (!/^(function|object)$/.test(typeof context)) {
        context = Object(context)
    }

    const self = this //_call方法执行时,谁调用_call,this指向谁, 此时this指向调用call方法的函数
    
    const key = Symbol('key') //创建一个唯一值
    
    context[key] = self //给context加一个属性值key,值是执行call的方法
    
    const result = context[key](...params) //把context对象的key执行,那么该函数中的this指向context
    
    Reflect.deleteProperty(context, key) //删除context的key属性
    
    return result //返回函数执行的结果
}

实现bind方法

function _bind(context, ...params) {

    const self = this //此时this指向调用bind方法的函数
    
    return function proxy(...args) { //_bind函数执行,返回一个proxy函数
        
        //proxy执行时,谁调用当前peoxy,this指向谁
        return self.call(context, ...params.concat(...arg)) //proxy执行时改变this指向,同时把函数执行结果返回
    }
    
}