语法

以下是js的语法要求

  • 大小写敏感
  • 标识符: 即我们说的变量名 开头必须是字幕/下划线/&的一种
  • 不能把关键字/保留字/true,false,null作为标识符
  • 注释:
    • 单行注销: //
    • 多行注销: / here is your code /
  • 严格模式: Es5引入严格模式,在严格模式下,ECMAScript 3 中的一些不确定的行为将得到处理,而且对某些不安全的操作也会抛出错误。用法
    • 在顶部添加 "use strict";
    • 在函数内部第一行添加
  • 语句: 建议每一行语句背后加分号, 哪怕这不是必须的-因为解释器会自行补充 , 不过这样会耗费时间和性能.

    关键字和保留字

    Reserved Words - JavaScript | MDN 可以查看最新的关键字和保留字

以上都是不能作为标识符的.

变量

使用var/let/const都可以声明一个变量

  • var: 有声明提升,可重复声明
  • let:和var类似,但是:
    • 具备块作用域,如:{ }
    • 不可重复声明
    • 在全局作用域中不可读取let声明的变量
    • for循环中的let ,和for循环中的var表现不一致。主要原因是 JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。 每个 setTimeout 引用的都是不同的变量实例
  • const:与let基本类似,用于声明常量,修改const声明会报错

声明风格和最佳实践:

  • 不使用var
  • 优先使用const,再let。因为使用const声明的时候,将来有人覆盖某一个变量,可迅速查出

数据类型

原始类型:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Symbol

复杂类型

  • Object

typeof操作符

Undefined类型

该类型只有一个值,就是undefined, 左右变量使用let 或者 var声明未赋值的时候,值就是undefined,无需显式声明成undefined

  1. undefined == null // true, 因为undefined是null派生而来

Null类型

该类型同样只有一个值,就是null,表示一个空对象的指针,通常声明一个还没被实际定义的对象数据时,我们可以用null进行填充

Boolean类型

Number类型

几点要注意的:

  • 八进制数通常(非严格模式,严格模式0o开头)0开头 ,比如 071, 但是只要数值中的数字大于进制范围,该数字会被识别成十进制数字,如079
  • 十六进制数字以0x开头,如0xA123, A到F忽略大小写
  • 0.1+0.2!=0.3 是因为使用了IEEE754数值造成的,不是语言的问题
  • JS中数值范围为Number.MIN_VALUE ~ Number.MAX_VALUE, 超过这个范围只会返回Infinity和-Infinity, 所有数值为无限大的,都不能再用于计算,因为没有对应值可以展示
  • NaN: Not a Number, NaN == Nan // false
  • 函数isNaN可以接受任何参数,尝试转换成数值,甚至是对象,但是要注意会先尝试调用Object的valueOf方法转换,如果无效,则再调用toString方法

数值转换
以下三个方法可以进行数值转换:

  • Number: 参数可传任何数据
    • 传布尔值,true为1,false为0
    • 传数值直接返回
    • null返回0
    • undefined返回NaN
    • 字符串:
      • 传数值字符串则返回对应十进制数值
      • 传浮点数字符串返回对应浮点数值
      • 如果字符串以0x开头,包含数字和字母,并且单个字母值在A-F闭合区间,则转换成十进制数值
      • 空字符(相当于不传参数)返回0
      • 除了以上四种字符串传参方式,剩余都返回NaN
  • parseInt(arg1,arg2): 参数解释 字符串, 进制
    • 在不传arg2的前提下(相当于arg2传了10),传任何 数字 开头的字符串(不包括0x本身),都可以返回对应的整数。但是0x开头的字符串,后续至少要跟一位A-F闭区间的字符,才能转换成对应的十进制展示数否则返回NaN
    • 如果传了合理的arg2, 那么arg1的字符串只要在arg2的范围内,则能正确返回对应的十进制展示数,如parseInt(‘kk’,32) // 660
  • parseFloat:略

注意Number方法转换参数为数值,和一元操作符 + 相同

