function foo(a) { var b = 2; function c() {} var d = function() {}; b = 3;}foo(1);
执行该函数上下文时,这时候的AO是
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: undefined, c: reference to function c(){}, d: undefined}
代码执行阶段会顺序执行代码,执行完后是
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: 3, c: reference to function c(){}, d: reference to FunctionExpression "d"}
总结
- 全局上下文的变量对象初始化是全局对象
- 函数上下文变量对象的初始化是argument对象
- 在进入函数上下文后添加形参,变量声明,函数声明的属性值
- 在执行代码阶段,会再次修改变量对象属性值
console.log(foo);function foo(){ console.log("foo");}var foo = 1;
结果为函数对象,因为在执行上下文时,首先会处理函数声明,然后才处理变量声明,如果之前已经有声明过的变量 , 则不会发生覆盖作用域链作用域链指的是由多个变量对象创建的链表当查找变量对象时 , 会优先从当前上下文的变量中查找,如果找不到,会到父级去找(词法作用域)
函数创建函数内部有一个属性scope,当函数被创建时,会保存所有的父级对象到其中scope可以表示所有父变量对象的层级链但是并不代表所有的作用域链
函数激活函数激活时,进入函数上下文,创建活动变量后,添加到作用域链的顶端接下来用一个例子来帮助理解
var scope = "global scope";function checkscope(){ var scope2 = 'local scope'; return scope2;}checkscope();
执行过程如下:- 函数被创建,保存作用域链到内部属性
checkscope.[[scope]] = [ globalContext.VO];
可见,此时作用域链内是全局对象2.函数执行上下文被压入上下文栈ECSstack = [Checkscope,globalContext]
3.函数并不立即执行,而是开始做准备工作,复制函数scope属性创建作用域链Scope:checkscope.[[scope]]用arguments创建活动对象,随后初始化活动对象AO = {arguments:{length:0;},scope2:undefined,Scope:checkscope.[[scope]]}
4.将活动对象压入作用域链顶端Scope:checkscope.[AO,[scope]]5.准备工作完成,开始执行函数,并且修改AO的值6.查找到scope2的值,函数返回后结束执行,并从ECS栈中弹出ECSstack = [globalContext]从ECMAScript规范解读thisECMAScript的中文版地址是(http://yanhaijing.com/es5/#115)ECMAScript有语言类型和规范类型两种类型语言类型就是开发者可以可以直接操作的,比如:undefined,null,string,number等等类型而规范类型是用算法描述ECMAScript语言结构和语言类型的接下来主要介绍规范类型中的Reference
Reference根据ECMAScript里所述,Reference是用来解释delete,typeof以及赋值等操作行为的尤大是这么说的
这里的 Reference 是一个 Specification Type,也就是 “只存在于规范里的抽象类型” 。它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中.Reference 有三个组成部分
- 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的取值从规范中可以得知如下
- 计算MemberExpression的结果赋值给ref
- 判断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};
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- javascript编程单线程之异步模式Asynchronous
- javascript编程单线程之同步模式
- JavaScript函数式编程之函子
- 原生JavaScript
- Learning Records 计算机网络
- JavaScript之无题之让人烦躁的模块化
- GACL 谣言检测《Rumor Detection on Social Media with Graph Adversarial Contrastive Learning》
- Javascript 手写 LRU 算法
- javascript 中的 Microsoft.XMLHTTP 的相关问题!