JavaScript 基础语法
JavaScript 是用于实现网页动态效果的一种高级语言。作为一个只使用了10天就被开发出来的语言,具有很多为网络编程而生的特点,以及很多有趣的特性。在这一篇中,对 JavaScript 的基础语法进行介绍。后面还有一篇,对JS操作 HTML 的方法和异步特性进行单独介绍。
1. 变量
JavaScript 是一种 弱类型 或者说 动态语言。所有的变量都使用 var
声明。 这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。这也意味着你可以使用同一个变量保存不同类型的数据。
最新的 ECMAScript 标准中定义了7种原始数据类型如下:
Boolean
-true
或false
Null
- 用 type of 检验 null数据类型时为Object,但它不是对象,这是JS的一个bugUndefined
Number
- JavaScript中的所有数字都是浮点数,没有整数BigInt
String
Symbol
(ES6)
除上述原始类型以外,所有变量都为 Object
类型。
JS 的对象是 若干键值对的无序集合。其中,键(属性名)必须为字符串类型,值可以为任意类型(如果键不是字符串类型,需要使用 Map
)。
重点类型:参考 JavaScript标准内置对象
Object 类型的变量,可以使用继承自 Object.prototype
的方法,例如:is() - 可以用于判断两个 NaN相等, toString()
..
String 类型的变量,可以使用继承自 String.prototype
的方法,例如:charAt(), concat(), slice(), replace()
…
数组类型的变量,可以使用继承自 Array.prototype
的方法,例如:concat(), filter(), forEach(), join(), indexOf()
…
Function 类型的变量,可以使用继承自Function.prototype
的方法,例如:apply(), bind(), call()
…
解构赋值:在变量赋值时,JS 支持解构赋值,也就是按顺序为数组中的多个元素赋值,如下:
1 | // 赋值后,x = hello, y = JavaScript, z = ES6 |
2. 函数
可以以下面两种形式声明函数,例子如下:
1 | function abs(x){ |
参数:传入函数的内容称为参数。 函数声明时,可以用 rest
关键字,接收多传入的关键字,e.g. foo(a, b ...rest)
。函数调用时,JS 可以通过 arguments
关键字,获取传入函数中的参数。
JS 中变量的 作用域 最小为一个函数。而 for(...)
等控制流语句或直接 {... }
构成的程序块不是一个作用域,此时,可以使用 let
关键字,声明改变量仅在该代码块中有效。
方法:在一个对象中绑定函数,该函数称为该对象的方法。需要注意的是,在 JS 中,this
关键字永远指向调用该 his
关键字所在方法的对象。因此,某些情况例如函数嵌套时,内部的嵌套函数就无法获取当前对象。可以使用下面方法解决:
1 | var studentA = { |
更灵活地为函数中的 this
绑定对象,可以使用 函数对象的 apply()
方法。例如:
1 | function getAge() { |
Note: apply()
方法还可以用于实现对原方法的包装(装饰器)。
高阶函数:接收参数为 函数 的函数称为高阶函数。JS 中 Array
的很多方法为高阶函数。例如,map(), reduce(), filter(), sort()
等。在这类函数中,传入的参数可以使用箭头函数,即 =>
, 可简化函数体书写,省略函数名,return
关键字(如果函数体只有一句)。
1 | function pow(x) { |
闭包:函数返回值为函数,这一做法称为闭包(closure)。闭包的一个作用是实现 private 的函数成员变量,如下:
1 | function create_counter(initial) { |
generator 称为生成器,它类似函数,但可以多次”返回”,例子如下:
1 | function* foo(x) { |
生成器执行时,每遇到一次 yield
就会进行一次返回,然后进入暂停状态-暂停至 yield
进行返回的位置处。可以使用 generator 的 next()
方法将其再次唤醒(or 使用 for(var 'yield_value' of 'generator')
的方法,使它自动执行并逐次返回 yield
的内容),从而从暂停处开始继续执行。直到执行至 return
处,generator 才真正执行完毕。
作用:执行中多次返回,‘记住’函数执行状态;把异步回调代码变为‘同步’代码(ref-AJAX part)
3. 面向对象编程
JS 中使用原型(prototype)的概念实现对象之间的继承关系(注意本质上,JS中没有类和类的实例的区别,都是对象实例)。
具体地,通过将对象的原型属性(obj.__proto__
)指向它需要继承的对象,来实现方法的继承。‘类’的编写与写函数一样,但在生成该类型的对象时,需要使用 new
关键字而不是直接调用函数。参考如下的例子:
1 | // tips: 用于构造对象的函数 首字母大写~ |
上述 studentA 对象的原型链如下:studentA ----> Student.prototype ----> Object.prototype ----> null
。
从ES6开始,JS 引入了关键字 class
, 面向对象的实现更加简单了。但需要注意的是,本质上,JS 的继承的内部机制没有变。
使用 class, extends 关键字实现继承的代码例子如下:
1 | class PrimaryStudent extends Student { |
4. 异常处理
类似其他高级语言,JS 中也使用 try ... catch ... finally ...
的形式来处理错误(note: JS 中,程序异常等称为 Error,JS提供一个标准的 Error 对象表示程序错误、异常)。
在 JS 中,需要特别注意的是异步程序执行时,对 Error 的 catch 可能会被跳过。例子如下:
1 | function printTime() { |
由于 printTime
函数延迟1s 执行,执行 printTime
函数时,catch
函数已经被跳过,所以无法再捕获其中的 Error
。因此,对于回调函数中的错误,不可在调用时进行捕获,而应该在回调函数本体内进行捕获。
Ref: