- 浏览: 1230942 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
lankk:
lankk 写道事实上,在运行String s1=new St ...
理解String 及 String.intern() 在实际中的应用 -
lankk:
事实上,在运行String s1=new String(&qu ...
理解String 及 String.intern() 在实际中的应用 -
lankk:
同意1楼的说法http://docs.oracle.com/j ...
理解String 及 String.intern() 在实际中的应用 -
raoyutao:
...
jdk 线程池 ThreadPoolExecutor -
hongdanning:
理解了。之前困惑的一些明白了。谢谢分享。
理解String 及 String.intern() 在实际中的应用
红色虚线表示隐式Prototype链。
这张对象模型图中包含了太多东西,不少地方需要仔细体会,可以写些测试代码进行验证。彻底理解了这张图,对JavaScript语言的了解也就差不多了。下面是一些补充说明:
1. 图中有好几个地方提到build-in Function constructor,这是同一个对象,可以测试验证:
Function==Function.constructor //result: true
Function==Function.prototype.constructor //result: true
Function==Object.constructor //result: true
//Function also equals to Number.constructor, String.constructor, Array.constructor, RegExp.constructor, etc.
function fn(){}
Function==fn.constructor //result: true
这说明了几个问题: Function指向系统内置的函数构造器(build-in Function constructor);Function具有自举性;系统中所有函数都是由Function构造。
2. 左下角的obj1, obj2...objn范指用类似这样的代码创建的对象: function fn1(){}; var obj1=new fn1();
这些对象没有本地constructor方法,但它们将从Prototype链上得到一个继承的constructor方法,即fn.prototype.constructor,从函数对象的构造过程可以知道,它就是fn本身了。
右下角的obj1, obj2...objn范指用类似这样的代码创建的对象: var obj1=new Object();或var obj1={};或var obj1=new Number(123);或obj1=/\w+/;等等。所以这些对象Prototype链的指向、从Prototype链继承而来的constructor的值(指它们的constructor是build-in Number constructor还是build-in Object constructor等)等依赖于具体的对象类型。另外注意的是,var obj=new Object(123);这样创建的对象,它的类型仍然是Number,即同样需要根据参数值的类型来确定。
同样它们也没有本地constructor,而是从Prototype链上获得继承的constructor方法,即build-in *** constructor,具体是哪一个由数据类型确定。
3. 关于图中Prototype链的补充说明:
Object.prototype是整个链的终结点,它的内部[[Prototype]]为null。
所有函数的Prototype链都指向Function.prototype。
Function的Prototype链指向Function.prototype,这是规范要求的,因为设计者将Function设计为具有自举性。Function的Prototype链这样设计之后,Function.constructor==Function, Function instanceOf Function都为true。另外Function已经是最顶层的构造器,但Function本身也是一个函数对象,它必然是由某个东西创建出来的,这样自举在语义上合情合理。
Function.prototype的Prototype链指向Object.prototype,这也是规范强制要求的。首先Function.prototype是Function的一个实例对象(typeof Function.prototype可以知道它是一个Function,instanceOf无法通过测试,因为Prototype链在内部被额外设置了),所以按照Prototype的规则,Function.prototype的内部[[Prototype]]值应当为Function.prototype这个对象,即它的Prototype链指向自己本身。这样一方面在Prototype链上造成一个死循环,另一方面它本身成为了一个终结点,结果就是所有函数对象将不是派生自Object了。加上这个强制要求之后,Prototype链只有唯一的一个终结点。
4. 因为Function.prototype是一个函数对象,所以它应当具有显示的prototype属性,即Function.prototype.prototype,但只有FireFox中可以访问到,IE、Opera、Safari都无法访问。所以图中用了个表示不存在的符号。
5. 用户自定义函数(user defined functions)默认情况下[[Prototype]]值是Object.prototype,即它的隐式Prototype链指向Object.prototype,所以图中就这样表示了,但并不代表总是这样,当用户设置了自定义函数的prototype属性之后,情况就不同了。
执行模型
执行上下文(Execution Context)简介
JavaScript代码运行的地方都存在执行上下文,它是一个概念,一种机制,用来完成JavaScript运行时作用域、生存期等方面的处理。执行上下文包括Variable Object、Variable Instatiation、Scope/Scope Chain等概念,在不同的场景/执行环境下,处理上存在一些差异,下面先对这些场景进行说明。
函数对象分为用户自定义函数对象和系统内置函数对象,对于用户自定义函数对象将按照下面描述的机制进行处理,但内置函数对象与具体实现相关,ECMA规范对它们执行上下文的处理没有要求,即它们基本不适合本节描述的内容。
执行的JavaScript代码分三种类型,后面会对这三种类型处理上不同的地方进行说明:
1. Global Code,即全局的、不在任何函数里面的代码,例如一个js文件、嵌入在HTML页面中的js代码等。
2. Eval Code,即使用eval()函数动态执行的JS代码。
3. Function Code,即用户自定义函数中的函数体JS代码。
基本原理
在用户自定义函数中,可以传入参数、在函数中定义局部变量,函数体代码可以使用这些入参、局部变量。背后的机制是什么样呢?
当JS执行流进入函数时,JavaScript引擎在内部创建一个对象,叫做Variable Object。对应函数的每一个参数,在Variable Object上添加一个属性,属性的名字、值与参数的名字、值相同。函数中每声明一个变量,也会在Variable Object上添加一个属性,名字就是变量名,因此为变量赋值就是给Variable Object对应的属性赋值。在函数中访问参数或者局部变量时,就是在variable Object上搜索相应的属性,返回其值。
一般情况下Variable Object是一个内部对象,JS代码中无法直接访问。规范中对其实现方式也不做要求,因此它可能只是引擎内部的一种数据结构。
大致处理方式就这样,但作用域的概念不只这么简单,例如函数体中可以使用全局变量、函数嵌套定义时情况更复杂点。这些情况下怎样处理?JavaScript引擎将不同执行位置上的Variable Object按照规则构建一个链表,在访问一个变量时,先在链表的第一个Variable Object上查找,如果没有找到则继续在第二个Variable Object上查找,直到搜索结束。这就是Scope/Scope Chain的大致概念。
下面是各个方面详细的处理。
Global Object
JavaScript的运行环境都必须存在一个唯一的全局对象-Global Object,例如HTML中的window对象。Global Object是一个宿主对象,除了作为JavaScript运行时的全局容器应具备的职责外,ECMA规范对它没有额外要求。它包Math、String、Date、parseInt等JavaScript中内置的全局对象、函数(都作为Global Object的属性),还可以包含其它宿主环境需要的一些属性。
Variable Object
上面简述了Variable Object的基本概念。创建Variable Object,将参数、局部变量设置为Variable Object属性的处理过程叫做Variable Instatiation-变量实例化,后面结合Scope Chain再进行详细说明。
Global Code
Variable Object就是Global Object,这是Variable Object唯一特殊的地方(指它是内部的无法访问的对象而言)。
document.write(window.globalVariable); //result: WWW
上面代码在Global Code方式下运行,根据对Variable Object的处理,定义变量globalVariable时就会在Global Object(即window)对象上添加这个属性,所以输出是WWW这个值。
Function Code
Variable Object也叫做Activation Object(因为有一些差异存在,所以规范中重新取一个名字以示区别,Global Code/Eval Code中叫Variable Object,Function Code中就叫做Activation Object)。
每次进入函数执行都会创建一个新的Activation Object对象,然后创建一个arguments对象并设置为Activation Object的属性,再进行Variable Instantiation处理。
在退出函数时,Activation Object会被丢弃(并不是内存释放,只是可以被垃圾回收了)。
附arguments对象的属性:
length: 为实际传入参数的个数。注意,参考函数对象创建过程,函数对象上的length为函数定义时要求的参数个数;
callee: 为执行的函数对象本身。目的是使函数对象能够引用自己,例如需要递归调用的地方。
function fnName(...) { ... }这样定义函数,它的递归调用可以在函数体内使用fnName完成。var fn=function(...) { ... }这样定义匿名函数,在函数体内无法使用名字引用自己,通过arguments.callee就可以引用自己而实现递归调用。
参数列表: 调用者实际传入的参数列表。这个参数列表提供一个使用索引访问实际参数的方法。Variable Instantiation处理时会在Activation Object对象上添加属性,前提是函数声明时有指定参数列表。如果函数声明中不给出参数列表,或者实际调用参数个数与声明时的不一样,可以通过arguments访问各个参数。
arguments中的参数列表与Activation Object上的参数属性引用的是相同的参数对象(如果修改,在两处都会反映出来)。规范并不要求arguments是一个数组对象,下面是一个测试:
var argumentsLike = { 0: "aaa", 1: 222, 2: "WWW", length: 3, callee: function() { } };
document.write(argumentsLike[2] + "<br />"); //result: WWW
document.write(argumentsLike[1] + "<br />"); //result: 222
//convert the argumentsLike to an Array object, just as we can do this for the arguments property
var array = [].slice.apply(argumentsLike);
document.write(array instanceof Array); //result: true
document.write("<br />");
document.write(array.reverse().join("|")); //result: WWW|222|aaa
Eval Code
Variable Object就是调用eval时当前执行上下文中的Variable Object。在Global Code中调用eval函数,它的Variable Object就是Global Object;在函数中调用eval,它的Variable Object就是函数的Activation Object。
function fn(arg){
var innerVar = "variable in function";
eval(' \
var evalVar = "variable in eval"; \
document.write(arg + "<br />"); \
document.write(innerVar + "<br />"); \
');
document.write(evalVar);
}
fn("arguments for function");
输出结果是:
arguments for function
variable in function
variable in eval
说明: eval调用中可以访问函数fn的参数、局部变量;在eval中定义的局部变量在函数fn中也可以访问,因为它们的Varible Object是同一个对象。
Scope/Scope Chain
首先Scope Chain是一个类似链表/堆栈的结构,里面每个元素基本都是Variable Object/Activation Object。
其次存在执行上下文的地方都有当前Scope Chain,可以理解为Scope Chain就是执行上下文的具体表现形式。
Global Code
Scope Chain只包含一个对象,即Global Object。在开始JavaScript代码的执行之前,引擎会创建好这个Scope Chain结构。
Function Code
函数对象在内部都有一个[[Scope]]属性,用来记录该函数所处位置的Scope Chain。
创建函数对象时,引擎会将当前执行环境的Scope Chain传给Function的[[Construct]]方法。[[Construct]]会创建一个新的Scope Chain,内容与传入的Scope Chain完全一样,并赋给被创建函数的内部[[Scope]]属性。在前面函数对象创建过程一节中,这个处理位于步骤4和5之间。
进入函数调用时,也会创建一个新的Scope Chain,包括同一个函数的递归调用,退出函数时这个Scope Chain被丢弃。新建的Scope Chain第一个对象是Activation Object,接下来的内容与内部[[Scope]]上存储的Scope Chain内容完全一样。
Eval Code
进入Eval Code执行时会创建一个新的Scope Chain,内容与当前执行上下文的Scope Chain完全一样。
实例说明
Scope Chain的原理就上面这些,必须结合JS代码的执行、Variable Instantiation的细节处理,才能理解上面这些如何产生作用,下面用一个简单的场景来综合说明。假设下面是一段JavaScript的Global Code:
function fn1(arg1, arg2){
var innerVar1="variable in function code";
function fn2() { return outerVar1+" - "+innerVar1+" - "+" - "+(arg1 + arg2); }
return fn2();
}
var outerVar2=fn1(10, 20);
执行处理过程大致如下:
1. 初始化Global Object即window对象,Variable Object为window对象本身。创建Scope Chain对象,假设为scope_1,其中只包含window对象。
2. 扫描JS源代码(读入源代码、可能有词法语法分析过程),从结果中可以得到定义的变量名、函数对象。按照扫描顺序:
2.1 发现变量outerVar1,在window对象上添加outerVar1属性,值为undefined;
2.2 发现函数fn1的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_1。将结果添加到window的属性中,名字为fn1,值为返回的函数对象。注意fn1的内部[[Scope]]就是scope_1。另外注意,创建过程并不会对函数体中的JS代码做特殊处理,可以理解为只是将函数体JS代码的扫描结果保存在函数对象的内部属性上,在函数执行时再做进一步处理。这对理解Function Code,尤其是嵌套函数定义中的Variable Instantiation很关键;
2.3 发现变量outerVar2,在window对象上添加outerVar2属性,值为undefined;
3. 执行outerVar1赋值语句,赋值为"variable in global code"。
4. 执行函数fn1,得到返回值:
4.1 创建Activation Object,假设为activation_1;创建一个新的Scope Chain,假设为scope_2,scope_2中第一个对象为activation_1,第二个对象为window对象(取自fn1的[[Scope]],即scope_1中的内容);
4.2 处理参数列表。在activation_1上设置属性arg1、arg2,值分别为10、20。创建arguments对象并进行设置,将arguments设置为activation_1的属性;
4.3 对fn1的函数体执行类似步骤2的处理过程:
4.3.1 发现变量innerVar1,在activation_1对象上添加innerVar1属性,值为undefine;
4.3.2 发现函数fn2的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_2(函数fn1的Scope Chain为当前执行上下文的内容)。将结果添加到activation_1的属性中,名字为fn2,值为返回的函数对象。注意fn2的内部[[Scope]]就是scope_2;
4.4 执行innerVar1赋值语句,赋值为"variable in function code"。
4.5 执行fn2:
4.5.1 创建Activation Object,假设为activation_2;创建一个新的Scope Chain,假设为scope_3,scope_3中第一个对象为activation_2,接下来的对象依次为activation_1、window对象(取自fn2的[[Scope]],即scope_2);
4.5.2 处理参数列表。因为fn2没有参数,所以只用创建arguments对象并设置为activation_2的属性。
4.5.3 对fn2的函数体执行类似步骤2的处理过程,没有发现变量定义和函数声明。
4.5.4 执行函数体。对任何一个变量引用,从scope_3上进行搜索,这个示例中,outerVar1将在window上找到;innerVar1、arg1、arg2将在activation_1上找到。
4.5.5 丢弃scope_3、activation_2(指它们可以被垃圾回收了)。
4.5.6 返回fn2的返回值。
4.6 丢弃activation_1、scope_2。
4.7 返回结果。
5. 将结果赋值给outerVar2。
其它情况下Scope Chain、Variable Instantiation处理类似上面的过程进行分析就行了。
发表评论
-
node npm windows
2018-10-15 16:06 1239在window下npm install, 遇到一 ... -
How to use requirejs in client side
2016-12-05 16:27 468How to use requirejs in client ... -
dojo get post demo
2015-07-31 14:37 1051dojo.xhrGet({ u ... -
dgrid之Grid Pagination 集成分页 后台rest service
2015-05-19 13:09 2378dgrid之Grid集成分页 后台rest serv ... -
angular 1.3.15 表达式bug
2015-04-15 13:41 871不确定这是 angular的还是浏览器的, chrom ... -
书上看来的js闭包列子
2014-01-22 12:19 1511js闭包列子 <html> <h ... -
犀牛书 & JavaScript Web Applications notes
2012-10-20 22:10 1650https://www.evernote.com/shar ... -
犀牛书 笔记
2012-10-15 09:51 5http://www.evernote.com/shard/s ... -
点击其他地方隐藏popup窗口
2011-12-14 16:54 2268现在系统有一个弹出的日期选择窗口, 要求在窗口弹出后, 点击窗 ... -
jqgrid 隔行变底色
2011-10-20 19:07 5266jgrid默认配置没有 隔行变底色的选项 查看源码 看他怎 ... -
twitter search jquery plugin
2011-06-20 16:05 1981详见 http://tweet.seaofclouds.co ... -
js encodeURIComponent encodeURI decodeURI
2011-05-26 15:48 1480js encodeURIComponent enco ... -
jquery hover hasClass insertBefore live blockUI children notice
2011-05-17 18:22 1866hover $(".onenote& ... -
jquery validate
2011-05-05 18:44 1184function(){ $("#re ... -
js 测试 用户名 中文 英文 数字 判断 函数 是否 存在
2010-11-03 20:24 1786/^((\w)|([\u4E00-\u9FA5])){1,20 ... -
css 滤镜 路径
2010-09-13 20:10 1205在ie6处理png透明的代码是: 1. filt ... -
jquery取得text,areatext,radio,checkbox,select的值
2010-07-09 18:21 1495jquery取得 text,areatext,radio,c ... -
js 遍历对象属性
2010-07-05 12:14 1405<!DOCTYPE html PUBLIC " ... -
jQuery 对Select的操作
2010-06-30 20:36 1117语法解释: 1. $("# ... -
国家地区 js 数组
2010-06-30 19:06 4745en var geolocation= [ [" ...
相关推荐
DeePool通过实现JavaScript对象池,为开发者提供了一种优化内存使用、提高程序运行效率的有效手段。尤其在需要大量创建和销毁对象的场景下,使用DeePool可以显著提升性能,减少内存压力。掌握并合理运用DeePool,...
本篇文章将深入探讨JavaScript对象属性排序的原理、方法以及注意事项。 首先,了解JavaScript对象的基本特性是至关重要的。在ECMAScript规范中,对象的属性访问速度并不依赖于属性的位置或顺序,因为它们内部是通过...
每个JavaScript对象都有一个`__proto__`属性,指向创建该对象的构造函数的原型。原型对象也是一个对象,可以通过`prototype`属性来访问。我们可以在原型上定义方法,这样所有实例都可以访问这些方法: ```...
JavaScript(简称JS)是Web开发中的重要脚本语言,尤其在客户端编程中不可或缺。本文将深入探讨JS对象的实例创建、属性与方法、原型链、继承机制以及在实际应用中的常见场景。 一、JS对象实例的创建 1. 构造函数...
JavaScript对象具有原型链,允许对象继承其他对象的属性和方法。`__proto__`(非标准,推荐使用`Object.getPrototypeOf`)指向其构造函数的原型: ```javascript var parentObj = { parentMethod: function() {} }; ...
在JavaScript中,JSON字符串与JavaScript对象之间可以方便地进行转换,这对于数据传输和存储至关重要。本篇文章将深入探讨JSON字符串与JS对象之间的转换方法。 1. `eval` 函数转换 `eval()` 是JavaScript中的一个...
有关js对象的操作和遍历对象小练习带注释.html
- **对象与数组**:如何定义JavaScript对象和数组,并在QML中使用它们来存储和操作数据。 - **函数与方法**:定义和调用JavaScript函数,以及在QML对象上添加自定义方法。 - **信号与槽**:利用JavaScript处理QML的...
这个类将作为JavaScript对象的实现,需要包含以下内容: ```cpp #include <JavaScriptCore/JavaScript.h> class MyJsObject : public JSGlobalContextRef::GlobalObject { // ... }; ``` 在这个类中,你可以定义...
XPath是一种在XML文档中查找信息的语言,但在JavaScript对象中,城市名称通常不需要XPath来访问。而“有无城市名称后缀”,可能是指某些城市坐标信息中可能包含了额外的信息,比如“市”或“区”的后缀,这取决于...
总的来说,理解并掌握JavaScript对象和数组的监听机制,有助于我们更好地实现MVVM,提高代码的可维护性和性能。通过这个实例,开发者可以深入学习到如何利用原生JavaScript实现数据绑定和实时更新,这对于前端开发者...
### JavaScript对象读取速度实例详解 #### 一、引言 在JavaScript开发中,了解对象的访问机制对于提高代码执行效率至关重要。本文将基于提供的文件信息,深入探讨JS对象读取速度的影响因素,并通过具体示例来展示...
JavaScript对象允许动态添加、修改和删除属性,无需预先声明。 五、原型与继承 在JS中,每个对象都有一个隐式原型属性 `__proto__`,指向创建它的构造函数的原型。这使得对象可以继承其他对象的属性和方法。通过 `...
### JavaScript对象模型-执行模型详解 #### 一、基本数据类型 JavaScript作为一种广泛使用的脚本语言,在其设计之初便提供了一系列的基本数据类型,这些类型构成了JS语言的基础,并且是理解和运用JS的重要基石。 ...
这时,`CSSobj`应运而生,它是一款高效、便捷的工具,能够帮助开发者将JavaScript对象中的样式规则整合成CSSOM(CSS Object Model),从而实现对CSS样式的动态管理。 **什么是CSSOM?** CSSOM是CSS的DOM表示形式,...
"JAVASCRIPT对象属性大全.doc"和"js对象属性方法大总结.doc"可能涵盖了JavaScript对象的属性和方法,包括但不限于原型链(prototype)、原型对象(__proto__)、构造函数(constructor)、以及如何添加和访问对象的...
标签"工具"可能指的是开发者工具,如浏览器的开发者工具,它们提供调试、性能分析等功能,帮助我们理解JavaScript对象编程的实现和行为。 在提供的Noname2.html文件中,可能包含了一个具体的JavaScript对象编程示例...
JavaScript对象(JS Objects)在JSON中扮演着核心角色。一个JS对象本质上是一个键值对的集合,这些键值对由逗号分隔,并被包裹在花括号{}内。键(key)通常是字符串,而值(value)可以是各种数据类型,包括字符串、...
javaScript对象大全-javaScript必备手册-JS资料-JS教程.doc
这些基础知识构成了JavaScript对象模型的基础,理解和熟练掌握这些概念对于编写JavaScript代码至关重要。在实际编程中,我们经常结合使用这些对象和方法来实现各种功能,如数据处理、用户交互等。随着学习的深入,还...