JS 语法快速参考

本文最后更新于 2021年4月4日 晚上

这篇文章主要是收集 JS 的语法, 以供日后查询, 绝大部分参考的是MDN 有关 JS 的帮助文档里面的内容.

简介

JS 只是一种 ECMA 标准的实现.

语法

  1. 声明: 使用如下的声明方式
  • var: 变量声明时使用.

  • let: 局部变量声明使用

  • const: 局部常量声明使用.

JS 中在任何函数外部定义的变量就是全局变量, 在函数内就是局部变量.

  1. 关于undefinednull:

可以使用 undefined 来判断当前变量是否有值. 另外在布尔判断中, 它表示的是 false 的含义.

另外如果在数值表达式中使用 undefined 的变量, 则会产生一个 NaN 结果:

1
2
var a; // undefined
a + 2; // 值是 NaN

null 代表的是 0 值, 并且在数值表达式中使用 null 还会产生计算结果, 我了个擦.

1
2
var n = null;
n * 32; // 值是 0
  1. 关于作用域:

在 ECMA 2015(ECMA 6) 之前, 是没有块作用域的, 不过 ECMA 2015 之后添加了, 故使用 let 在块作用域内定义变量.

  1. 关于全局变量:

全局变量实际上是一个 全局对象(global object) 的属性, 如果是在网页中, 就是 window 对象的属性, 故实际上全局变量可以通过 window.xxx 来访问 xxx 全局变量.

  1. 关于常量(const):

常量在运行时无法被改变, 但常量对象的属性不受此限制, 即可以向 const 定义的对象进行添加属性或改变属性的值等操作.

1
2
const MY_OBJECT = {'key': 'value'};
MY_OBJECT.key = 'otherValue';

另外数组也不受限制:

1
2
3
const MY_ARRAY = ['HTML','CSS'];
MY_ARRAY.push('JAVASCRIPT');
console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];
  1. 数据类型和数据结构:

最新的 ECMA 标准定义了七种数据类型, 包括六种标准类型, 还有一种对象类型(Object).

6 种标准类型如下:

- Boolean: true 或者 false

- null: 空类型

- undefined: 未定义

- Number: 数值类型

- String: 字符串类型

- Symbol: ECMA 2015(ES6) 新增, 代表的是可识别的且不可变数据类型.

JS 是一种动态类型的语言, 故变量可以理解可以具有任何上述类型, 故:

1
2
var answer = 42;
answer = 'Thanks for all the fish...';
另外还有一些奇奇怪怪且有趣的自动类型转换:
1
2
   '37' - 7 // 30
'37' + 7 // "377"
有两种方式可以从字符串获取数值: 第一种是 `parseInt()` 和 `parseFloat()`. 第二种是在前面添加 `+` 号:
1
2
3
'1.1' + '1.1' // '1.11.1'
(+'1.1') + (+'1.1') // 2.2
// Note: the parentheses are added for clarity, not required.
  1. 字面量的赋值详见 MDN 的链接: Literals.

主要是 6 种基本类型的字面量, 以及 Object 类型的字面量. 主要是 Object 字面量是 {} 包裹的, 类似字典的写法, 如下所示:

1
2
3
4
var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales };
console.log(car.myCar); // Saturn
console.log(car.getCar); // Honda
console.log(car.special); // Toyota

另外就是在 ES 2015(ES6) 中, 对象的支持得到极大增强. 具体内容需要进一步探索.

  1. 语句块:
1
2
3
{
// ...
}

在语句块中实际定义了一个块作用域, 在 ES6 之前是没有这个东西的.

在 ES6 之后, let 和 const 量是块作用域的.

  1. 在 JS 中的流程控制语句和 C 系语言都差不多. 只是要注意, 在 JS 中有许多的值可以表示 false:
  • false

  • undefined

  • null

  • 0

  • NaN

  • 空字符串 ""

而其他所有的值, 包括对象, 用在布尔判断中都表示的 true 值. 另外有一个比较让人抓狂的现实是 true 字面量和以 true 为值的 Boolean 对象并不相等:

1
2
3
var b = new Boolean(false);
if (b) // this condition evaluates to true
if (b == true) // this condition evaluates to false

另外注意不要把 swift 的 switch 带到这里, 默认是 fallthrough 的.

  1. 异常处理:

使用 throw 抛出异常, 使用 try...catch 捕捉异常.

可以抛出各种数据类型的异常:

1
2
3
4
throw 'Error2';   // String type
throw 42; // Number type
throw true; // Boolean type
throw {toString: function() { return "I'm an object!"; } };

不过最好还是使用 Error 对象来作为错误载体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function doSomethingErrorProne() {
if (ourCodeMakesAMistake()) {
throw (new Error('The message'));
} else {
doSomethingToGetAJavascriptError();
}
}

