都是本人理解,笔记大致概念,不详细也并非完全正确,所以仅供参考。
基本规范:
- 不在同一行声明多个变量
- 使用 === 和 !== 来比较值
- 使用对象字面量替代new方法声明变量
- switch语句必须带有default分支,for循环和if语句带大括号
数据类型
两大数据类型:
- 基本数据类型
- 引用数据类型
基本数据类型
String、Number、Boolean、Null、Undefined、Symbol
Symbol:代表独一无二的值。
参见:http://es6.ruanyifeng.com/#docs/symbol
引用数据类型
Object、Array、Function
变量/函数提升
抽象变量和函数从无到引用的过程实质为:创建、初始化、赋值、引用
过程 | 描述 |
---|---|
创建 | 在当前执行块中注册此变量名 |
初始化 | 在内存中初始化存储空间并存储初始值 |
赋值 | 即字面量的意思,赋值,存储数据 |
引用 | 即字面量的意思,引用/调用变量/函数 |
PS:变量/函数需初始化后方可进行引用,否则报错 is not defined
当声明变量/函数时,JS解析器提升其过程,故而存在不同的特性,如:
- var声明语句提升了创建、初始化的过程,故在申明语句前也可调用。
- let/const声明语句提升了创建过程,故在申明语句后方可使用。
- function 声明提升了创建、初始化、赋值的过程,故在申明语句前可执行此方法。
PS:所以,let 和 const 的唯一区别就是 const 没有赋值过程。
PS:运算符的 {} 会隔断函数提升,而不会隔断变量提升,但 {} 内部函数声明是否会覆盖外部同名函数依解析器不同则有不同的表现形式,绝大多数情况下,会覆盖外部同名函数。
既然有变量和函数的提升,那么就会有同名情况下的先后顺序问题,实际在提升时,函数的提升过程永远大于变量,所以理论上是变量覆盖函数,在同名变量和同名函数同时声明的情况下,但如果函数和变量同名,而如果变量未赋值,则依旧是函数,因为var是创建过程,而=是赋值过程,看下面的例子。
function a(){}
var a;
typeof a; // function
// 思考:如果这样呢?
function b(){}
var b = 1;
typeof b; // number
函数声明和函数表达式的区别
函数声明和函数表达式的作用差不多,但是其概念不同。
- 函数声明:在作用域中声明一个具名函数
- 函数表达式:在作用域中创建一个匿名函数,并将函数进行运算操作
由上节可知,函数声明会被提升,所以可以在其之前使用。
而如果以函数表达式的形式声明并赋值,则无法在其之前使用。
a(); // aaa
function a(){ console.log('aaa') }
b(); // Uncaught ReferenceError: b is not a function
var b = function(){ console.log('bbb') }
再由上节可知,运算符的 {} 会隔断函数提升,所以:
a(); // Uncaught ReferenceError: a is not a function
if(1){
function a(){ console.log('aaa') }
}
函数表达式的常用场景
都知道立即执行函数这样写,那为什么可以这样写呢?
(function(win){
// some code ...
})(window)
因为JS解析器需要区分函数声明和函数表达式,所以直接使用 function(){} 会被解析函数声明,这样的声明明显是错误语法,所以需要使用运算符来区别,所以会像如上写法增加括号,那么举一反三,也可以这样写。
tip: JS解析器经常要判断某一句代码是表达式/运算符,默认会解析成表达式,当要解析程运算符时,往往都会在代码处以括号包裹来告诉编译器它是一个运算符。
!function(win){
// some code ...
}(window)
+function(win){
// some code ...
}(window)
-function(win){
// some code ...
}(window)
但是因为 + - 这些符号会和上一行进行运算,所以常见的是 () 和 ! ,所以立即执行函数,实质是就是函数表达式的巧用。