Javascript本质第一篇:核心概念
很多人在使用Javascript之前都至少使用过C++、C#或Java,面向对象的编程思想已经根深蒂固,恰好Javascript在语法上借鉴了Java,虽然方便了Javascript的入门,但要深入理解Javascript的时候,长期使用这些编程语言造成的思维定势却给使用Javascript带来误导。作者在学习Javascript的时候曾陷入了这个误区,希望通过这篇文章让新学者避免走这个弯路,迅速正确地掌握Javascript。
1. 要点
在面对Javascript时,要牢记以下几点:
1.1 Javascript不是面向对象的编程语言
如果非要把Javascript归到面向什么的话,Javascript准确的说是面向原型的编程语言,它是从self语言发展而来,除了语法上借鉴了Java,其它方面和Java什么关系都没有,本质上更不同。简单说,Javascript里面没有类,全是对象。在使用Javascript的时候,应该时刻提醒自己:Javascript不是C++、C#或Java。
1.2 Javascript是解释执行的语言
虽然这很显而易见,但如果不时刻牢记这一点,而把Javascript和编译型语言的运行方式混淆的话,也非常不利于理解Javascript。比如,如果你用C++、C#或Java中的局部变量的思想去理解Javascript函数中通过var定义的变量的话,就会有麻烦。
2. Javascript中的对象和类型
Javascript没有传统面向对象编程语言中的类,全部是对象。
Javascript中的对象是键值对的集合,键的类型是字符串,值可以是任意对象。创建新对象的方式有:new 函数()、{}语法、Object.create(原型对象)。
函数也是对象,是一种包含可运行的代码的特殊对象,并且代码能够以函数调用的形式被执行。函数对象能通过function关键字定义或通过new关键字使用Function构造函数来创建。
下面的示例创建了一个函数对象foo,并为它设置三个属性:一个数字,一个字符串,一个函数。从示例可以看到函数对象除了能被调用以外,其他行为和普通对象无异。

当通过“new 函数()”的语法创建对象时,函数被称为构造函数。
在Javascript中,通常将构造函数称为对象的类型。比如obj = new Fun(),那么称obj的类型为Fun。
Javascript有Undefined, Null, Boolean, Number, String, Object和Function这几种基本类型。Javascript运行时会对Undefined, Null, Boolean, Number, and String这五种基础类型的对象以及Function类型的函数对象会以特定的方式解释和处理。
因为函数是对象,函数除了可以通过function语法定义以外,也可以用创建对象的方式创建:fun = new Function("参数", "函数体"),Function本身是Javascript内建的函数。
基本类型Boolean, Number, String, Object, Array, Date等都是内建的函数。没有Undefined和Null内建函数,而是有Undefined和Null类型的内建的唯一的对象,分别是undefined和null。
3. 执行上下文
Javascript中每一行代码的执行都是在当前执行上下文中完成。
执行上下文的层级关系是由代码的定义结构(也就是源代码字面结构)决定的,与运行时函数的调用栈结构无关。
执行上下文由一个上下文变量容器和一个this绑定构成。上下文变量容器中包含当前执行上下文中定义的变量。this绑定表示当前执行上下文中this关键字指向的对象。
简单来说,每次函数调用都进入一个新的执行上下文,同一函数递的归调用也会进入新的执行上下文。
每一个执行上下文都包含对创建它的上一级执行上下文的引用,因此所有执行上下文组成一棵树。
在浏览器中,根执行上下文(即不在任何函数中运行的代码)中没有上下文变量容器,this绑定到全局对象window。因此在根执行上下文中定义变量时,使用var、不使用var和使用this.定义的变量都是全局对象window的属性,因为没有上下文变量容器。通过这一规定,Javascript运行过程中的所有执行上下文都能指向全局对象,形成一棵完整的树。
在除了根执行上下文之外的其它执行上下文中,变量定义的规则如下:
| var i = 1 | 变量i位于当前执行上下文的上下文变量容器中 |
| j = 2 | 变量j是全局对象的属性 |
| this.k = 3 | 变量k是当前执行上下文的this对象的属性 |
在表达式中使用一个变量时,Javascript将首先从当前执行上下文的上下文变量容器中查找该变量,如果不存在,则在上级执行上下文的上下文变量容器中查找,以此类推,直到根执行上下文,在根执行上下文中,将在全局对象中查找是否有同名的属性。示例如下:

当前执行上下文的this绑定默认继承自上级执行上下文,如果当前运行代码所在的函数是通过obj.currentfun()的方式调用,也就是obj对象的方法,那么this将被绑定到obj。在使用时,this关键字必须明确写出,因为this在逻辑上是与执行上下文有关的,与当前函数所属的对象没有直接因果关系。
垃圾回收机制:如果当前执行上下文及其中的代码已经执行完成,且其所有下级执行上下文已经释放,且没有来自当前执行上下文之外的对当前执行上下文的上下文变量容器中的变量的引用,那么当前执行上下文被释放,当前执行上下文的上下文变量容器中的变量指向的对象和this指向的对象的引用值减一(各引擎具体实现不同,这里描述的是原理)。
这也就是Javascript中常用到的闭包模式的原理。如果从传统面向对象语言的角度去看,闭包模式看上去很诡异;但是在理解了Javascript的执行上下文后,闭包模式就是一种很自然的代码编写模式。
4. 原型
由于Javascript中没有类的概念,因此也没有面向对象中的继承的概念。在完全没有任何继承机制的编程语言中,每个对象的方法都要明确设置一遍。假如Javascript没有继承机制,通过构造函数function A(name) {this.name= name;};创建了100个A的对象, 现在要为每个对象实现一个新的方法,就需要明确的为这100个对象都添加一个方法属性,当每个对象都有很多方法的时候,会带来巨大的性能开销和非常差的编码体验,使得代码编写方式最终会倒退到面向过程的方式。
Javascript由面向原型的编程语言self发展而来,通过原型实现了另一种方式的继承:属性共享。如果为了和面向对象中的继承区分,Javascript中通过原型实现的应该叫做共享。
Javascript中的原型在物理上是一个对象,可以是任意对象;原型这个词也表示一种机制。
每个对象都可以拥有一个原型,同时这个原型本身还可以有自己的原型,形成一个原型链,直到其原型为null的原型。
当获取对象的一个属性值的时候,先在当前对象的键值对集合中查找这属性,如果找到返回对应的值;如果没有,则在原型对象的键值对集合中查找,如果还没找到,则在原型的原型中查找,以此类推。
通过一个示例来演示原型的使用方法:

上面例子中,PersonPrototype就是原型对象,Person是构造函数,将Person的prototype属性设置为PersonPrototype对象,那么通过new Person创建的所有对象的原型都是PersonPrototype。
通过示例可以看到,修改原型中showMyName方法的定义,p.showMyName()的输出也会跟着发生变化,这个现象和上面原型的定义一致。
如果明确的为对象p设置一个showMyName方法,那么p对象的键值对集合中将也包含showMyName的定义,根据上面规则的描述的规则,p对象中定义的showMyName将被使用,忽略了原型中对showMyName的定义。这个时候,我们可以通过p.__proto__.showMyName来访问原型中的showMyName方法,但是调用p.__proto__.showMyName的时候,this关键字绑定到了原型对象PersonPrototype,由于原型对象中没有name属性的定义,因此输出“undefined!”。
接下来再定义几个Person对象:

