javascript系列之核心知识点(一)

JavaScript. The core.







1.对象

2.原型链

3.构造函数

4.执行上下文堆栈

5.执行上下文

6.变量对象

7.活动对象

8.作用域链

9.闭包

10.this值

11.总结

这篇文章是“ECMA-262-3
in
detail
”系列的一个摘要和总结。每一部分包含了对应章节的连接引用,所以你可以仔细去阅读得到一个更深刻的理解。适合的读者:资深程序员,专家。我们从探讨对象的概念开始,这也是ECMAScript的奠基石。





对象

ECMAScript,一个高度抽象的面向对象语言。它按原始方式处理对象,但当我们需要时,它也可以转化对象。

对象是只有一个原型对象的属性集合。这个原型是object或者null

让我们看一个对象的基本实例,对象的原型是通过内置属性[[Prototype]]引用的。然而专门为了理解原型对象,在图中我们将会用_<internal-property>_下划线_proto_代替双括号。代码:

1 var foo={
2 x:10,
3 y:20
4 };

  我们有了含有两个显式的自身属性和一个隐式的_proto_属性的结构,这个_proto_属性是foo原型的一个引用:

图1.一个含有原型的基本对象

这些原型需要什么?让我们思考完原型链的概念后来回答这个问题。





原型链

原型对象也仅仅是一个简单的对象,且他们也有自己的原型。如果一个原型对象有一个非null的引用指向它的原型,这样循环下去(译者注:到null终止)。这就形成所谓的原型链。

    
原型链是一个有限长的对象链,用来实现继承和共享属性的。

考虑这种情况,当我们有两个仅仅只在一些小的部分存在差异而其他绝大部分都相同的对象。为了设计一个更好的系统,很明显的,在单一的对象中我们会重用相似功能/代码,而不用去重复它。在基于类的系统中,这种代码重用方式叫基于类的继承-你把相似的功能放在类A中,然后构造从类A继承而来的类B和类C,他们都有自身的微小变化。

ECMAScript没有类的概念,然而代码重用方式也没有太大不同(尽管在某些方面它比基于类的方式更灵活),是通过原型链来实现代码重用的。这种继承被称为仿类继承(或者为了符合ECMAScript,叫原型链继承)。

类似在例子中用classesA,B和C。在ECMAScript中,你可以创建对象:a,b和c。所以对象a含有对象b和c的相同部分。b和c仅仅包含他们自身的属性或者方法。


 1 var a={
2 x:10,
3 calculate:function(z){
4 return this.x+this.y+z
5 }
6 };
7 var b={
8 y:20,
9 _proto_:a
10 };
11 var c={
12 y:30,
13 _proto_:a
14 };
15 //调用继承的方法
16 b.calculate(30);//60
17 c.calculate(40);//80

很简单吧。我们发现b和c获取了定义在对象a中的calculate方法。准确的说是通过原型链获取的。

原理很简单:如果一个属性或者方法在对象自身中找不到(也就是说对象中没有一个这样的自身属性),然后就试图在原型链中寻找这个属性/方法。如果这个属性
在原型中没有找到,则考虑到这个原型对象的原型中查找,递推下去,也就是说贯穿整个原型链(在基于类的继承中是完全一样的,在解析一个继承的方法时-遍历
整个类链)。第一个找到的同名属性/方法被使用。所以,被找到的属性被称为继承属性。如果遍历完整个原型链,这个属性还是没找到,返回
undefined。

注意,在使用继承方法时,方法中的this值被设置为初始对象(译者注:调用对象),而不是方法存在的原型对象。也就是说,在上面例子中的this.y是从b和c获取的,而不是从a获取。然而,this.x是通过原型链机制从a中获取。

如果一个对象没有显式的定义其原型,缺省的_proto_值将指向Object.prototypeObject.prototype对象也有自身的_proto_,就是这个原型链的最终连接,其值为null。下面这幅图展示了a,b和c对象的继承结构:


图2.原型链

注意:ES5中标准化了一个基于原型继承的替代方法Object.create函数:

1 var b=Object.create(a,{y:{value:20}});
2 var c=Object.create(a,{y:{value:30}});

ES6中标准化了__proto__,可以在对象初始化时使用

经常需要得到有相同或者类似结构(也就是有相同的属性集合),而其值又不同的一些对象。在这种情况下我们应该使用构造函数在特定模式下来创建对象。





构造函数

除了通过特定模式创建对象之外,构造函数还干了另外一件有用的事情-为新创建的对象自动设置一个原型对象。这个原型对象放在ConstructorFunction.prototype的属性中。例如我们用构造函数重写前面例子中的b和c,因此,对象Foo.prototype扮演着a(原型)的角色:


 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.y+this.x+z;
