this的指向确定
- 参考说明
- Reference介绍
- this确定的方法
- new的说明
- 样例
1. 参考说明
拜读了冴羽大神的深入系列,然后加上自己谷歌的一些理解,让这部分更加容易理解
2. Reference介绍
利用Reference 来就是用来解释诸如 delete、typeof 以及赋值等操作行为的。用其更好的描述语言的底层行为
几个概念
对于任何一个我们需要查询的属性,我们将其Reference 用三部分来组成
- base value
代表的是该属性所在的对象, 其值为Object, boolean, string, number, environment record(环境)
- reference name
代表的是该属性的名称
3.strict reference
代表的是否为严格模式
- GetBase()方法
用来获取base value的值
- isPropertyReference()
当base value是一个对象就返回true (我们在这里用来判断this的归属)
6.GetValue
无论任何操作我们取到Reference实际对应的值,调用的全都是GetValue方法, 而只要调用的是GetValue方法,我们获得的一定是一个确定的值,不再是一个Refference (之后做判断!!!重要)
3. this确定的方法
- 求出MemberExpression对应的Reference对象 (如果可以的话)
这里的MemberExpression就是我们查询这个属性时候的表达式
例子:
var foo = 1;
var fooReference = {
base: EnvironmentRecord,
name: 'foo',
strict: false
};
foo定义在全局中所以 对应的base我们认为base=Environment 或者认为是window也可以,其余的不用介绍了把~
- 判断 ref 是不是一个 Reference 类型
2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
2.3 如果 ref 不是 Reference,那么 this 的值为 undefined
4 new 的说明
new在创建一个对象时,其伪代码可以写为
new A("p1"){
var o = {};
o.__proto__ = A.prototype;
result = A.call(o, "p1");
result = typeof result === "object"? result: o;
return result
}
所以如果我们定义的构造函数如果存在返回值,返回值的情况不同会导致我们 base value的不同
// Example 1
function Person(name){
this.name = name;
return 1
}
person = new Person("tom");
console.log(person.name) // "tom"
// Example 2
function Person2(name){
this.name = name;
return {}
}
person2 = new Person2("tom");
console.log(person2.name) // undefined
Example 1: 确定person.name, base value = person, 此时的person来自于new Person() 由于返回值是1不是对象,所以返回obj(详见上述的new的详细解释), 因此base value = Person(), 用isPropertyReference()得到true, 所以此时的this指向就是person 输出为tom (见上述的判断方法)
Example 2: 由于 person2.name中的person来自于 new Person2()返回的{}. 同1理, 这里this指向为{}, 里面不存在name属性, 所以为undefined
例子:
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)());
例1
找到foo.bar为MemberExpression, 其可转化为Reference, ref为
{
baseValue: foo,
name: bar
}
其baseValue 对应着一个object对象,所以其this指向就是foo 输出为 2
例2
(foo.bar)() 和 foo.bar 相同,因为()仅改变运算顺序,而本身的运算顺序就是从左到右不改变,所以和第一题一样,输出为2
例3
这里先进行了 foo.bar = foo.bar
MemberExpression简化成 ref() 其中ref = (foo.bar = foo.bar) 我们需要判断ref中this 的指向
-
首先: "="是一个赋值操作, 赋值操作返回的是一个值 (利用GetValue方法), 不再是一个Reference 对象了
-
此时ref返回不再是一个Reference, 所以此时将this指向 undefiend, 非严格模式下, undefiend就是指向window
-
最终输出 1
例4
MemberExpression简化成 ref() 其中ref = (false || foo.bar) 我们需要判断ref中this 的指向
false || foo.bar 这里相当于进行了一个赋值操作 调用了GetValue方法 和例3一样, this指向window 输出1
例5
在大神博客中讲, 官方的说明中写出 逗号表达式也是反映为GetValue, 因此输出仍为1
(A, B)() —> 先执行A, 再执行B, 之后把B 的函数进行调用输出