call,apply,bind的区别?
- 这三个方法都是用来改变函数执行时的上下文,也就是改变函数执行时的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]
- 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指向,同时把函数执行结果返回
}
}