在上述代码中,所有Person对象都共享了原型对象的方法,除非某个Person对象中重新定义了原型中同名的方法。
在对象中定义与原型中同名的属性时,会在该对象中创建一个新的键值对,而不会覆盖原型中同名属性的值。
一般来说原型对象中通常定义方法和常量,不应该定义对象的状态值,因为多数情况下所有的对象共享一个状态值没有实际意义。比如上面的代码中,name属性在逻辑上不应该被定义在原型中,因为每个人都有自己的名字。
方法是最适合定义在原型中的。共享方法给所有的对象,正是原型的主要作用。
5. 结论
本文介绍了Javascript的三个核心概念:对象、执行上下文和原型。这些是Javascript最重要的内容,理解这三点之后,很快就能掌握Javascript。
Javascript代码中各类表达式与Java基本相同。
Javascript包括很多预定义的类型、对象和对象属性,比如全局对象及其属性,JSON类型和RegExp类型等等,这些查阅手册即可。
当然,还有很多细节性的东西,例如:如果不明确设置Person的原型,该原型默认会是一个Person类型的对象;constructor属性的作用。有机会将在后续章节中展开讨论。
Javascript本质第一篇:核心概念的更多相关文章
- Javascript本质第二篇:执行上下文
在上一篇文章<Javascript本质第一篇:核心概念>中,对Javascript执行上下文做了解释,但是这些都是基于Javascript标准中对执行上下文的定义,也就是说理论上的东西,本 ...
- 学习 JavaScript (四)核心概念:操作符
JavaScript 的核心概念主要由语法.变量.数据类型.操作符.语句.函数组成,前面三个上一篇文章已经讲解完了.后面三个内容超级多,这篇文章主要讲解的是操作符. 操作符 什么叫做操作符? 这是一种 ...
- 学习 JavaScript (三)核心概念:语法、变量、数据类型
JavaScript 的核心概念主要由语法.变量.数据类型.操作符.语句.函数组成,这篇文章主要讲解的是前面三个,后面三个下一篇文章再讲解. 01 语法 熟悉 JavaScript 历史的人应该都知道 ...
- vue-learning:40 - Vuex - 第一篇:概念和基本使用
vuex 第一篇 目录 vuex概念 state / mapState getter / mapGetter mutation / mapMutation action / mapAction mod ...
- Vue入门教程 第一篇 (概念及初始化)
注:为了本教程的准确性,部分描述引用了官网及网络内容. 安装Vue 1.使用npm安装vue: npm install vue 2.下载使用js文件: https://vuejs.org/js/vue ...
- 学习 JavaScript (六)核心概念:函数
基本知识 函数对于我们来说,不算陌生的东西.中学就已经有了函数的概念,比如: y = f(x) 输入一个数 x,能够得到与之对应的一个数 y.也就是说,f(x) 的有一个返回值,这是函数在数学上的定义 ...
- 学习 JavaScript (五)核心概念:语句
语句 语句被称作是流控制语句,通常有标志性的一个或者多个关键字,if . do-while. while.for. for-in. label. break.continue.with.switch. ...
- JavaScript学习第一篇
在学习之前让我们了解了解JavaScript的由来 Javascript是一种web技术,最初起名叫LiveScript,它是Netscape开发出来一种脚本语言,其目的是为了扩展基本的Html的功能 ...
- android学习第一篇 基本概念
一. 1. Android 四大組件 Activity , Service , BroadcastReceiver ,ContentProvider 2. 多個Activity組成棧,當前A ...
随机推荐
- 图文介绍如何在Eclipse统计代码行数(转)
使用Eclipse可以方便的统计工程或文件的代码行数,方法如下: 1.点击要统计的项目或许文件夹,在菜单栏点击Search,然后点击File... 2.选中正则表达式(Regular expressi ...
- 记一次在java中的日期parse错误
String dateString = "2014101517"; new SimpleDateFormat("yyyyMMddHH").parse(dateS ...
- Keras官方Example里Mnist-cnn的调试运行
问题:老板让测试运行Keras官网里的Mnist-cnn.py,结果从下载数据就是一路坑-- 当前环境:Ubuntu12.04.python2.7.Keras 1.1.1(不知道这个版本号对不对,在启 ...
- 写给Git初学者的7个建议
[原文] - http://blog.jobbole.com/50603/ 当我刚刚开始使用Git的版本控制时,我根本不确定我付出那么多时间是不是会得到回报.Branch.Stage.Stash,这些 ...
- [翻译] ORMLite document -- Getting Started
前言 此文档翻译于第一次学习 ORMLite 框架,如果发现当中有什么不对的地方,请指正.若翻译与原文档出现任何的不相符,请以原文档为准.原则上建议学习原英文文档. ----------------- ...
- 一个快速排序(分类)及使用类似思想实现选择问题[c++实现]
一.快速排序(快速分类)算法: 问题描述:给定线性集中n个元素和一个整数k,1<=k<=n,要求找出这n个元素中第k小的元素. 思想:选取数组A中的某个元素 t=A[s],然后将其他元素重 ...
- 2016-1-29 图解HTTP(04)
第7章 确保Web安全的HTTPS 在HTTP协议中有可能存在信息窃听或身份伪装等安全问题.使用HTTPS通信机制可以有效的防止这些问题. 7.1 HTTP的缺点 ● 通信使用明文(不加密),内容可能 ...
- C程序语法(无左递归)
<程序> -〉 <外部声明> | <函数定义><外部声明> -〉<头文件> | <变量> | <结构体> <头 ...
- Jstack Jmap jstat
jstack jmap jstat 代码,这里以这个为例怎样使用jstack诊断Java应用程序故障 public class DeadLock { public static void main(S ...
- BZOJ2498 : Xavier is Learning to Count
考虑容斥,通过$Bell(p)$的时间枚举所有等价情况. 对于一种情况,强制了一个等价类里面的数都要相同,其它的可以相同也可以不同. 这方案数显然可以通过多项式乘法求得,乘上容斥系数$(-1)^{p- ...