本觉得对 JS 中的 this 已经很熟练了,再看完冴羽的博客后,才发现本身对 ES 规范知之甚少,原来我都是根据经验在判断 this,这篇文章会从最底层的 ES 规范上去介绍 this 的判断。html
本文已同步到我的博客从 ES 规范 中理解 this,感谢鼓励。git
第一次作这道题时,只对了第一题。。github
var value = 1; var foo = { value: 2, bar: function() { return this.value; } }; //示例1 console.log(foo.bar()); //示例2 console.log((foo.bar)()); //示例3 console.log((foo.bar = foo.bar)()); //示例4 console.log((false || foo.bar)()); //示例5 console.log((foo.bar, foo.bar)());
先想想这道题的答案,而后解释一下缘由。算法
要完全弄明白上面的测试题,还得看规范文档 😂ide
常见的几种规范:函数
在 ECMAScript 规范中还有一种只存在于规范中的类型,它们的做用是用来描述语言底层行为逻辑。测试
规范 8.7 The Reference Specification Typethis
Reference 类型实例大体长这样:lua
var foo = { bar: function() { return this; } }; var fooReference = { base: EnvironmentRecord, name: 'foo', strict: false }; GetBase(fooReference); // EnvironmentRecord; var barReference = { base: 'foo', name: 'bar', strict: false }; GetBase(barReference); // foo;
GetBase(V)
. Returns the base value component of the reference V.HasPrimitiveBase(V)
. Returns true if the base value is a Boolean, String, or Number.IsPropertyReference(V)
. Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.规范 10.2.1.1.6 ImplicitThisValue()
undefined
.步骤1
将 ref 赋值为 MemberExpression(简单理解 MemberExpression 其实就是()左边的部分)步骤2
判断 ref 的类型
步骤3
若是 ref 是 Reference 类型
步骤4
若是 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)步骤5
若是 base value 值是 Environment Record, 那么 this 的值为 ImplicitThisValue(ref)步骤6
若是 ref 不是 Reference 类型,那么 this 的值为 undefined提示
非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。
一、使用属性读取
规范:获取 foo.bar
的返回类型。
二、交给函数调用规范,去解析 this。
Return a value of type Reference
whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.函数调用规范
步骤1
-> 步骤2
-> 步骤3
-> 步骤4
一、使用属性读取
规范:获取 foo.bar
的返回类型。
二、使用括号运算符
规范:获取 (foo.bar)
的返回类型。
三、交给函数调用规范,去解析 this。
查看规范 11.1.6 The Grouping Operator
This may be of type Reference
.函数调用规范
步骤1
-> 步骤2
-> 步骤3
-> 步骤4
一、使用赋值运算符
规范:获取 foo.bar = foo.bar
的返回类型。
二、使用括号运算符
规范:获取 (foo.bar = foo.bar)
的返回类型。
三、交给函数调用规范,去解析 this。
规范 11.13.1 Simple Assignment ( = )
GetValue(rref)
.函数调用规范
步骤1
-> 步骤2
-> 步骤6
一、使用逻辑与算法
规范:获取 false || foo.bar
的返回类型。
二、使用括号运算符
规范:获取 (false || foo.bar)
的返回类型。
三、交给函数调用规范,去解析 this。
规范 11.11 Binary Logical Operators
GetValue(rref)
.函数调用规范
步骤1
-> 步骤2
-> 步骤6
一、使用逗号操做符
规范:获取 foo.bar, foo.bar
的返回类型。
二、使用括号运算符
规范:获取 (foo.bar, foo.bar)
的返回类型。
三、交给函数调用规范,去解析 this。
GetValue(rref)
. 返回的是 GetValue 后的值,不是一个 Refernce。函数调用规范
步骤1
-> 步骤2
-> 步骤6
function foo() { console.log(this); } foo(); GetBase(fooReference); // EnvironmentRecord;
一、使用标识符解析
规范:获取 foo
的返回类型。
二、交给函数调用规范,去解析 this。
规范 10.3.1 Identifier Resolution
is always a value of type Reference
with its referenced name component equal to the Identifier String.函数调用规范
步骤1
-> 步骤2
-> 步骤3
-> 步骤5
遇到问题时,尽可能从原理的角度看待问题,不要凭经验办事情,不妨多研究研究底层规范。
tip 参考资料
JavaScript 深刻之从 ECMAScript 规范解读 this
ES5 规范文档