这篇文章主要是收集 JS 的语法, 以供日后查询, 绝大部分参考的是MDN 有关 JS 的帮助文档里面的内容.
简介
JS 只是一种 ECMA 标准的实现.
语法
- 声明: 使用如下的声明方式
-
var: 变量声明时使用.
-
let: 局部变量声明使用
-
const: 局部常量声明使用.
JS 中在任何函数外部定义的变量就是全局变量, 在函数内就是局部变量.
- 关于
undefined和null:
可以使用 undefined 来判断当前变量是否有值. 另外在布尔判断中, 它表示的是 false 的含义.
另外如果在数值表达式中使用 undefined 的变量, 则会产生一个 NaN 结果:
var a; // undefined a + 2; // 值是 NaN
而 null 代表的是 0 值, 并且在数值表达式中使用 null 还会产生计算结果, 我了个擦.
var n = null; n * 32; // 值是 0
- 关于作用域:
在 ECMA 2015(ECMA 6) 之前, 是没有块作用域的, 不过 ECMA 2015 之后添加了, 故使用 let 在块作用域内定义变量.
- 关于全局变量:
全局变量实际上是一个 全局对象(global object) 的属性, 如果是在网页中, 就是 window 对象的属性, 故实际上全局变量可以通过 window.xxx 来访问 xxx 全局变量.
- 关于常量(const):
常量在运行时无法被改变, 但常量对象的属性不受此限制, 即可以向 const 定义的对象进行添加属性或改变属性的值等操作.
const MY_OBJECT = {'key': 'value'}; MY_OBJECT.key = 'otherValue';
另外数组也不受限制:
const MY_ARRAY = ['HTML','CSS']; MY_ARRAY.push('JAVASCRIPT'); console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];
- 数据类型和数据结构:
最新的 ECMA 标准定义了七种数据类型, 包括六种标准类型, 还有一种对象类型(Object).
6 种标准类型如下:
-
Boolean: true 或者 false
-
null: 空类型
-
undefined: 未定义
-
Number: 数值类型
-
String: 字符串类型
-
Symbol: ECMA 2015(ES6) 新增, 代表的是可识别的且不可变数据类型.
JS 是一种动态类型的语言, 故变量可以理解可以具有任何上述类型, 故:
var answer = 42; answer = 'Thanks for all the fish...';
另外还有一些奇奇怪怪且有趣的自动类型转换:
'37' - 7 // 30 '37' + 7 // "377"
有两种方式可以从字符串获取数值:
第一种是 parseInt() 和 parseFloat().
第二种是在前面添加 + 号:
'1.1' + '1.1' // '1.11.1' (+'1.1') + (+'1.1') // 2.2 // Note: the parentheses are added for clarity, not required.
- 字面量的赋值详见 MDN 的链接: Literals.
主要是 6 种基本类型的字面量, 以及 Object 类型的字面量. 主要是 Object 字面量是 {} 包裹的, 类似字典的写法, 如下所示:
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) 中, 对象的支持得到极大增强. 具体内容需要进一步探索.
- 语句块:
{ // ... }
在语句块中实际定义了一个块作用域, 在 ES6 之前是没有这个东西的.
在 ES6 之后, let 和 const 量是块作用域的.
- 在 JS 中的流程控制语句和 C 系语言都差不多. 只是要注意, 在 JS 中有许多的值可以表示 false:
-
false -
undefined -
null -
0 -
NaN -
空字符串
""
而其他所有的值, 包括对象, 用在布尔判断中都表示的 true 值. 另外有一个比较让人抓狂的现实是 true 字面量和以 true 为值的 Boolean 对象并不相等:
var b = new Boolean(false); if (b) // this condition evaluates to true if (b == true) // this condition evaluates to false
另外注意不要把 swift 的 switch 带到这里, 默认是 fallthrough 的.
- 异常处理:
使用 throw 抛出异常, 使用 try...catch 捕捉异常.
可以抛出各种数据类型的异常:
throw 'Error2'; // String type throw 42; // Number type throw true; // Boolean type throw {toString: function() { return "I'm an object!"; } };
不过最好还是使用 Error 对象来作为错误载体:
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) }
- ES6 之后在语言中内置了
Promise对象, 作为异步操作支持, 是一种 Promise 实现.
下面是一个典型用法:
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(); }); }
-
循环语句在这里可以看到, 有 for-in 语句的, 另外可以使用
for-of语句来遍历 iterable 量, 比如数组等. -
函数的参数传递时, 如果是 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));
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 可以形成一个上下文环境, 在该上下文中包含其所处的上下文中的变量, 即变量捕捉.
- 在任何函数内都有一个特殊的对象, 就是
arguments对象, 包含的是所有的参数:
arguments[i]
这样就可以在不知道有多少个参数传入的情况下处理参数表了:
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');
- 关于函数参数, 详见函数参数文档. 从 ES6 开始, 可以提供函数参数的默认参数值(如果不提供, 则默认是
undefined):
function multiply(a, b = 1) { return a * b; } multiply(5); // 5
- ES6 之后, 还增加了
rest parameter, 即不定数量的参数表达:
function multiply(multiplier, ...theArgs) { return theArgs.map(x => multiplier * x); } var arr = multiply(2, 1, 2, 3); console.log(arr); // [2, 4, 6]
-
ES6 新增了
=>的语法, 和 C# 或 Dart 中都类似, 是一种函数表达. -
限制模式: 启用方法是在脚本文件开头的位置添加如下内容:
'use strict'; var v = "Hi! I'm a strict mode script!";
关于在限制模式中进行的改变可以看限制模式改变文档.
- 在函数中, 默认还存在一个
this指针, 指向的就是该函数, 实际上这个函数也形成了一个类定义, 但如果是嵌套函数则会存在问题, 故可以使用如下方式避免:
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 指针:
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();
下面是一些比较有趣的内容:
- 解构:
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;
-
和 swift 一样, 也有
==和===, 后者表示严格相等, 具体含义详见文档. -
次方操作符:
**, 比如2 ** 3结果是8. -
位操作符也有.
-
delete操作符会将对象或对象属性删除, 删除对象后, 指向该对象的变量就变成了undefined值, 删除属性也是同理, 如果删除成功的话, 会返回 true.
delete objectName; delete objectName.property; delete objectName[index]; delete property; // legal only within a with statement
如果在数组上使用 delete, 则会将对应下标变为 undefined, 而不是减少一个元素这么简单.
typeof会返回某个类型的字符串表示, 如下所示:
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"
有两个特殊情况:
typeof true; // returns "boolean" typeof null; // returns "object"
-
void在 js 中是作为一种操作符存在的, 用于表示某个表达式没有返回值, 即undefined的返回值. -
in操作符用于判断某个属性名是否在对象中:
// 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
instanceof用于判断是否是某个类型对象:
var theDay = new Date(1995, 12, 17); if (theDay instanceof Date) { // statements to execute }
var biggestNum = Number.MAX_VALUE; var smallestNum = Number.MIN_VALUE; var infiniteNum = Number.POSITIVE_INFINITY; var negInfiniteNum = Number.NEGATIVE_INFINITY; var notANum = Number.NaN;
-
Math对象: 数学计算相关. -
Date对象: 使用Date对象进行和日期有关的操作. -
JS 中的字符串.
-
Date and time formatting: 日期和时间的转换.
-
带有类型的数组(Typed Arrays), 在某些网络操作中, 比如 WebSocket 中很常用, 详见文档.
-
字典类型(Map), 详见文档.
-
哈希表(Set), 详见文档.
-
JS 中的对象模型非常简单, 无论是语法上还是概念上, 看下面这段:
/* 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 函数:
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 中没有多继承.
-
JS 中的 Promise 文档, 可以参考一下, 这个是万物之源啊. 另外就是错误传递可以看这个文档.
-
在 ECMA 2017 中引入了
async/await可以极大方便异步编程, 并且可以使用 await 来等待 promise. -
在 JS 中可以使用
yield懒生产序列. -
JS 中从 ECMA 2015 (ES6) 开始, 也引入了元编程和反射, 详见文档.
-
虽然说是基于 prototype 的语言, 但在 ES6 中引入了一种 class 语法, 这样可以极大方便从其他语言转过来的开发者, 不过要注意, 这里只是一种语法, 实际上底层还是基于 prototype 的, 而非类, 详见文档.
-
关于 JSON, 这个才是正宗的 JSON 介绍!