推荐英文原址ECMA-262

3.构造函数

构造函数除了通过指定的模式创建对象以外,还有另外一个好处——它能够自动设置新创建对象的原型对象,这个原型对象存储在构造函数的Prototype属性中。

例如,我们使用构造函数来创建对象b和c,如下

[javascript] view
plain
copy

  1. // 构造函数
  2. function Foo(y) {
  3. // 通过指定模式创建对象,对象创建完后,就拥有了y属性
  4. this.y = y;
  5. }
  6. //Foo.prototype存储了新创建对象的原型的引用,我们可以使用它来定义共享的属性或方法
  7. //如下这句,使所有新创建的对象有用共享的属性 "x"
  8. Foo.prototype.x = 10;
  9. // 所有新创建的对象有用共享的方法 "calculate"
  10. Foo.prototype.calculate = function (z) {
  11. return this.x + this.y + z;
  12. };
  13. // 使用Foo构造函数创建对象b和c,注意使用new调用构造函数创建对象
  14. var b = new Foo(20);
  15. var c = new Foo(30);
  16. // 调用继承的方法,该方法为二者共享的,只有一份拷贝
  17. b.calculate(30); // 60
  18. c.calculate(40); // 80
  19. console.log(
  20. //对象b和c原型相同
  21. b.__proto__ === Foo.prototype, // true
  22. c.__proto__ === Foo.prototype, // true
  23. // Foo.prototype 会自动创建一个特别的属性constructor指向构造函数Foo
  24. //对象b和c可以通过代理找到此构造函数
  25. b.constructor === Foo, // true
  26. c.constructor === Foo, // true
  27. Foo.prototype.constructor === Foo // true
  28. b.calculate === b.__proto__.calculate, // true
  29. b.__proto__.calculate === Foo.prototype.calculate // true
  30. );

以上对象的关系如下图所示,

(此图看起来非常复杂,我会着重来分析的,容我翻译完本节回头再写^_^)

这张图展示了每一个对象都有一个对应的原型。构造函数Foo自身也有原型,该原型由Foo的属性_ _proto_ _所指向,如图Function.prototype,而Function.prototype本身又有原型,即Object.prototype。因此,Foo.prototype只是Foo的显式属性,它被对象b和c引用。