String类型

字符串具有length属性

字符字面量:

  • \n : 换行
  • \t :制表
  • \b:退格
  • \r:回车
  • \f:换页
  • \:反斜杠
  • \’:单引号(一般用于单引号中嵌套单引号使用)
  • \”:双引号,同上
  • `:反引号,同上
  • \xnn:十六进制开头的数值,如\xAF
  • \unnn:以十六进制编码的Unicode字符,如\u03a3 表示 ∑

字符串特点:略

转换成字符串:

  • toString方法:
    • 数值,布尔值,对象,字符串都有toString方法,null, undefined没有
    • 通常toString不用传参数几个返回对应的字符串,如果是数值类型转换,可传进制参数,表明某个数值转换对应进制的结果
  • string方法:
    • 所有变量都可以用string方法转换成对应字符串

字面量模板和字符串插值:` 和 ${x} , 具备多行字符串快速书写的能力,注意模板会保留对应的空格符

模板字面量标签函数:略

原始字符串:略

Symbol类型

Symbol(符号)类型是ES6新增的数据类型,符号类型是基本数据类型,且符号是唯一的,不可变的。它的主要用途是保证对象的属性名是唯一的,避免发生冲突

基本用法

  1. let sy1 = Symbol()
  2. let sy2 = Symbol()
  3. typeof sy1 // symbol
  4. console.log(sy1==sy2) // false
  5. let sy3 = Symbol('sy3')
  6. alert(sy3) // TypeError: Cannot convert a Symbol value to a string 注意它是不会隐式转换的
  7. alert(sy3.description); // sy3 可以这样
  8. alert(sy3.toString()); // 强制转换
  9. alert(String(sy3)); // 强制转换
  10. // 可以传参,但参数只有描述意义
  11. let syFoo = Symbol('这个是Foo')
  12. let syBar = Symbol('这个是Bar')
  13. console.log(syFoo) // Symbol(这个是Foo)
  14. // symbol不能用new创建
  15. let myBoolean = new Boolean();
  16. console.log(typeof myBoolean); // "object"
  17. let myString = new String();
  18. console.log(typeof myString); // "object"
  19. let myNumber = new Number();
  20. console.log(typeof myNumber); // "object"
  21. let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor


使用全局符号注册表

前面我们知道,即便对Symbol函数传相同参数,返回的两个symbol实例都不相等,如果你想要一个符号,但是其他地方又可以用到,就用Symbol.for创建

  1. let fooGlobalSymbol = Symbol.for('foo'); // 全局注册表的符号必须使用字符串键来创建
  2. console.log(typeof fooGlobalSymbol); // symbol
  3. let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
  4. let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
  5. console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
  6. let localSymbol = Symbol('foo');
  7. console.log(fooGlobalSymbol == localSymbol) // false
  8. // 创建全局符号
  9. let s = Symbol.for('foo');
  10. console.log(Symbol.keyFor(s)); // foo
  11. // 创建普通符号
  12. let s2 = Symbol('bar');
  13. console.log(Symbol.keyFor(s2)); // undefined
  14. Symbol.keyFor(123); // TypeError: 123 is not a symbol, 参数必须是符号

