雨中莫听哀曲,悲歌莫过童声。
规范抽象类型
Reference类型——只存在于规范里一种抽象类型,描述语言底层的行为逻辑,存在于规范类型中,不存在于语言类型中,不存在于实际的js代码中。
Reference的三个组成部分
-
base value
(属性所存在的对象或者EnviromentRecord)(值:Undefined\Object\Boolean\String\Number\EnviromentRecord) -
referenced name (属性的名称)
-
strict refernce (严格标志)
例如:
var foo = 1;
//对应的Reference类型
var fooRefrence = {
base:EviromentRecord,
name:'foo',
strict:false
};
var foo = {
bar:function(){
return this;
}
}
foo.bar();
//对应的Reference类型
var BarReference = {
base:foo,
name:'bar',
strict:false
}
获取规范抽象类型
1、GetBase–返回Reference的base value
2、IsPropertyRefernce,判断base value的类型,如果base value是一个对象返回true,
GetValue 返回对象属性真正的值,调用了GetValue将返回一个具体的值,执行过GetValue,依据执行结果是否为Object就会返回Reference类型,若不是,不返回Reference类型
函数调用时如何确定this的取值
1、计算属性访问表达式MemberExpression的结果,赋给ref
MemberExpression 分5种:
PrimaryExpression // 原始表达式
FunctionExpression // 函数定义表达式
MemberExpression [ Expression ] // 属性访问表达式
MemberExpression.IdentifierName // 属性访问表达式
new MemberExpression Arguments // 对象创建表达式
例子1:
function foo(){
console.log(this);
}
foo(); //MemberExpression是foo()
例子2:
function foo(){
return function(){
console.log(this);
}
}
foo()(); //MemberExpression是foo()
例子3:
var foo = {
bar:function(){
return this;
}
}
foo.bar(); //MemberExpression是foo.bar
//简单理解 MemberExpression 其实就是()左边的部分。
2、判断ref是否是一个Reference类型
2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true(即Reference是Object), 那么 thisValue 的值为 GetBase(ref),也就是Reference中的base value
2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么thisValue的值为 ImplicitThisValue(ref),它的返回结果,而ImplicitThisValue函数始终返回undefined
2.3 如果 ref 不是 Reference,那么 this 的值为 undefined
//解析
var value = 1;
var foo = {
value : 2,
bar : function(){
console.log(this.value);
}
}
console.log(foo.bar());
console.log((foo.bar)());
console.log((foo.bar = foo.bar)());
console.log((false || foo.bar)());
console.log((foo.bar,foo.bar)());
分析
//第一条:
/*
* 1.获取对应的Reference,即:
var Reference = {
base:foo,
name:'bar',
strict:false
};
* 2.--2.1 获取MemberExpression的结果,即foo.bar,赋给ref
baseValue 等于 GetValue(baseReference) 。
--2.2 通过IsPropertyReference检查ref的类型,IsPropertyReference判断base value,base value是对象,返回true,因此thisValue的值为GetBaseValue(ref),即base value的值,所以this为foo,那么访问的value就是2
*/
//第二条
/*
* 1.获取对应的Reference,即:
var Reference = {
base:foo,
name:'bar',
strict:false
};
* 2.获取的MemberExpression也为foo.bar,()并没有对MemExpression进行计算,所以,后续的分析均与第一条相同,结果也相同
*/
//第三条
/*
* 1.获取对应的Reference,即:
var Reference = {
base:foo,
name:'bar',
strict:false
};
* 2.获取的MemberExpression为(foo.bar == foo.bar),存在赋值操作,调用GetValue方法,调用了GetValue方法后返回[Object Function]类型,不是Reference类型,
那么thisValue将为undefined,默认指向window
注意:简单赋值语句返回的是对等于号右边进行GetValue之后的结果,GetValue会返回js的类型,此处会返回 foo.bar的类型也就是一个 [Object Function] 类型,即不是一个Reference类型,所以this就为undefined,
规范中 if thisArg is null or undefined, set the ThisBinding to the global object.
所以this指向window
*/
//第四条
/*
* 1.获取对应的Reference,即:
var Reference = {
base:foo,
name:'bar',
strict:false
};
* 2.获取的MemberExpression为(flase || foo.bar),逻辑运算,同样调用GetValue方法,结果与第三条一致
*/
//第五条
/*
* 1.获取对应的Reference,即:
var Reference = {
base:foo,
name:'bar',
strict:false
};
* 2.获取的MemberExpression为(foo.bar , foo.bar),逗号操作符,同样调用GetValue方法,结果与第三条一致
*/
普通函数调用
function foo(){
console.log(this);
}
foo();
//分析:
/*
1.获取Reference:
var Reference = {
base:EnviromentRecord,
name:'foo',
strict:false
}
2.获取MemberExpression即foo,IsPropertyReference判断base value类型,base value是EnviromentRecord,此处会调用ImplicitThisValue(),这个函数始终返回undefined,所以thisValue为undefined,那么this指向window
*/
//对直接this理解的推翻:
//简单的理解this就是调用函数的对象的问题
var value = 1;
var foo = {
value : 2,
bar : function(){
console.log(this.value);
}
}
console.log((false || foo.bar)());
在这个函数调用的情况下,不能确定调用函数的对象,又如何判定this的指向呢?所以还是看规范吧!
最后附一张this速查表,这张表是对一般情况的一些总结。