正常情况下,如果不考虑类的概念,我们可以把构造函数和原型统称为“类”。事实上,python的动态类就是利用属性/方法手段来实现的。从这点上来看,python的类语法只是ECMAScript代理继承的一种浓缩(syntactic
sugar一词翻译

这个主题的详细完整解释放在了ES3 系列第7章,共有两个部分:面向对象理论和ECMAScript实现。

现在,如果你有基本的面向对象的观点,我们来看看ECMAScript中运行时程序执行的实现。我们也叫做程序执行上下文栈,其中的每个抽象元素都由对象表示,实际上,ECMAScript时刻都透露着面向对象的思想。

4.执行上下文栈

ECMAScript有三种类型的代码:全局代码、函数代码和eval代码。每种代码在它的执行上下文中进行。全局上下文的实例只有一个,而函数和eval上下文却有多个实例。每次函数或者eval调用都会进入相应的函数或者eval的执行上下文中,计算函数或者eval的代码类型。(后面一句相当拗口,说白了就是每次函数调用前将一些状态压入栈中保存,从而在函数代码的执行时,处在当前的函数执行的上下文内。懂得基本的汇编函数调用对理解这个大有益处。)

请注意,每个函数可以产生无数个上下文,因为每次函数被调用(即使函数被自己调用,即嵌套函数)都会产生一个新的上下文,并拥有当前上下文的状态。

[javascript] view
plain
copy

  1. function foo(bar) {}
  2. //调用同一个函数三次,会产生三个的上下文,每个上下文拥有不同的状态,例如参数bar值不一样(很多情况下不仅仅与此)
  3. foo(10);
  4. foo(20);
  5. foo(30);

一个上下文激活另一个上下文,那么前者就叫做调用者,后者叫作被调用者。被调用者可能同一时间又是调用者(例如一个函数被全局上下文调用,该函数又调用内部函数)。当调用者调用被调用者,那么调用者会暂停滋生的执行,并把控制流传给被调用者。被调用者被压入栈,变成一个运行(激活)的执行上下文,当被调用上下文结束,将会返回控制流给调用者,调用者再继续执行直到结束(期间可能又激活其他上下文)。被调用者返回return结果或者因为异常退出。一个非捕获异常可能导致从多个上下文退出(出栈)。

所有的ECMAScript程序运行时通过执行上下文(EC)栈来展现,栈最顶部的上下文是激活(正在运行着)的上下文,如下为一个执行上下文栈,

当程序开始时,先进入全局执行上下文(Global EC),它是栈中最底部也是第一个元素。全局代码进行一些初始化,创建必要的对象和函数 。在全局上下文执行的时候,它会激活其它上下文(函数调用),并将新元素压入栈。初始化以后,则等待一些事件来触发函数,从而进入新的上下文中。下图展现了函数上下文的变化情况,栈从上下文EC1进入和退出全局上下文的过程,

如我们所说,每个栈中的执行上下文都是一个对象,让我们来看看它的结构以及上下文需要哪些状态来运行代码。

5.执行上下文

执行上下文抽来来说就是一个简单对象。每一个执行上下文都有一些属性的集合(上下文状态),用来跟踪相关代码的执行过程。下图即为上下文的结构图

[javascript] view
plain
copy

  1. <span style="font-family: 'Microsoft YaHei'; white-space: normal; background-color: rgb(255, 255, 255); ">除了这三种必要属性外,执行上下文在实现上可以有其它的状态。我们来看看这些重要属性的细节。</span>

变量对象

变量对象是跟上下文有关的数据的范围,这个对象存储了在上下文中定义的变量、函数声明

注意,函数表达式(对比函数声明)不包括在变量对象之中

变量对象是一个抽象的概念,在不同的上下文类型中,会使用不同的对象。例如,在全局上下文中,变量对象就是全局对象本身(这就是为什么我们能够通过全局对象的属性名来引用全局变量),如下:

[javascript] view
plain
copy

  1. var foo = 10;
  2. function bar() {} // 函数声明, FD
  3. (function baz() {}); //函数表达式, FE
  4. console.log(
  5. this.foo == foo, // true
  6. window.bar == bar // true
  7. );
  8. console.log(baz); // 引用错误, "baz" 未定义

全局上下文变量对象(VO)会有下列属性

再一次看到,函数baz作为一个函数表达式没有包括在变量对象中。这就是为什么在外部访问函数自身时产生引用错误。

注意,相对于其他语言(如C++),在ECMAScript只有函数会创建一个新的范围。变量和在函数内定义的内部函数在外部不可见,不会污染全局对象变量。

使用eval也会进入一个新的eval执行上下文,然后,eval使用全局变量对象或者调用eval的变量对象(例如调用eval的某个函数)

函数和其变量对象是什么样的?在函数上下文中,变量对象表现为一个激活对象(activation object)

激活对象

当一个函数被调用时,一个特别的激活对象就会被创建。形式参数和一个特别的argument对象(它是对形参的一种映射,可以通过索引寻找指定的形参)将会用来对它赋值,然后激活对象就可以作为一个函数的变量。例如,一个函数的变量对象不仅存储了函数的变量和函数声明,它也存储了形式参数和argument对象,它就叫做激活对象。例如下面这个例子:

[javascript] view
plain
copy

  1. function foo(x, y) {
  2. var z = 30;
  3. function bar() {} // FD
  4. (function baz() {}); // FE
  5. }
  6. foo(10, 20);

我们有了函数上下文的另一个对象。

函数表达式baz仍然不包括在变量/激活对象中。

我们继续进行下一节。如我们所知,在ECMAScript中我们使用内部函数,这些内部函数可能引用父函数或者全局函数的变量,就像上文提到的原型链,我们给作用域对象起名为作用域链。

作用域链

我们作用域链是一个对象列表,它用来寻找出现在上下文代码中的特定符号。

V8引擎实现标准ECMA-262(三)的更多相关文章

  1. 一文搞懂V8引擎的垃圾回收

    引言 作为目前最流行的JavaScript引擎,V8引擎从出现的那一刻起便广泛受到人们的关注,我们知道,JavaScript可以高效地运行在浏览器和Nodejs这两大宿主环境中,也是因为背后有强大的V ...

  2. 浅谈Chrome V8引擎中的垃圾回收机制

    垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...

  3. V8引擎嵌入指南

    如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...

  4. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  5. 精读《V8 引擎 Lazy Parsing》

    1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...

  6. Javascript的V8引擎研究

    1.针对上下文的Snapshot技术 什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面 ...

  7. Google V8 引擎 原理详解

    V8 引擎概览 V8 引擎简介 Google V8 引擎使用 C++ 代码编写,实现了 ECMAScript 规范的第五版,可以运行在所有的主流 操作系统中,甚至可以运行在移动终端 ( 基于 ARM ...

  8. Nodejs V8引擎 fast property lookup

    前言 之所以会研究这个东西,是我在网上找了一下各个语言的执行效率比较.好吧,我承认这是个无聊的东西,不过看看总是无妨,然而我惊讶的发现,有些测试声称Java,C,Nodejs是处在同一个效率级别参见链 ...

  9. JavaScript工作机制:V8 引擎内部机制及如何编写优化代码的5个诀窍

    概述 JavaScript引擎是一个执行JavaScript代码的程序或解释器.JavaScript引擎可以被实现为标准解释器,或者实现为以某种形式将JavaScript编译为字节码的即时编译器. 下 ...

随机推荐

  1. Django惰性加载和LazyObject

    看登录中间件的时候发现request.user返回的是SimpleOject对象,往下看翻到了LazyObject,看源码看了半天没看懂 网上搜了一堆资料了解下惰性加载实现是的什么功能,再回去看源码, ...

  2. 深入浅出 Java Concurrency (5): 原子操作 part 4[转]

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...

  3. mysql高级教程(三)-----数据库锁、主从复制

    锁 概念 锁是计算机协调多个进程或线程并发访问某一资源的机制.  在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性. ...

  4. 【agc013d】AtCoder Grand Contest 013 D - Piling Up

    题意 盒子里有n块砖,每块的颜色可能为蓝色或红色. 执行m次三步操作: 1.从盒子里随便拿走一块砖 2.放入一块蓝砖和红砖到盒子里 3.从盒子里随便拿走一块砖 给定n,m 问拿出来的砖,可能有多少种不 ...

  5. day1(老男孩-Python3.5-S14期全栈开发)

    作者:赵俊            发布日期:2019/10/18 一.第一个python程序 1.在解释器下写hello world程序运行,与运行外部文件方法 运行外部文件,必须在相应位置创建一个p ...

  6. JasperReport查看和打印报告7

    报表填充过程JasperPrint对象的输出可以使用内置的浏览器组件来查看,打印或导出到更多的流行的文件格式,如PDF,HTML,RTF,XLS,ODT,CSV或XML.Jasper文件查看和打印将包 ...

  7. 高斯消元和高斯约旦消元 Gauss(-Jordan) Elimination

    高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵. 在讲算法前先介绍些概念 矩阵的初等变换 矩阵的初等变换又分为矩阵的初等行变换和矩阵的初等列变换 ...

  8. xshell评,xftp估过期解决办法

    去官网 xshell:https://www.netsarang.com/download/down_form.html?code=522 xftp:https://www.netsarang.com ...

  9. 未加星标 Linux磁盘下查看I/O磁盘的性能

    iostat查看linux硬盘IO性能 rrqm/s:每秒进行merge的读操作数目.即delta(rmerge)/s wrqm/s:每秒进行merge的写操作数目.即delta(wmerge)/s ...

  10. 搭建php虚拟环境

    参考网址: http://my.oschina.net/u/998304/blog/501363?p={{totalPage}} Box镜像列表: http://www.vagrantbox.es/ ...