1. call和apply
call
和 apply
的功能相同,都是改变 this
的指向,并立即执行函数。区别在于传参方式不同。(thisArg, arg1, arg2, ...)
:第一个参数是 this
指向的对象,其它参数依次传入。(thisArg, [argsArray])
:第一个参数是 this
指向的对象,第二个参数是数组或类数组。
2. call的实现原理
- 思考过程
我们知道,函数都可以调用 call
,说明 call
是函数原型上的方法,所有的实例都可以调用。即: ;
其次,如果第一个参数没有传入,在全局环境下,那么默认this
指向 window(浏览器) / global(node)
(非严格模式);
传入 call
的第一个参数是 this
指向的对象,根据隐式绑定的规则,我们知道 ()
,foo()
中的 this
指向 obj
,因此我们可以这样调用函数 (...args)
,所以相应的func
中的this
就指向了thisArgs
,然后返回执行结果。
- 原理实现
.ca_ll = function() {
// 剩余运算符,得到的是一个数组,包含除了this值的其他参数
let [thisArgs, ...args] = arguments;
if(!thisArgs) {
thisArgs = typeof window === 'undefined' ? global : window;
}
= this;
let result = (...args);
delete ; // thisArgs上并没有func属性,所以执行结果之后需要移除
return result;
}
// 测试用例
var foo = {
name: 'zl'
}
function func(job, age) {
();
(job, age);
}
func.ca_ll(foo, 'coder', 45); //zl coder 45
3. apply的实现原理
- 思考过程
apply
的实现过程和call
的实现过程类似,只是对于参数的处理有些不同。
- 原理实现
.app_ly = function() {
let [thisArgs, args] = arguments;
let result; // 函数返回结果
if(!thisArgs) {
thisArgs = typeof window === 'undefined' ? global : window;
}
= this;
if(!args) {
// 第二个参数为null或者是undefined
result = ();
} else {
result = (...args);
}
delete ;
return result;
}
// 测试用例
let foo = {
name: 'zl'
}
function func(job, age) {
();
(job, age);
}
func.app_ly(foo, ['coder', 45]); //zl coder 45
4. bind的实现原理
bind
和 call
/apply
有一个很重要的区别,一个函数被 call
/apply
的时候,会直接调用,但是 bind
会创建一个新函数。当这个新函数被调用时,bind()
的第一个参数将作为它运行时的 this
,之后的一序列参数将会在传递的实参前传入作为它的参数。
bind
的实现见柯里化一篇/zl13015214442/article/details/89424840