apply 和 call 的相同点是:
- 都由一个函数调用
- 第一个参数都是原函数的执行环境 this
不同点是:
apply 的第二个参数接收原函数的所有参数,而 call 从第二个参数开始跟原函数一样是打散的
代码如下:
1 | F(arg1, arg2, ...){} |
需要特别注意的是,如果是在非严格模式下,thisArg 如果为 null 或 undefined,就会被替换成全局对象(在浏览器中是 window);如果为原始值,就会被替换成原始值的的自动包装对象。
严格模式下,thisArg 传什么就是什么。
1 | function getGlobalObject() { |
以上代码涉及到了挺多知识点的:
- 防御式编程,对参数进行校验:this, thisArg, argsArray
- 细心,为了防止改到 fn,做了暂存
- ES3 开始,非严格模式下,thisArg 的特殊处理
- 如果不让用 ES6 的扩展运算符
...
,就要利用new Function()
自己构造新的函数调用语句。apply 是 es5 的,所以不让用 es6 的语法很正常。 - 在 ES3、ES5 中 undefined 是能修改的
借助以上结果,模拟实现 call 方法的话,如下:
1 | Function.prototype.callFn = function call(thisArg) { |
测试用例:
1 | const a = { |
在 ES3、ES5 中 undefined 是能修改的
可能大部分人不知道。ES5 中虽然在全局作用域下不能修改,但在局部作用域中也是能修改的,不信可以复制以下测试代码在控制台执行下。虽然一般情况下是不会的去修改它。
1 | function test() { |
所以判断一个变量 a 是不是 undefined,更严谨的方案是 typeof a === 'undefined'
或者 a === void 0;
这里面用的是 void,void 的作用是计算表达式,始终返回 undefined,也可以这样写 void(0)。