使用符号作为属性

  1. let s1 = Symbol('foo'),
  2. s2 = Symbol('bar'),
  3. s3 = Symbol('baz'),
  4. s4 = Symbol('qux');
  5. let o = {
  6. [s1]: 'foo val'
  7. };
  8. // 这样也可以:
  9. o[s1] = 'foo val'; // 注意 这里和 o['s1'] 是不一样的
  10. console.log(o);// {Symbol(foo): foo val}
  1. let s1 = Symbol('foo'),
  2. s2 = Symbol('bar');
  3. let o = {
  4. [s1]: 'foo val',
  5. [s2]: 'bar val',
  6. baz: 'baz val',
  7. qux: 'qux val',
  8. [Symbol('a')]:'foo',
  9. [Symbol('b')]:'bar',
  10. };
  11. console.log(Object.getOwnPropertySymbols(o));// [Symbol(foo), Symbol(bar)]
  12. console.log(Object.getOwnPropertyNames(o)); // ["baz", "qux"]
  13. // 注意使用symbol作为属性,在遍历key的的时候,是不会被打印出来
  14. // 利用此特征,可以用它来给object对象写一些私有属性
  15. console.log(Object.getOwnPropertyDescriptors(o));
  16. // {baz: {...}, qux: {...}, Symbol(foo): {...}, Symbol(bar): {...}}
  17. console.log(Reflect.ownKeys(o)); // 注意这个API, ["baz", "qux", Symbol(foo), Symbol(bar)]
  18. console.log(o) //{…, Symbol(a): "foo",Symbol(b): "bar"} // 注意这里,symbol直接是一个实例
  19. let barSymbol = Object.getOwnPropertySymbols(o)
  20. .find((symbol) => symbol.toString().match(/bar/)); // 只有这样才能匹配到未标记的symbol
  21. console.log(barSymbol); // Symbol(bar)

其他

剩余不常用API待补充

  • Symbol.iterator
  • Symbol.asyncIterator
  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.match
  • Symbol.replace
  • Symbol.search
  • Symbol.species
  • Symbol.split
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables

Object类型

一组数据和功能的集合,创建方法见代码

  1. let obj = new Object()
  2. let obj1 = new Object // 不传参数也可以

object实例包含以下属性和方法:

  • constructor: 通常指向构造函数
  • hasOwnProperty(name):检测当前对象是否包含某个非原型链上的属性
  • isPrototypeOf(obj):是否为其他对象的原型对象
  • propertyIsEnumerable(propName):检测该对象的某个属性是否可以枚举
  • toLocalString()
  • toString()
  • valueOf()

    操作符

    一元操作符

位操作符

布尔操作符

乘性操作符

指数操作符

加性操作符

关系操作符

相等操作符

条件操作符

赋值操作符

逗号操作符

语句

if语句

为了其他同事的着想,if后面请用花括号!

do-while语句

至少执行一次循环

for语句

for-in语句

通常用于遍历对象属性

  1. let arr = [1,2,3,4]
  2. let d = Symbol('d')
  3. let obj = {
  4. a:1,
  5. b:2,
  6. c:3,
  7. [d]:4,
  8. e:null,
  9. g:7,
  10. f:undefined,
  11. }
  12. for(let i in arr){ // 注意这里遍历的是数组
  13. console.log(i) // 依次打印0,1,2,3 ,注意依次打印的是索引
  14. }
  15. for(let i in obj){
  16. console.log(i) // 注意这里不会遍历到 [d], 并且会按用户顺序返回
  17. }

for-of语句

可以理解成专用于数组的遍历语句

  1. let arr = [1,2,3,4]
  2. let obj = {a:1,b:2,c:3}
  3. for(let i of arr){
  4. console.log(i) // 依次打印1,2,3,4
  5. }
  6. for(let i of obj){ // 注意这里是遍历对象
  7. console.log(i) // TypeError: obj is not iterable
  8. }

标签语句

标签语句用于给语句加标签,语法如下

  1. start: for (let i = 0; i < count; i++) {
  2. console.log(i);
  3. }
  4. //在这个例子中,start 是一个标签,可以在后面通过 break 或 continue 语句引用。标签语句的典型应用场景是嵌套循环。

不建议使用

break和continue语句

不建议使用,当然在特定循环条件中需要跳出可用break

with语句

永远不要用with语句

switch语句

如果你写了大量的if-else语句,那你需要考虑用switch

函数

函数在任何语言中,都是非常重要的角色, JS的函数使用 function关键字声明,更多详细的内容,会在第十章的时候讲解

  1. function fnName(arg){
  2. // ....
  3. return // 函数默认是没有返回值的
  4. console.log('hello') // return之后的语句不会被执行
  5. }