12 };
13 //使用"pattern"Foo来创建我们的b,c对象
14 var b=new Foo(20);
15 var c=new Foo(30);
16 //调用继承的方法
17 b.calculate(30);//60
18 c.calculate(40);//80
19 //我们展示所期望的引用属性
20 console.log(
21 b._proto_===Foo.prototype,//true
22 c._proto_===Foo.prototype,//true
23 //"Foo.prototype"自动构造了特殊的"constructor"属性,它是构造函数自身的引用;实例b和c可以通过委托和检测他的构造函数来找到她
24 b.constructor===Foo,//true
25 c.constructor===Foo,//true
26 Foo.prototype.constructor===Foo,//true
27 b.calculate===b._proto_.calculate,//true
28 b.__proto__.calculate === Foo.prototype.calculate//true
29 );

这段代码可以用如下的关系图表示:

图3.构造函数和对象之间的关系

上图再一次表明每一个对象都有一个原型。构造函数的_proto_
Function.prototype,通过它(译者注:Function.prototype)的 _proto_属性再次引用到Object.prototype。再次重申,Foo.prototype仅仅只是Foo的一个显式属性指向b和c对象的原型。

  
这个主题的完整和详细的解释在这个系列的第七节能找到。
这里你会找到不同OOP语言的范例和理论以及和ECMAScript的比较。Chapter
7.2. OOP. ECMAScript implementation
致力于ECMAScript的OOP。

现在,我们了解了对象的基础知识,然我们看看在ECMAScript中代码执行时如何实现的。这就是所谓的执行上下文堆栈,这里面的每一部分也可以抽象的表示为一个对象。是的,在ECMAScript的操作中处处充斥着对象的理念。





执行上下文堆栈

有三种类型的ECMAScript代码:全局代码,函数代码和eval代码。每一种代码都在其执行上下文中运行。只有一个全局上下文,可能有许多函数和eval执行上下文的实例。每次调用函数,进入函数的执行上下文并执行器函数代码。每次调用eval函数,进入eval的执行上下文并运行它的代码。

记住一个函数可能产生无限多个上下文环境,因为每调用一次函数(即使函数递归的调用自己)都会产生一个新的上下文:


1 function foo(bar){
2 //调用同一个函数,由于不同的上下文状态(比如"bar"参数值)产生不同的上下文
3 foo(10);
4 foo(20);
5 foo(30);
6 }

一个执行上下文可能激活另一个上下文,例如。一个函数调用另一个函数(或者全局上下文调用全局函数),等等。逻辑上这是有一个堆栈来实现的,就是所谓的执行上下文堆栈。激活了另一个上下文的上下文叫做调用者。被激活的上下文叫做被调用者。同时被调用者也可以是其他被调用者的调用者(例如,一个函数在全局上下文调用,又调用了它的一些内部函数)。

当一个调用者激活(调用)一个被调用者,调用者暂停它的上下文并传递控制流进入被调用者。被调用者被压入栈中并成为当前(激活)的执行上下文。当被调用者
的上下文结束后,控制流回到调用者中,运行调用者的上下文处理(此时他可能有激活了其他上下文),直到结束。被调用者可能由于错误返回或调出。一个抛出二
没有没捕获的错误会跳出(从堆栈中弹出)一个或多个上下文。

例如。所有的ECMAScript程序运行时可以表示为一个执行上下文堆栈(EC),栈的顶部是一个激活上下文:

图4.一个执行上下文堆栈

程序开始时便进入全局执行上下文,栈的第一个元素也是最底部的元素。然后全局代码进行了一些初始化,创建了必要的对象和函数。在执行全局上下文时,它的代
码会激活其他(已经创建)函数,并进入到他们的执行上下文,向执行上下文堆栈汇总推入新的元素,一直下去。当初始化结束后,运行的系统会等待一些事件(例
如用户点击鼠标),这些事件会激活一些函数并进入一个新的执行上下文。

在下图中,有函数上下文EC1和全局上下文Global EC,当全局上下文进入和跳出EC1时堆栈变化如下:

图5,执行上下文堆栈变化

这准确的描述了ECMAScript中的运行程序是如何管理代码的执行的。关于ECMAScript中执行上下文更详细的信息请阅读Chapter
1. Execution context
.





执行上下文

执行上下文可以抽象的表示为一个简单的对象。每一个执行上下文都有一些必要的属性(可以叫做上下文状态)去追踪它对应代码的执行进程。下图展示了一个上下文的结构:

图6一个执行上下文结构

