一、JavaScript介绍
JavaScript是目前所有主流浏览器上唯一支持的脚本语言,这也是早期JavaScript的唯一用途。其主要作用是在不与服务器交互的情况下修改HTML页面内容,因此其最关键的部分是DOM(文档对象模型),也就是HTML元素的结构。通过Ajax可以使HTML页面通过JavaScript,在不重新加载页面的情况下从服务器上获取数据并显示,大幅提高用户体验。通过JavaScript,使Web页面发展成胖客户端成为可能。
语言的性质
本节对JavaScript的性质做简要介绍,以帮你理解一些疑问。
JavaScript和ECMAScript(JavaScript versus ECMAScript)
编程语言称为JavaScript,语言标准被称为ECMAScript。他们有不同名字的原因是因为“Java”已经被注册为商标(属于Oracle)。目前,只有Mozilla被正式允许使用“JavaScript”名称,因为很久以前他们得到一份许可。因此,开放的语言标准拥有不同的名字。当前的JavaScript版本是ECMAScript 6,ECMAScript 7当前是开发版。
JavaScript之父,Brendan Eich迅速了创建一门编程语言。(否则,Netscape将使用其他技术)。他借鉴了几门其他语言的一些特性:
- JavaScript借鉴了Java的语法和如何区分原始值和对象。
- JavaScript的函数设计受Scheme和AWK的启发——他们(的函数)都是第一类(first-class)对象,并且在语言中广泛使用。闭包使他们(函数)变成强大的工具。
- Self影响了JavaScript独一无二的面向对象编程(OOP)风格。它的核心思想(在这里我们没有提到)非常优雅,基于此创建的语言非常少。但后面会提到一个简单的模式照顾大部分用例。JavaScript面向对象编程的杀手级特性是你可以直接创建对象。不需要先创建类或其他类似的东西。
- Perl和Python影响了JavaScript字符串,数组和正则表达式的操作。
JavaScript在最初的时候并不是一个完善的语言,因此也导致JavaScript遗留了很多令人诟病的问题。在开发稍大规模的应用时会显得力不从心,但是由于JavaScript本身是一种非常灵活的语言,因此在它的基础上开发程序库比较容易,因此出现了一大批非常优秀的第三方库,如jQuery,ExtJS,underscorejs,backbone等等,由于这些第三方库,JavaScript变得非常简单。其中jQuery的使用非常广泛,它大幅简化了DOM和Ajax,已经成为了很多网站的标配。jQuery虽然基于JavaScript,但它提供了另外一种编程范式,也就是逻辑式编程,与SQL和正则表达式类似。
JavaScript能做什么

