ECMAScript : the point & the core

ECMAScript javascript this closure prototype

此文将对JS的核心内容: 执行上下文 作用域 以及涉及的活动对象,变量对象。 执行流细节:各种创建,声明。 关于声明:hoistin机制, 优先顺序,声明 定义 初始化 分阶段进行。函数与变量同名时所遇的问题,它们声明先后,初始化先后,所引起的问题。各种杂合,要彻底搞明白还需要理一下。把几遍博文翻译了,理解了,那就差不多了。

先谈基础的部分: 按点谈论

ECMA-262 : the core

基本类项与引用类型的区别

1。复制变量 variable : 1,副本 2,堆内存概念(指针指向)
2。按值传递:ECMAScript 中所有函数的参数都是按值传递的。注意的引用类型的问题。
3。类型检测: 1,基本:typeof 2,引用:instanceof

执行环境及作用域 :

大部分情况叫做: 执行上下文 (execution context ) 解析: 执行环境(execution context,为简单起见,有时也称为“ 环境”)是 JavaScript 中最为重要的一个概 念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个 与之关联的变量对象(variable object) ,环境中定义的所有变量和函数都保存在这个对象中。虽然我们 编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同,表示执行环 境的对象也不一样。在 Web 浏览器中,全局执行环境被认为是 window 对象(第 7 章将详细讨论) ,因 此所有全局变量和函数都是作为 window 对象的属性和方法创建的。某个执行环境中的所有代码执行完 毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退 出——例如关闭网页或浏览器——时才会被销毁)。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。 而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。 ECMAScript 程序中的执行流 正是由这个方便的机制控制着。 此处输入图片的描述

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是 保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所 在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对 象在最开始时只包含一个变量,即 arguments 对象(这个对象在全局环境中是不存在的)。作用域链中 的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延 续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始, 然后逐级地向后回溯,直至找到标识符为止(如果找不到标识符,通常会导致错误发生)。

细节问题:

查找调用函数的代码。 执行函数代码之前,先创建执行上下文。 进入创建阶段: 初始化作用域链: 创建变量对象: 创建arguments对象,检查上下文,初始化参数名称和值并创建引用的复制。 扫描上下文的函数声明: 为发现的每一个函数,在变量对象上创建一个属性——确切的说是函数的名字——其有一个指向函数在内存中的引用。 如果函数的名字已经存在,引用指针将被重写。 扫面上下文的变量声明: 为发现的每个变量声明,在变量对象上创建一个属性——就是变量的名字,并且将变量的值初始化为undefined 如果变量的名字已经在变量对象里存在,将不会进行任何操作并继续扫描。 求出上下文内部“this”的值。 激活/代码执行阶段: 在当前上下文上运行/解释函数代码,并随着代码一行行执行指派变量的值。 从上面可以看出 是扫描函数声明,再扫描变量声明,并且对出现的名字重复,采取的处理也不一样。

变量的hoisting机制

http://segmentfault.com/a/1190000002582759
http://yanhaijing.com/javascript/2014/04/30/JavaScript-Scoping-and-Hoisting/

声明提升到作用域的最前面: 声明只是为undefined,并未初始化赋值。仅仅变量名字被提升了。而函数声明,整个函数体也会提升 *声明 初始化 * 在MDN里看来,先考虑声明与 初始化这两个不同 如果变量声明语句里面带有赋值操作,则赋值操作只有被执行到声明语句的时候才会发生,而不是创建的时候。j就是执行到这一行时。 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Grammarandtypes

名字解析顺序

javascript中一个名字(name)以四种方式进入作用域(scope),其优先级顺序如下:
1、语言内置:所有的作用域中都有 this 和 arguments 关键字
2、形式参数:函数的参数在函数作用域中都是有效的
3、函数声明:形如function foo() {}
4、变量声明:形如var bar;

名字声明的优先级如上所示,也就是说如果一个变量的名字与函数的名字相同,那么函数的名字会覆盖变量的名字,无论其在代码中的顺序如何。但名字的初始化却是按其在代码中书写的顺序进行的,不受以上优先级的影响。看代码:

