JavaScript深入之从ECMAScript规范解读this
(深入js系列读后感> github.com/mqyqingfeng…)
Types
ECMAScript 有两种类型,语言类型和规范类型
语言类型 就是常说的数据类型,比如 Undefined、Null、String 等等
规范类型 是用来用算法描述 ECMAScript 语言结构和 ECMAScript 语言类型的。规范类型包括:Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。
总结:这些都不重要,只需要知道 ECMAScript 还有一种只存在与规范中的类型,用来描述语言底层行为逻辑
Reference
Reference 是规范类型的一种,用来解释语言的底层行为逻辑才存在的,比如 delete、typeof 以及复制等操作行为。
(上面这句话有点难以理解,只需要知道有这么回事就行,记住 Reference 是规范类型的一种)
Reference 的构成:
- base value (base):属性所在的对象或者 EnvironmentRecord,它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的一种。
- referenced name (name): 属性名
- strict reference (strict): 是否是严格模式
举个例子:
var foo = 1
// 对应的 Reference :
var fooReference = {
base: EnviromentRecord,
name: 'foo',
strict: false
}
再举个例子
var foo = {
bar: function () {
return this
}
}
foo.bar()
// bar 对应的 Reference :
var BarReference = {
base: foo,
name: 'bar',
strict: false
}
介绍几个和 Reference 相关的方法:GetBase、IsPropertyReference、GetValue
-
GetBase: 获取 Reference 中 base 的值
-
IsPropertyReference: 判断 Reference 中 base 是否为对象,是 返回 true, 否 返回 false
-
GetValue: 返回的将是属性具体的值,而不是一个 Reference ,这个很关键
简单模拟 GetValue 的使用
var foo = 1 // 对应的 Reference : var fooReference = { base: EnviromentRecord, name: 'foo', strict: false } GetValue(fooReference) // 1
重点记忆一下这三个方法,后面判断 this 时,会用到!!!
确定 this 的值
ES5 的规范中讲了当函数调用当时候,如何确定 this 的值。主要看1、6、7点。
主要意思:
- 计算 MemberExpression 的结果赋值给
ref
什么是 MemberExpression ?举个例子:
function foo() {
console.log(this)
}
foo() // MemberExpression 是 foo
function foo() {
return function() {
console.log(this)
}
}
foo()() // MemberExpression 是 foo()
var foo = {
bar: function () {
return this;
}
}
foo.bar(); // MemberExpression 是 foo.bar
简单来说,函数调用的时候,()
左边的部分就是 MemberExpression 的值
-
根据 ES5 规范,判断
ref
是不是一个 Reference 类型 -
如果 ref 是 Reference,并且
IsPropertyReference(ref)
(判断 Reference 中 base 是否为对象,上面有解释) 是 true,那么 this 的值为GetBase(ref)
(获取 Reference 中 base 的值,上面有解释) -
如果 ref 是 Reference,并且
GetBase(ref)
是EnvironmentRecord
,那么 this 的值为ImplicitThisValue(ref)
(查看规范 10.2.1.2.6,ImplicitThisValue 方法的介绍:该函数始终返回 undefined) -
如果 ref 不是 Reference,那么 this 的值为 undefined
小试牛刀
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
function foo1() {
console.log(this)
}
// 示例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)())
// 示例6
foo1()
-
示例1
-
ref = foo.bar
-
判断 ref 是否为 Reference,根据 ES5 规范 11.2.1
(Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.)
判断,当以.
的方式访问属性时,返回 Reference。结论 ref 是 Reference 类型var Reference = { base: foo, name: 'bar', strict: false }
-
this 的值为
GetBase(ref)
就是foo
-
-
示例2
- ref = (foo.bar)
- 根据 ES5 规范 11.1.6
(Return the result of evaluating Expression. This may be of type Reference.)
判断,() 并没有对 ref 进行计算,所以和 示例1 的结果一致
-
示例3
- ref = (foo.bar = foo.bar)
- 根据 ES5 规范 11.13.1 判断,等号操作返回值为
GetValue('等号右边属性')
,根据上面 GetValue 介绍,调用 GetValue 返回的将是属性具体的值,而不是 Reference - 按照判断 this 的逻辑,ref 不是 Reference ,那么 this 的值为 undefined,在非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象
-
示例4
- ref = (foo.bar || foo.bar)
- 根据ES5规范 11.11 判断,二元逻辑操作返回值会调用 GetValue,所以和 示例三 一致
-
示例5
- ref = (foo.bar, foo.bar)
- 根据ES5规范 11.14 判断,逗号操作返回值会调用 GetValue,所以和 示例三 一致
-
示例6
-
ref = foo1
-
根据ES5规范 10.3.1 判断,标识符的引用,返回一个 Reference 类型的值
var foo1Reference = { base: EnvironmentRecord, name: 'foo', strict: false }
-
按照判断 this 的逻辑,ref 是 Reference,判断 IsPropertyReference(ref) 是 true 还是 false,根据 IsPropertyReference 的描述 (判断 Reference 中 base 是否为对象),这里的 base 为 EnvironmentRecord,不是 Object 类型
-
因为 IsPropertyReference(ref) 为 false,再判断 GetBase(ref) 的值,正是
environment record
,所以 this 的值为 ImplicitThisValue(ref),根据上面介绍,该函数返回 undefined
-
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!