除了这三个必须的属性(变量对象,this值和作用域链),执行上下文依据具体实现可能有其他附加状态。让我们详细的考虑上下文的这些重要属性。

javascript系列之核心知识点(一),布布扣,bubuko.com

时间: 2024-08-07 18:29:13

javascript系列之核心知识点(一)的相关文章

【SpringBoot MQ 系列】RabbitMq 核心知识点小结

[MQ 系列]RabbitMq 核心知识点小结 以下内容,部分取材于官方教程,部分来源网络博主的分享,如有兴趣了解更多详细的知识点,可以在本文最后的文章列表中获取原地址 RabbitMQ 是一个基于 AMQP 协议实现的企业级消息系统,想要顺畅的玩耍的前提是得先了解它,本文将主要介绍 rabbitmq 的一些基本知识点 特点 基本概念 消息投递消费的几种姿势 事务 集群 I. 基本知识点 它是采用 Erlang 语言实现的 AMQP(Advanced Message Queued Protoco

深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)

本篇是ECMA-262-3 in detail系列的一个概述(本人后续会翻译整理这些文章到本系列(第11-19章).每个章节都有一个更详细的内容链接,你可以继续读一下每个章节对应的详细内容链接进行更深入的了解. 适合的读者:有经验的开发员,专业前端人员. 原作者: Dmitry A. Soshnikov 发布时间: 2010-09-02 原文:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ 参考1:http://ued.ctr

javascript系列之DOM(二)

原生DOM扩展 我们接着第一部分来说,上文提到了两种常规的DOM操作:创建文档片段和遍历元素节点.我们知道那些雨后春笋般的库,有很大一部分工作就是提供了一些优秀 的DOM操作API.可见原生的一些方法和属性,还不能很灵活快捷的来完成我们所希望的操作.下面将总结出总结出几种很实用的扩展方法.包括 after()和before(), A:after()和before() 1 function after(elem){ 2 if(this.parentNode){ 3 this.parentNode.

深入理解JavaScript系列 --汤姆大叔

深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 深入理解JavaScript系列(2):揭秘命名函数表达式 深入理解JavaScript系列(3):全面解析Module模式 深入理解JavaScript系列(4):立即调用的函数表达式 深入理解JavaScript系列(5):强大的原型和原型链 深入理解JavaScript系列(6

深入理解JavaScript系列:JavaScript的构成

此篇文章不是干货类型,也算不上概念阐述,就是简单的进行一个思路上的整理. 要了解一样东西或者完成一件事情,首要的就是先要搞清楚他是什么.作为一个前端开发人员,JavaScript应该算作是最核心之一的内容.要想从掌握到熟悉再到精通这门语言,第一步要做的就是先弄明白JavaScript是个什么. 1.JavaScript是什么. JavaScript是门语言,和C#.C++.Java这些编程语言一样,只不过不同语言间有各自的语言规范差异.当然,这是句废话. 前端学习一般从写一个静态页面开始,这个以

深入理解JavaScript系列(44):设计模式之桥接模式

介绍 桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化. 正文 桥接模式最常用在事件监控上,先看一段代码: addEvent(element, 'click', getBeerById); function getBeerById(e) { var id = this.id; asyncRequest('GET', 'beer.uri?id=' + id, function(resp) { // Callback response. console.log('Requ

深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP

前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第5篇,依赖倒置原则LSP(The Dependency Inversion Principle ). 英文原文:http://freshbrewedcode.com/derekgreer/2012/01/22/solid-javascript-the-dependency-inversion-principle/ 依赖倒置原则 依赖倒置原则的描述是: A. High-level modules should not

深入理解JavaScript系列(24):JavaScript与DOM(下)

介绍 上一章我们介绍了JavaScript的基本内容和DOM对象的各个方面,包括如何访问node节点.本章我们将讲解如何通过DOM操作元素并且讨论浏览器事件模型. 本文参考:http://net.tutsplus.com/tutorials/javascript-ajax/javascript-and-the-dom-lesson-2/ 操作元素 上一章节我们提到了DOM节点集合或单个节点的访问步骤,每个DOM节点都包括一个属性集合,大多数的属性都提供为相应的功能提供了抽象.例如,如果有一个带有

深入理解JavaScript系列(4):立即调用的函数表达式

前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法也不一定完全对,主要是看个人如何理解,因为有的人说立即调用,有的人说自动执行,所以你完全可以按照你自己的理解来取一个名字,不过我听很多人都叫它为“自执行”,但作者后面说了很多,来说服大家称呼为“立即调用的函数表达式”. 本文英文原文地址:http://benalman.com/news/2010/11/immedia