Learning Records JavaScript进阶( 三 )


  1. base value 2. reference name 3. strict reference其中base value 就是属性所在的对象或者EnvironmentRecord,reference name是属性的名称下面举两个例子
var foo = 1;// 对应的Reference是:var fooReference = { base: EnvironmentRecord, name: 'foo', strict: false};var foo = { bar: function () { return this; }};foo.bar(); // foo// bar对应的Reference是:var BarReference = { base: foo, propertyName: 'bar', strict: false};利用getbase可以得到reference的base value,getvalue可以得到该属性具体的值IsPropertyReference:如果base value是一个对象,返回true
关于this我们来看看在函数调用的时候,如何确定this的取值从规范中可以得知如下
  1. 计算MemberExpression的结果赋值给ref
  2. 判断ref是否是一个Reference类型
  • 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
  • 如果 ref 是 Reference,并且 base value值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
  • 如果 ref 不是 Reference,那么 this 的值为 undefined
function foo() { console.log(this)}foo(); // MemberExpression 是 foofunction foo() { return function() { console.log(this) }}foo()(); // MemberExpression 是 foo()var foo = { bar: function () { return this; }}foo.bar(); // MemberExpression 是 foo.bar原来对MemberExpression的描述就不多赘述,可以简单理解为()左边的部分
var value = https://www.huyubaike.com/biancheng/1;var foo = { value: 2, bar: function () { return this.value; }}//示例1console.log(foo.bar());//示例2console.log((foo.bar)());//示例3console.log((foo.bar = foo.bar)());//示例4console.log((false || foo.bar)());//示例5console.log((foo.bar, foo.bar)());可以看到示例1的MemberExpression是foo.bar,是一个函数reference是var Reference = { base: foo, name:'bar', strict: false};可以看到它是第一种情况,this应该指向的是 GetBase(ref),也就是foo,答案为2对于示例2,加了括号并不会产生影响,所以结果不变至于示例3,4,5,他们都用了操作符,最后的结果是一个值,所以不是reference,this指向undefined
还有一种情况,就是第二种情况,这时返回的是ImplicitThisValue(ref),该函数总是返回undefined,所以最后this也是指向undefined的(当然个人认为这句话还是有点问题)例子
function foo() {console.log(this);}foo();像上面这段代码在本机的输出结果其实是windows全局对象这是因为当前环境的JavaScript没有使用严格模式使用严格模式后,值为undefined
执行上下文那么在了解清楚前面几个东西之后,就可以来看看执行上下文了对执行上下文来说,有3个重要的属性:1.变量对象 2.作用域链 3.this依然给出这个例子
var scope = "global scope";function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f();}checkscope();现在我们来通过上下文的角度重新分析一下这段代码
  1. 创建全局上下文,压入上下文栈:ECSstack = [globalContext]
  2. 全局上下文初始化globalContext = {VO: [global],Scope: [globalContext.VO],this: globalContext.VO}
初始化的同时,checkscope函数被创建,并保存作用域链到内部属性Checkscope.[[scope]] = {globalContext.VO}
  1. checkscope执行上下文入栈ECStack = [checkscopeContext,globalContext,];
复制函数[[ scope ]]属性创建作用域链用argument创建活动对象AO初始化活动对象,加入形参,函数声明,变量声明将活动对象压入作用域链顶端
checkscopeContext = {AO: {arguments: {length: 0},scope: undefined,f: reference to function f(){}},Scope: [AO, globalContext.VO],this: undefined}在初始化的同时,保存作用域链到f的内部属性 [[ scope ]]

经验总结扩展阅读