如上图,JavaScript作为Github上最流行、最火的编程语言,几乎无所不能。这里是PuYart的关于JavaScript就要统治世界了的文章,可以让我们了解JavaScript到底能做什么的一些介绍。
- Web前端(各种前端工具类库、前端框架、动画效果、数据可视化等)
- 服务端开发(Node.js)
- 移动应用或者Hybrid App(Cordova)
- 桌面应用(NW.js、Electron)
- 游戏(Unity3D、Cocos2d-js、Pomelo)
- VR(JavaScript在VR世界的应用)
- 硬件、嵌入式物联网等(Tessel:用JavaScript做嵌入式开发)
- 操作系统(NodeOS)
Atwood’s Law: any application that can be written in JavaScript, will eventually be written in JavaScript.(Atwood定律:凡是能用JavaScript写出来的,最终都会用JavaScript写出来。)
二、 JavaScript语法
语句和表达式
了解JavaScript的语法,先来了解两个主要的语法类型:语句和表达式。
- 语句通常是“做某些事情”。程序是一组语句的序列。举个例子,下面声明(创建)一个变量 foo:
| 1 | var foo; | 
- 表达式是产生“值”。他们通常位于赋值操作的右边、函数参数等。举个例子:
| 1 | 3 * 7 | 
语句和表达式之间的区别最好通过实例说明,JavaScript(像Java)有两种不同的方式实现if-then-else。一种是用语句:
| 1 | var x; | 
另一种是表达式:
| 1 | var x = y >= 0 ? y : -y; | 
你可以将后者作为函数参数(但前者不行):
| 1 | myFunction(y >= 0 ? y : -y) | 
最后,每当JavaScript期待一个语句,你也可以用一个表达式代替。例如:
| 1 | foo(bar(7, 1)); | 
foo(...);是一个语句(也叫做表达式语句),bar(7, 1)则是一个表达式。他们都实现函数调用。
流程控制语句和语句块
流程控制语句,其语句体可以是单条语句。举两个例子:
| 1 | if (obj !== null) obj.foo(); | 
然而,任何语句总能被语句块代替,花括号包含零或多条语句。因此,你也可以这样写:
| 1 | if (obj !== null) { | 
为便于程序的阅读和维护,推荐使用后一种方式,即语句块方式。
分号
JavaScript中的分号是可选的。但省略(分号)可能会带来意想不到的结果,所以我建议还是写上分号。
正如上面所看到的,分号作为语句的结尾,但语句块不需要。仅有一种情况下你能看到语句块后面有分号——函数表达式后面的函数体块。表达式作为语句的结尾,后面是分号:
| 1 | var x = 3 * 7; | 
注释
JavaScript的注释有两种形式:单行注释和多行注释。单行注释以//开头,以换行符结尾:
| 1 | x++; // 单行(single-line)注释 | 
多行注释用/**/包裹
| 1 | /* | 
三、变量和赋值
JavaScript中的变量在使用前必须先声明,否则会报错引用错误(Reference Error):
| 1 | var foo; // 声明变量“foo” | 
赋值
你可以在声明变量的同时为其赋值:
| 1 | var foo = 6; | 
你也可以给已经存在的变量重新赋值:
| 1 | foo = 4; // 更改变量的值 | 
复合赋值操作符
有很多复合赋值操作符,例如+=。下面的两个赋值操作等价:
| 1 | x += 1; | 
标识符和变量名
标识符就是事物的名字,在JavaScript中他们扮演不同的语法角色。例如,变量的名称是一个标识符。
大体上,标识符的第一个字符可以是任何Unicode字符、美元标志符($)或下划线(_)。后面可以是任意字符和数字。因此,下面全是合法的标识符:
| 1 | arg0 | 
注意:首字符不能是数字,如果是数字的话,该如何区分是数字还是变量呢?
一些标识符是“保留关键字”——他们是语法的一部分,不能用作变量名。从技术上讲,下面三个标识符不是保留字,但也不应该作为变量名:
| 1 | Infinity NaN undefined | 
四、值
JavaScript有所有我们期待的编程语言值类型:布尔,数字,字符串,数组等。JavaScript中的所有值都有属性。每个属性有一个键(或名字)和一个值。你可以使用点(.)操作符读取属性:
| 1 | value.propKey | 
举个例子:字符串abc有属性lenght(长度)
| 1 | var str = 'abc'; | 
上面的代码也可以写成下面这样:
| 1 | 'abc'.length // 得到3 | 
点操作符也可以用来给属性赋值:
| 1 | var obj = {}; // 空对象 | 
你也可以通过它(.)调用方法:
| 1 | 'hello'.toUpperCase(); // 得到HELLO | 
上面,我们在值hello上面调用方法toUpperCase()。
原始类型值和对象
JavaScript定义了不同值之间的区别:
- 原始值包括:boolean,number,string,null和undefined。
- 所有其他的值都是对象。实际上对象被定义为——所有不为原始值的值。
两者之间的主要区别在于他们是如何被比较的:每一个对象有一个独一无二的标志,并且仅和自己相等:
| 1 | var obj1 = {}; // 一个空对象 | 
相反,所有原始值只要编码值相同就被认为是相同的:
| 1 | var prim1 = 123; | 
原始类型值
下面全是原始类型值(简称:原始值):
- 布尔类型:true,false 
- 数字类型:1736,1.351 
- 字符串类型: ‘abc’,”abc” 
- 两个“无值(non-values)”:undefined,null 
 原始值的特征:
- 值做比较时,“内容”做比较。 
| 1 | 3 === 3 // true | 
- 无法更改:值的属性无法更改,无法添加和移除属性,获取未知属性总返回undefined。
| 1 | var str = 'abc'; | 
对象
对象的类型
所有非原始值的值都是对象。最常见的几种对象类型是:
- 简单对象(类型是Object)能通过对象字面量创建:
| 1 | { | 
上面的对象有两个属性:firstName属性的值是“Jane”,lastName属性的值是“Doe”。
- 数组(类型是Array)能通过数组字面量创建:
| 1 | [ ‘apple’, ‘banana’, ‘cherry’ ] | 
上面的数组有三个元素,可以通过数字索引访问。例如“apple”的索引是0。
- 正则表达式对象(类型是RegExp)能通过正则表达式字面量创建。
| 1 | /^a+b+$/ | 
对象的特征
- 比较的是引用:比较的是标识符,每个值有自己的标识符。
| 1 | {} === {} // 两个不同的空对象, false | 
- 默认可以更改。
| 1 | var obj = {}; | 
所有的数据结构(如数组)都是对象,但并不是所有的对象都是数据结构。例如:正则表达式是对象,但不是数据结构。
undefined 和 null
JavaScript有两个“无值)”:undefined和null。
undefined的意思是“没有值”。未初始化的变量是undefined:
| 1 | var foo; | 
读取不存在的属性时,将返回undefined:
| 1 | > var obj = {}; // 空对象 | 
缺省的参数也是undefined:
| 1 | function f(x) { | 
null的意思是“没有对象”。它被用来表示对象的无值(参数,链上的对象等)。
通常情况下你应该把undefined和null看成是等价的,如果他们代表相同意义的无值的话。检查他们的一种方式是通过严格比较:
| 1 | if (x === undefined || x === null) { | 
另一种在实际中使用的方法是认为undefined 和 null 都是false:
| 1 | if (!x) { | 
警告:false,0,NaN 和 “” 都被当作false。
包装类型
对象类型的实例Foo(包括内建类型,例如Array和其他自定义类型)从对象Foo.prototype上获取方法。你可以通过读取这个方法的方式(不是调用)验证这点:
| 1 | [].push === Array.prototype.push // true | 
相反,原始类型是没有类型的,所以每个原始类型有一个关联类型,称之为包装类型:
- 布尔值的包装类型是 Boolean。布尔值从Boolean.prototype上获取方法:
| 1 | > true.toString === Boolean.prototype.toString //true | 
注意:包装类型名字的首字母是大写的B。如果在JavaScript中布尔值的类型可以访问,那么它可能会被转换为布尔对象。
- 数字值的包装类型是Number。
- 字符串值的包装类型是String。
包装类型也有实例(他们的实例是对象),但不常用。相反,包装类型有其他用处:如果你将他们作为函数调用,他们可以将值转换为原始类型。
| 1 | Number('123') //123 | 
通过typeof和instanceof将值分类
有两个操作符可以用来将值分类:typeof主要用于原始值,instanceof主要用于对象。
typeof 使用方法如下:
typeof «value»
typeof返回描述value“类型”的一个字符串。例如:
| 1 | typeof true //'boolean' | 
下面列出了typeof操作的所有结果:
| 1 | 操作数 结果 | 
有两个结果和我们上面说的的原始值与对象是矛盾的:
- 函数的类型是function而不是object。因为函数(类型为“function”)是对象(类型是对象)的子类型,这不是一个错误。
- null的类型是- object。这是一个bug,但从没被修复,因为修复后会破坏现有的代码。
instanceof使用方法如下:
«value» instanceof «Constr»
如果value是一个对象,并且value 是由构造函数Constr创建的(参考:类)。例如:
| 1 | var b = new Bar(); // 通过构造函数Bar创建对象 | 
深入阅读
五、布尔
布尔类型原始值包括true和false。下面的操作符会得到布尔值:
- 二元逻辑运算符:&&(与),||(或)
- 前缀逻辑运算符:!(非)
- 等值运算符:=== !== == !=
- 比较运算符(字符串或数字):> >= < <=
真值和假值
每当JavaScript希望一个布尔值时(例如:if语句的条件),可以使用任何值。它将被理解(转换)为true或false。下面的值被理解为false:
- undefined, null
- 布尔: false
- 数字: 0, NaN
- 字符串: ‘’
所有其他值被认为true。被理解为false的值称为假值,被理解为true的值称为真值。可以使用Boolean作为函数,测试值被理解为什么。
| 1 | Boolean(undefined) //false | 
二元逻辑运算符
JavaScript中的二元逻辑运算符是短路运算——如果第一个操作数可以确定结果,第二个操作数将不被验证(运算)。例如,在下面的代码中,函数foo()永远不会被调用。
| 1 | false && foo() | 
此外,二元逻辑运算符会返回操作数中的一个,可能是一个布尔值,也可能不是。
- 与:如果第一个操作数是假值,返回第一个。否则返回第二个操作数。
| 1 | NaN && 'abc' //NaN | 
- 或:如果第一个操作数是真值,返回第一个。否则,返回第二个操作数。
| 1 | 'abc' || 123 //'abc' | 
等值运算符
在JavaScript中检测相等,你可以使用严格相等(===)和严格不等(!==)。或者你也可以使用非严格相等(==)和非严格不等(!=)。
经验规则:总是用严格运算符,假装非严格运算符不存在。严格相等更安全。
深入阅读
六、数字
JavaScript中的所有数字都是浮点型(虽然大部分的JavaScript引擎内部也使用整数)。至于为什么这样设计,查看这里(每一个JavaScript开发者应该了解的浮点知识)。
| 1 | 1 === 1.0 //true | 
特殊数字:
- NaN(“不是一个数字 not a number”): 错误值。
| 1 | Number('xyz') // 'xyz' 不能被转换为数字得到:NaN | 
- Infinity:也是最大错误值(无穷大)
| 1 | 3 / 0 //Infinity | 
Infinity有时很有用,因为它比任何其他数字都大。同样,-Infinity 比其他任何数字都小。
- JavaScript有两个零,- +0和- -0。它(js引擎)通常不让你看到,并简单将两个零都显示为0:
| 1 | +0 //0 | 
因此最好假装只有一个零(正如我们看到假值时所做的那样:**-0 和 +0 都是假值**)。
运算符
JavaScript中有下列算数运算符:
| 1 | 加: number1 + number2 | 
全局对象Math通过函数提供更多算数运算操作。
JavaScript中也有位运算符(例如:&)。
七、字符串
字符串可以直接通过字符串字面量创建。这些字面量被单引号或双引号包裹。反斜线(\)转义字符并且产生一些控制字符。例如:
| 1 | 'abc' | 
可以通过方括号访问单个字符:
| 1 | var str = 'abc'; | 
length属性是字符串的字符数量。
| 1 | 'abc'.length //3 | 
提醒:字符串是不可变的,如果你想改变现有字符串,你需要创建一个新的字符串。
字符串运算符
字符串可以通过加号操作符(+)拼接,如果其中一个操作数为字符串,会将另一个操作数也转换为字符串。
| 1 | var msgCount = 3; | 
连续执行拼接操作可以使用+=操作符:
| 1 | var str = ''; | 
字符串方法
字符串有许多有用的方法。例如:
| 1 | 'abc'.slice(1) // 复制子字符串,得到索引1及其之后的字符串,即:'bc' | 
八、语句
条件(Conditionals)
if语句通过布尔条件决定执行那个分支:
| 1 | if (myvar === 0) { | 
下面的switch语句,furit的值决定那个分支被执行。
| 1 | switch (fruit) { | 
循环(Loops)
for 循环的格式如下:
| 1 | for(初始化; 当条件成立时循环; 下一步操作) | 
例子:
| 1 | for (var i=0; i < arr.length; i++) { | 
当条件成立时while循环继续循环它的循环体。
| 1 | // 和上面的for循环相等 | 
当条件成立时,do-while循环继续循环。由于条件位于循环体之后,所以循环体总是被至少至少执行一次。
| 1 | do { | 
在所有的循环中:
- break中断循环
- continue开始一个新的循环迭代
九、函数
定义函数的一种方法是通过函数声明:
| 1 | function add(param1, param2) { | 
上面的代码定义一个名称叫做add的函数,有两个参数param1和param2,并且返回参数的和。下面是如何调用这个函数:
| 1 | add(6, 1) //7 | 
另一种定义add()函数的方法是通过函数表达式:
| 1 | var add = function (param1, param2) { | 
函数表达式产生一个值,因此可以直接将函数作为参数传递给其他函数:
| 1 | someOtherFunction(function (p1, p2) { ... }); | 
函数声明提升
函数声明会被提升,他们全被移动到当前作用域开始之处。这允许你在函数声明之前调用它们:
| 1 | function foo() { | 
注意:虽然变量声明也会被提升,但赋值的过程不会被提升:
| 1 | function foo() { | 
特殊变量参数
在JavaScript中你可以调用任意函数并传递任意数量的参数——语言绝不会“抱怨”(参数检测)。都可以正常工作,然而,使所有参数可访问需要通过特殊变量arguments。arguments看起来像数组,但它没有数组的方法(称为类数组 array-like)。
| 1 | function f() { return arguments } | 
太多或太少参数
让我们通过下面的函数探索JavaScript中传递太多或太少参数时如何处理
| 1 | function f(x, y) { | 
多出的参数将被忽略(可以通过arguments访问):
| 1 | f('a', 'b', 'c') //a b | 
缺少的参数将会是undefined:
| 1 | f('a') //a undefined | 
可选参数
下面是一个常见模式,给参数设置默认值:
| 1 | function pair(x, y) { | 
在(*)这行,如果x是真值(除了:null,undefined 等),         操作符返回x。否则,它返回第二个操作数。
| 1 | pair() //[ 0, 0 ] | 
强制数量
如果你想强制参数的数量,你可以检测arguments.length:
| 1 | function pair(x, y) { | 
将arguments 转换为数组
arguments不是一个数组,它仅仅是类数组(array-like):它有一个length属性,并且你可以通过方括号索引方式访问它的元素。然而,你不能移除元素,或在它上面调用任何数组方法。因此,有时你需要将其转换为数组。这就是下面函数的作用。
| 1 | function toArray(arrayLikeObject) { | 
十、异常处理
异常处理最常见的方式像下面这样:
| 1 | function throwException() { | 
try分支包裹易出错的代码,如果try分支内部抛出异常,catch分支将会执行。
十一、严格模式
严格模式开启检测和一些其他措施,使JavaScript变成更整洁的语言。推荐使用严格模式。为了开启严格模式,只需在JavaScript文件或script标签第一行添加如下语句:
| 1 | ; | 
你也可以在每个函数上选择性开启严格模式,只需将上面的代码放在函数的开头:
| 1 | function functionInStrictMode() { | 
下面的两小节看下严格模式的三大好处。
明确错误
让我们看一个例子,严格模式给我们明确的错误,否则JavaScript总是静默失败:下面的函数f() 执行一些非法操作,它试图更改所有字符串都有的只读属性——length:
| 1 | function f() { | 
当你调用上面的函数,它静默失败,赋值操作被简单忽略。让我们将f()在严格模式下运行:
| 1 | function f_strict() { | 
现在浏览器报给我们一些错误:
| 1 | f_strict() // TypeError: Cannot assign to read only property 'length' of abc | 
不是方法的函数中的this
在严格模式下,不作为方法的函数中的this值是undefined:
| 1 | function f_strict() { | 
在非严格模式下,this的值是被称作全局对象(global object)(在浏览器里是window):
| 1 | function f() { | 
不再自动创建全局变量
在非严格模式下,如果你给不存在的变量赋值,JavaScript会自动创建一个全局变量:
| 1 | function f() { foo = 5 } | 
在严格模式下,这会产生一个错误:
| 1 | function f_strict() { 'use strict'; foo2 = 4; } | 
深入阅读
十二、变量作用域和闭包
在JavaScript中,你必须使用变量之前,通过var声明变量:
| 1 | var x; | 
你可以用一条var语句声明和初始化多个变量:
| 1 | var x = 1, y = 2, z = 3; | 
但我建议每个变量使用一条语句。因此,我将上面的语句重写为:
| 1 | var x = 1; | 
由于提升(见下文),最好在函数顶部声明变量。
变量和函数作用域
变量的作用域总是整个函数(没有块级作用域)。例如:
| 1 | function foo() { | 
我们可以看到tmp变量不仅在(*)所在行的语句块存在,它在整个函数内都存在。
变量提升
变量声明会被提升:声明会被移到函数的顶部,但赋值过程不会。举个例子,在下面的函数中(*)行位置声明了一个变量。
| 1 | function foo() { | 
在内部,上面的函数被执行像下面这样:
| 1 | function foo() { | 
闭包
每个函数保持和函数体内部变量的连接,甚至离开创建它的作用域之后。例如:
| 1 | function createIncrementor(start) { | 
在(*)行开始的函数在它创建时保留上下文,并在内部保存一个start活动值:
| 1 | var inc = createIncrementor(5); | 
闭包是一个函数加上和其作用域链的链接。因此,createIncrementor()返回的是一个闭包。
IIFE:模拟块级作用域
有时你想模拟一个块,例如你想将变量从全局作用域隔离。完成这个工作的模式叫做 IIFE(立即执行函数表达式(Immediately Invoked Function Expression)):
| 1 | (function () { // 块开始 | 
上面你会看到函数表达式被立即执行。外面的括号用来阻止它被解析成函数声明;只有函数表达式能被立即调用。函数体产生一个新的作用域并使tmp变为局部变量。
闭包实现变量共享
下面是个经典问题,如果你不知道,会让你费尽思量。因此,先浏览下,对问题有个大概的了解。
闭包保持和外部变量的连接,有时可能和你想像的行为不一致:
| 1 | var result = []; | 
(*)行的返回值总是当前的i值,而不是当函数被创建时的i值。当循环结束后,i的值是5,这是为什么数组中的所有函数的返回值总是一样的。如果你想捕获当前变量的快照,你可以使用IIFE:
| 1 | for (var i=0; i < 5; i++) { | 
深入阅读
十三、对象和继承
和所有的值类型一样,对象有属性。事实上,你可以将对象当作一组属性的集合,每个属性都是一对(键和值)。键是字符串,值可以是任意JavaScript值。到目前为止,我们仅仅见过键是标识符的属性,因为点操作符处理的键必须为标识符。在这节,你讲见到另一种访问属性的方法,能将任意字符串作为键。
单个对象
在JavaScript中,你可以直接创建对象,通过对象字面量:
| 1 | var jane = { | 
上面的对象有两个属性:name和describe。你能读(“get”)和 写(“set”)属性:
| 1 | jane.name // get,'Jane' | 
属性是函数如describe可以被当作方法调用。当调用他们时可以在它们内部通过this引用对象。
| 1 | jane.describe() // 调用方法,'Person named John' | 
in操作符用来检测一个属性是否存在:
| 1 | 'newProperty' in jane // true | 
若读取一个不存在的属性,将会得到undefined值。因此上面的两个检查也可以像下面这样:
| 1 | jane.newProperty !== undefined // true | 
delete操作符用来删除一个属性:
| 1 | delete jane.newProperty //true | 
任意键属性
属性的键可以是任意字符串。到目前为止,我们看到的对象字面量中的和点操作符后的属性关键字。按这种方法你只能使用标识符。如果你想用其他任意字符串作为键名,你必须在对象字面量里加上引号,并使用方括号获取和设置属性。
| 1 | var obj = { 'not an identifier': 123 }; | 
方括号允许你动态计算属性关键字:
| 1 | var x = 'name'; | 
引用方法
如果你引用一个方法,它将失去和对象的连接。就其本身而言,函数不是方法,其中的this值为undefined(严格模式下)。
| 1 | var func = jane.describe; | 
解决办法是使用函数内置的bind()方法。它创建一个新函数,其this值固定为给定的值。
| 1 | var func2 = jane.describe.bind(jane); | 
方法内部的函数
每个函数都有一个特殊变量this。如果你在方法内部嵌入函数是很不方便的,因为你不能从函数中访问方法的this。下面是一个例子,我们调用forEach循环一个数组:
| 1 | var jane = { | 
调用logHiToFriends会产生错误:
| 1 | jane.logHiToFriends() // TypeError: Cannot read property 'name' of undefined | 
有两种方法修复这问题。
- 将this存储在不同的变量。
| 1 | logHiToFriends: function () { | 
- forEach的第二个参数允许提供this值。
| 1 | logHiToFriends: function () { | 
在JavaScript中函数表达式经常被用作函数参数。时刻小心函数表达式中的this。
构造函数:对象工厂
除了作为“真正”的函数和方法,函数还在JavaScript中扮演第三种角色:如果通过new操作符调用,他们会变为构造函数,对象的工厂。构造函数是对其他语言中的类的粗略模拟。约定俗成,构造函数的第一个字母大写。例如:
| 1 | // 设置实例数据 | 
我们看到构造函数分为两部分:首先,Point函数设置实例数据。其次,Point.prototype属性包含对象的方法。前者的数据是每个实例私有的,后面的数据是所有实例共享的。
我们通过new操作符调用Point:
| 1 | var p = new Point(3, 5); | 
p是Point的一个实例:
| 1 | p instanceof Point //true | 
深入阅读
十四、数组
数组是数组元素的序列,能通过整数索引方法数组元素,数组索引从0开始。
数组字面量
数组字面量创建数组很方便:
| 1 | > var arr = [ 'a', 'b', 'c' ]; | 
上面的数组有三个元素:分别是字符串“a”,“b”, “c”。你可以通过整数索引访问它们:
| 1 | arr[0] //'a' | 
length属性总表示一个数组有多少项元素。
| 1 | arr.length //3 | 
除此之外它也可以用来从数组上移除尾部元素:
| 1 | arr.length = 2; | 
in操作符也可以在数组上工作。
| 1 | 1 in arr // arr在索引为1处是否有元素?,true | 
值得注意的是数组是对象,因此可以有对象属性:
| 1 | arr.foo = 123; | 
数组方法
数组有许多方法。举些例子:
| 1 | var arr = [ 'a', 'b', 'c' ]; | 
遍历数组
有几种方法可以遍历数组元素。其中两个最重要的是forEach和map。
forEach遍历整个数组,并将当前元素和它的索引传递给一个函数:
| 1 | [ 'a', 'b', 'c' ].forEach(function (elem, index) { // (*) | 
上面代码的输出
| 1 | 0. a | 
注意(*)行的函数参数是可省略的。例如:它可以只有一个参数elem。
map创建一个新数组,通过给每个存在数组元素应用一个函数:
| 1 | [1,2,3].map(function (x) { | 
深入阅读
十五、正则表达式
JavaScript内建支持正则表达式。他们被双斜线分隔:
| 1 | /^abc$/ | 
方法 test():测试是否匹配
| 1 | /^a+b+$/.test('aaab') // true | 
方法 exec():匹配和捕获组
| 1 | /a(b+)a/.exec('_abbba_aba_') // [ 'abbba', 'bbb' ] | 
返回的数组第一项(索引为0)是完整匹配,捕获的第一个分组在第二项(索引为1),等。有一种方法可以反复调用获取所有匹配。
方法 replace():搜索并替换
| 1 | '<a> <bbb>'.replace(/<(.*?)>/g, '[$1]') // '[a] [bbb]' | 
replace的第一个参数必须是正则表达式,并且开启全局搜索(/g标记),否则仅第一个匹配项会被替换。有一种方法使用一个函数来计算替换项。
十六、数学
Math是一个有算数功能的对象。例如:
| 1 | Math.abs(-2) // 2 | 
十七、标准库的其他功能
JavaScript标准库相对简单,但有很多其他东西你可以使用:
Date:日期构造函数,主要功能有转换和创建日期字符串,访问日期组成部分(年,小时等)。
JSON:一个对象,功能是转换和生成JSON数据。
console.*方法:浏览器的具体方法,不是语言成分的部分,但他们也可以在Node.js中工作。
十八、下一步学什么?
在你学会了这篇文章的基础教程后,你可以转到大部分章节末尾提到的高级教程。此外,我建议你看下面的资源:
- Style guides: I have written a guide to style guides
- Underscore.js: 一个弥补JavaScript标准库缺少的功能的库
- JSbooks – free JavaScript books
- Frontend rescue: how to keep up to date on frontend technologies
- http://yanhaijing.com 当然还有我的博客也非常不错哦
- http://yanhaijing.com/es5 如果你想成为高手,我建议阅读ecmascript规范
- 给javascript初学者的24条最佳实践
- 我希望我知道的七个JavaScript技巧
参考自原文:http://www.2ality.com/2013/06/basic-javascript.html
参考自译文:http://yanhaijing.com/basejs/
本文章由blinkfox原创,本站仅仅为学习转发
 
                     
                     
                        
                        