javascript要点总结
来自: http://my.oschina.net/u/2246410/blog/628611
javascript要点总结
介绍下javascript中的最重要几个概念执行环境、作用域、以及原型链。理解了这两个概念才能写出好的javascript代码,特别是在理解闭包、写插件或者使用使用框架快速上手。
一、执行环境、作用域
1、执行环境(摘抄于javascript高级程序设计):
执行环境(execution context,为简单起见,有时也称为“环境”)是 JavaScript 中最为重要的一个概念。执行环境定义了变量或函数是否有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object) ,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同,表示执行环境的对象也不一样。在 Web 浏览器中,全局执行环境被认为是 window 对象(第 7 章将详细讨论) ,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁) 。
每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。
2、作用域(摘抄于javascript高级程序设计):
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain) 。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始时只包含一个变量,即 arguments 对象(这个对象在全局环境中是不存在的) 。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。
ps:在C中,每次执行一个函数,都会在内存的栈重新中划定一个区域,加载实参、本地变量、返回地址等信息。这片新的内存栈就是执行环境,而执行链就是传递的指针(不是具体变量、而且每个函数都是传递指针)。所有本栈帧可以范围自己的变量和前面栈帧的变量,直到全局变量(window对象)。而前面的栈帧不能访问后面的栈帧变量。
3、案例:
<!DOCTYPE html> <html> <head> <script> var one="One"; function firstFunction(){ var two="Two"; console.log("Two:--"+one); console.log("Two:--"+two); //console.log("Two:--"+three); function sencondeFunction(){ var three="three"; console.log("three:--"+one); console.log("three:--"+two); console.log("three:--"+three); } sencondeFunction(); } firstFunction(); </script> </head> </html>
正常
把注释部分打开(前一个栈帧、访问后一个栈帧。会出现错误)
二、原型链
摘抄于《javascript高级程序设计》的概念:ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念
1、首先一张图:(摘抄于知乎)
2、开始瞎掰
a、我们的测试代码
<!DOCTYPE html> <html> <head> <script> function firstFunction(){ this.two="two"; this.age="age"; } firstFunction.prototype.a="a"; var first=new firstFunction(); console.log(first); console.log(firstFunction.prototype); </script> </head> </html>
b、浏览器告诉我们真像
联系上面的代码,我们先画一张图
__proto__:属性可以看作是原型链。
constructor:看作是java的字节码文件,只是用户定义的class对象,还没有在内存中实现。
prototype:则是class在堆中的实现,才具有使用价值。
接着将firstFunction.prototype中的constructor继续展开(后面的主语):
从这个图我们看见,prototype原型的__proto__是Object对象。然后,constructor的__proto__是function()对象,然后我们继续作画:
在图上添加2条红线后,我们还需要展开 __ptoto__:function(),如下图
从这我们发现function的__proto__也是Object,再把我们的画补齐:
后面的__proto__就展开也没有__proto__、constructor、prototype了,就不上图了。这里我们发现这图还有些变扭。根据《javascript高级程序设计》中描述:有prototype必然有对应的constructor,有constructor比然有对应的prototype。补全
所有的function的__proto__都是function.prototype。而所有prototype的__proto__都是object.prototype。最后object.prototype的__proto__指向的null