JS基础类型的包装问题
请问以下各个log输出什么?为什么会这样输出?
function test() {
console.log(this);
console.log(arguments);
}
const obj = {
fn: test
}
test(1, 2, 3);
obj.fn(1, 2, 3);
test.call(obj, 1, 2, 3);
obj.fn.call(1, 2, 3);
this
关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象.参考链接
arguments
关键字是函数内部的参数对象,生成函数作用域自动拥有的变量. 参考链接
call
可以显式绑定this的指向.参考链接
1. test(1, 2, 3)
在全局作用域中直接调用函数,相当于 window.test()
,参数对象则就是为当前传入的参数对象
因此:
test(1, 2, 3);
// this => window
// arguments => Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
2. obj.fn(1, 2, 3)
this
总是指向调用他的对象,因此obj.fn()
的this
为obj
; 参数对象arguments
则为传入的参数对象
因此:
obj.fn(1, 2, 3);
// this => obj
// arguments => Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
3. test.call(obj, 1, 2, 3)
call
可以显式更改this
的指向, 具体流程可入下列代码
test.call(obj, 1, 2, 3)
=> obj[Symbol] = test
=> obj[Symbol](1, 2, 3)
=> delete obj[Symbol]
因此:
test.call(obj, 1, 2, 3)
// this => obj
// arguments => Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
4. obj.fn.call(1, 2, 3)
当看到call
方法后面的上下文对象this
位置放得是 1
, 是一个数值,是不是有点懵,特别是面试的时候;
千万别慌我们冷静分析:
-
obj.fn.call(1, 2, 3)就是一个函数,然后调用了 call方法
obj.fn.call(1, 2, 3) => test.call(1, 2, 3)
-
按call的实现思路
test.call(1, 2, 3) => (1)[Symbol] = test => (1)[Symbol](1, 2, 3) => delete (1)[Symbol]
疑惑: 可是
1
是一个数值啊,怎么可能有方法呢?
冷知识
JS的包装类型: 原始数据类型,在调用属性和方法时,js会在后台隐式的将基本类型转换成对象
// 场景: 保留1位小数
3.1415926.toFixed(1)
很明显,当使用一个数值的时候,我们直接在后面去取对应的属性会自动给我们提示API;我们在使用数值的时候可能会潜意识使用它的API,但是却没有知其所以然,在看到obj.fn.call(1, 2, 3)
这个例子的时候自然会吃瘪。
该方法通常是由 JavaScript 引擎在内部隐式调用的,而不是由用户在代码中显式调用的。
因此放在 this
参数位置的1
其实是一个Number类型的对象,所以很容易得出结果
obj.fn.call(1, 2, 3) => test.call(1, 2, 3)
test.call(1, 2, 3)
=> (1)[Symbol] = test
=> (1)[Symbol](2, 3)
=> delete (1)[Symbol]
obj.fn.call(1, 2, 3)
// Number{1}
// arguments => Arguments(2) [2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
总结
通过这个例子,我们即能掌握 this
的指向问题,arguments
是什么,call
的基本使用以及JS的包装类型;学到了给我点个赞吧,嘻嘻嘻!