try {
doSomethingErrorProne();
} catch (e) {
console.log(e.name); // logs 'Error'
console.log(e.message); // logs 'The message' or a JavaScript error message)
}
  1. ES6 之后在语言中内置了 Promise 对象, 作为异步操作支持, 是一种 Promise 实现.

下面是一个典型用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function imgLoad(url) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = 'blob';
request.onload = function() {
if (request.status === 200) {
resolve(request.response);
} else {
reject(Error('Image didn\'t load successfully; error code:'
+ request.statusText));
}
};
request.onerror = function() {
reject(Error('There was a network error.'));
};
request.send();
});
}
  1. 循环语句在这里可以看到, 有 for-in 语句的, 另外可以使用 for-of 语句来遍历 iterable 量, 比如数组等.

  2. 函数的参数传递时, 如果是 6 种基本类型, 是按值传递的, 而如果是对象, 则是传递的引用, 比如数组或用户自定义对象.

函数可以定义为函数表达式, 这个时候就没有函数名而已. 当然也可以提供函数名, 这个时候该名字就可以在该函数内部使用, 比如有递归需求的时候:

1
2
3
4
5
6
var square = function(number) { return number * number; };
var x = square(4); // x gets the value 16

// 带函数名的函数表达式
var factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1); };
console.log(factorial(3));
  1. closure 在 js 中的定义是在函数内部定义的函数, 这样就形成了 closure.

A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that “closes” the expression).

实际就是在描述 closure 可以形成一个上下文环境, 在该上下文中包含其所处的上下文中的变量, 即变量捕捉.

  1. 在任何函数内都有一个特殊的对象, 就是 arguments 对象, 包含的是所有的参数:
1
arguments[i]

这样就可以在不知道有多少个参数传入的情况下处理参数表了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function myConcat(separator) {
var result = ''; // initialize list
var i;
// iterate through arguments
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}

// returns "red, orange, blue, "
myConcat(', ', 'red', 'orange', 'blue');
// returns "elephant; giraffe; lion; cheetah; "
myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
// returns "sage. basil. oregano. pepper. parsley. "
myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
  1. 关于函数参数, 详见函数参数文档. 从 ES6 开始, 可以提供函数参数的默认参数值(如果不提供, 则默认是 undefined):
1
2
3
4
5
function multiply(a, b = 1) {
return a * b;
}

multiply(5); // 5
  1. ES6 之后, 还增加了 rest parameter, 即不定数量的参数表达:
1
2
3
4
5
6
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
  1. ES6 新增了 => 的语法, 和 C# 或 Dart 中都类似, 是一种函数表达.

  2. 限制模式: 启用方法是在脚本文件开头的位置添加如下内容:

1
2
'use strict';
var v = "Hi! I'm a strict mode script!";

关于在限制模式中进行的改变可以看限制模式改变文档.

  1. 在函数中, 默认还存在一个 this 指针, 指向的就是该函数, 实际上这个函数也形成了一个类定义, 但如果是嵌套函数则会存在问题, 故可以使用如下方式避免:
1
2
3
4
5
6
7
8
9
10
11
function Person() {
var self = this; // Some choose `that` instead of `self`.
// Choose one and be consistent.
self.age = 0;

setInterval(function growUp() {
// The callback refers to the `self` variable of which
// the value is the expected object.
self.age++;
}, 1000);
}

另外在箭头表达式中不存在 this 指针:

1
2
3
4
5
6
7
8
9
function Person() {
this.age = 0;

setInterval(() => {// doesn't have a 'this' pointer inside inner function.
this.age++; // |this| properly refers to the person object
}, 1000);
}

var p = new Person();
  1. JS 中的函数默认都形成一个类定义. 它们可以直接通过 new 实例化出对象.

  2. 在 JS 中预定义了许多函数, 这些函数是顶层函数, 详见内置顶层函数.

  3. 操作符文档.

下面是一些比较有趣的内容:

  1. 解构:
1
2
3
4
5
6
7
8
9
var foo = ['one', 'two', 'three'];

// without destructuring
var one = foo[0];
var two = foo[1];
var three = foo[2];

// with destructuring
var [one, two, three] = foo;
  1. 和 swift 一样, 也有 =====, 后者表示严格相等, 具体含义详见文档.

  2. 次方操作符: **, 比如 2 ** 3 结果是 8.

  3. 位操作符也有.

  4. delete 操作符会将对象或对象属性删除, 删除对象后, 指向该对象的变量就变成了 undefined 值, 删除属性也是同理, 如果删除成功的话, 会返回 true.

1
2
3
4
delete objectName;
delete objectName.property;
delete objectName[index];
delete property; // legal only within a with statement
如果在数组上使用 `delete`, 则会将对应下标变为 `undefined`, 而不是减少一个元素这么简单.
  1. typeof 会返回某个类型的字符串表示, 如下所示:
1
2
3
4
5
6
7
8
9
10
11
var myFun = new Function('5 + 2');
var shape = 'round';
var size = 1;
var foo = ['Apple', 'Mango', 'Orange'];
var today = new Date();
typeof myFun; // returns "function"
typeof shape; // returns "string"
typeof size; // returns "number"
typeof foo; // returns "object"
typeof today; // returns "object"
typeof doesntExist; // returns "undefined"
有两个特殊情况:
1
2
typeof true; // returns "boolean"
typeof null; // returns "object"
  1. void 在 js 中是作为一种操作符存在的, 用于表示某个表达式没有返回值, 即 undefined 的返回值.

  2. in 操作符用于判断某个属性名是否在对象中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// where propNameOrNumber is a string, numeric, or symbol expression representing a property name or array index, and objectName is the name of an object.
propNameOrNumber in objectName

// 另外还有一些有趣的用法:

// Arrays
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
0 in trees; // returns true
3 in trees; // returns true
6 in trees; // returns false
'bay' in trees; // returns false (you must specify the index number,
// not the value at that index)
'length' in trees; // returns true (length is an Array property)

// built-in objects
'PI' in Math; // returns true
var myString = new String('coral');
'length' in myString; // returns true

// Custom objects
var mycar = { make: 'Honda', model: 'Accord', year: 1998 };
'make' in mycar; // returns true
'model' in mycar; // returns true
  1. instanceof 用于判断是否是某个类型对象:
1
2
3
4
var theDay = new Date(1995, 12, 17);
if (theDay instanceof Date) {
// statements to execute
}
  1. Number 对象:.
1
2
3
4
5
var biggestNum = Number.MAX_VALUE;
var smallestNum = Number.MIN_VALUE;
var infiniteNum = Number.POSITIVE_INFINITY;
var negInfiniteNum = Number.NEGATIVE_INFINITY;
var notANum = Number.NaN;
  1. Math 对象: 数学计算相关.

  2. Date 对象: 使用 Date 对象进行和日期有关的操作.

  3. JS 中的字符串.

  4. String 对象.

  5. Date and time formatting: 日期和时间的转换.

  6. Number formatting.

  7. Collation.

  8. 正则表达式的文档.

  9. JS 中的数组对象(Array object).

  10. 带有类型的数组(Typed Arrays), 在某些网络操作中, 比如 WebSocket 中很常用, 详见文档.

  11. 字典类型(Map), 详见文档.

  12. 哈希表(Set), 详见文档.

  13. JS 中的对象模型非常简单, 无论是语法上还是概念上, 看下面这段:

1
2
3
4
5
/*
JavaScript is designed on a simple object-based paradigm. An object is a collection of properties, and a property is an association between a name (or key) and a value. A property's value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects.

JS 中的对象就是属性的集合. 属性实际就是一个名字和值的关联, 属性的值可以是函数(这个属性就变成了对象方法).
*/

定义时可以使用函数或 Object 来.

在 js 中的所有对象都继承自至少一个另外的对象, 被继承的对象称为 prototype, 详见文档.

在 JS 中仍然有 setter 和 getter 可以定义, 详见文档.

关于对象模型的相关细节, 详见文档, 这里就引出了对基于 Class 和基于 prototype 的面向对象语言的差别的讨论, 一句话来说, 在基于 prototype 的语言中, 没有类的概念, 只有对象, 而 实际上就是作为 prototype 的对象的描述而已.

这个文档中 通过 JS 实现了一个 employee 的对象体系.

当对象被实例化后, 就会自动拥有一个 __proto__ 属性, 除了 Object 对象外, 每个对象都有一个 __proto__ 属性, 这个属性指向的是该对象的 prototype 对象, 可以理解位指向的父对象.

比如通过 __proto__ 属性, 可以自己实现一个 instanceOf 函数:

1
2
3
4
5
6
7
8
9
10
11
12
function instanceOf(object, constructor) {
object = object.__proto__;
while (object != null) {
if (object == constructor.prototype)
return true;
if (typeof object == 'xml') {
return constructor.prototype == XML.prototype;
}
object = object.__proto__;
}
return false;
}

在 JS 中没有多继承.

  1. JS 中的 Promise 文档, 可以参考一下, 这个是万物之源啊. 另外就是错误传递可以看这个文档.

  2. 在 ECMA 2017 中引入了 async/await 可以极大方便异步编程, 并且可以使用 await 来等待 promise.

  3. 在 JS 中可以使用 yield 懒生产序列.

  4. JS 中从 ECMA 2015 (ES6) 开始, 也引入了元编程和反射, 详见文档.

  5. JS 的面向对象深入.

  6. 虽然说是基于 prototype 的语言, 但在 ES6 中引入了一种 class 语法, 这样可以极大方便从其他语言转过来的开发者, 不过要注意, 这里只是一种语法, 实际上底层还是基于 prototype 的, 而非类, 详见文档.

  7. 关于 JSON, 这个才是正宗的 JSON 介绍!


JS 语法快速参考
https://blog.rayy.top/2019/01/19/2019-38-js-lan/
作者
貘鸣
发布于
2019年1月19日
许可协议