(function(){
var foo;  
console.log(typeof foo); //function  
function foo(){}  
foo = "foo";  
console.log(typeof foo); //string  
})();
function a(){};  
var a="aa";  
console.log(typeof a);//"string"  
var b="bb";  
function b(){};  
console.log(typeof b);//"string"  
//写到这,我就不明白了。懵了。这里我需要一个解释。
//考虑声明与初始化的不同
var a=1;  
var a=2;  
console.log(a);//2  
function aa(){return 1};  
function aa(){return 2};  
console.log(aa());//2  
var c=1;  
function c() {return 2};  
console.log(typeof c);//"number"  
function d() {return 1};  
var d=1;  
console.log(typeof d);//"number"  

如果形式参数中有多个同名变量,那么最后一个同名参数会覆盖其他同名参数,即使最后一个同名参数并没有定义。 以上的名字解析优先级存在例外,比如可以覆盖语言内置的名字arguments。

写的例子作为直接参考:

var a=1;  
var a=2;  
console.log(a);//2  
function aa(){return 1};  
function aa(){return 2};  
console.log(aa());//2  
var c=1;  
function c() {return 2};  
console.log(typeof c);//"number"  
function d() {return 1};  
var d=1;  
console.log(typeof d);//"number"  
// 现在就是同名的问题。c和d未出现覆盖。直接是变量为大。
(function(){
var foo;  
console.log(typeof foo); //function。执行上下文细节中是扫描function声明。因为都未执行到初始化的阶段(就是未执行声明的那一行)。 按我说的优先级来说,是foo未赋值 。  
function foo(){}  
foo = "foo";  
console.log(typeof foo); //string  
})();
var j="ss";  
console.log(j);// 上面已赋值,所以有输出"ss"  
console.log(k);// undefined, hosting后知道k为变量, 初始为undefined,但未执行到下一句的初始化操作,为进行赋值。  
var k="kk";  
//看下面两例子
var aa;  
console.log(typeof aa); //"function"  
function aa() {};  
var bb=1;  
console.log(typeof bb); //"number"  
function bb() {};  
//在与最开始的例子比较,可以设定一个简要的优先级。
//声明前后 , 初始化 前后。 分开看。
//首先遵循若变量在调用之前初始化,(即使function也初始化)变量一定为大。就未初始化之前,function为大。
//上面几个例子足够说明遇到的问题。并且解除疑惑了。但缺乏正确的原则的解释

总结:

很乱,真的很乱。搞得概念模糊啊。 执行上下文(execution context )算是基本明白了。从细节分开来讲:变量对象(variable object) 活动对象(activation object) 作用域链(scope chain)作用域。然后hoisting机制,也翻译为预解析,所以各种翻译也带来很多问题。其中声明(declaration)和初始化(initialization)是两个不同部分。针对同名的问题就只有通过实例说明。翻看国内大牛的blog也没有说清楚,有些翻译甚至错误的东西一并带来,不加验证。所以真的的把英语使劲搞好,参看技术性的名称,直接看外国大牛文章。

文章还需多加解释与加强,待后面学的更深再来整理整理。

参考:

基本内容直接看参考链接就好。

http://yanhaijing.com/javascript/2014/04/29/what-is-the-execution-context-in-javascript/ 注意这是翻译,原文章出处的博客作者更加牛逼,把原作者的文章翻译了(作者写的是一系列的文章)
http://yanhaijing.com/javascript/2014/04/30/JavaScript-Scoping-and-Hoisting/
http://segmentfault.com/a/1190000002582759
http://weizhifeng.net/javascript-the-core.html 翻译的
http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/ 原文,躲过语言,足以说明作者的牛逼。
http://dmitrysoshnikov.com/tag/ecma-262-3/ 一系列的文章。
https://github.com/TooBug/javascript.patterns/blob/master/chapter4.markdown
http://www.nowamagic.net/librarys/veda/detail/1707
http://bonsaiden.github.io/JavaScript-Garden/zh/