重学JavaScript 篇的目的是回顾基础,方便学习框架和源码的时候可以快速定位知识点,查漏补缺,所有文章都同步在 公众号(道道里的前端栈) 和 github 上。
语法
标识符、注释、严格模式、语句和关键字
在 JavaScript
中,变量、函数名、操作符等,一切都区分大小写。
JavaScript中的标识符,也就是变量、函数、属性或函数参数的名称,有一定的限制:第一个字符必须是 字母、下划线(_) 或者 **美元符号()**,其他字符可以是字母、下划线(_)、美元符号()∗∗,其他字符可以是字母、下划线()、美元符号()或数字。一般情况下,最好使用驼峰大小写形式。
JavaScript中的注释分为 单行 和 多行,"//" 双杠为单行注释,"/* */" 单杠和星号组成多行注释。
JavaScript中可以声明严格模式,在脚本头加上"use strict;",表示该脚本启用严格模式,目的是消除一些脚本中的不严谨的地方,保证代码的安全,同时也可以加快代码的运行速度。严格模式可以针对整个脚本文件,也可以针对单个函数,具体的详解可以查看阮一峰的博客:Javascript 严格模式详解。
JavaScript中语句结束要用分号结尾,就算不会报错,也要加上,可以避免很多不必要的细节问题,同时也可以提升性能,因为解析器会尝试在合适的位置补上分号以纠正语法错误。在使用 **if ** 的时候,最好加上大括号,虽然不会报错,但是也可能造成错误。
JavaScript中关键字有自己的用途,所以在声明标识符的时候不可以用关键字来声明,常用的关键字如下:
break、do、in、typeof、case、else、instanceof、var、catch、export、new、void、class、extends、return、while、const、finally、super、with、continue、for、switch 、yield、debugger、function、this、default、if、throw、delete、import、try、enum、let、implements、package、public、interface、protected、static、private、await
变量
JavaScript中变量声明可以用过 var
, let
, const
来声明,默认声明的变量的值为 undefined。如果出现语句:msg = 100,不会报错,但是不推荐。
var
- 作用域
在使用 var 的时候,变量就成为了包含它的函数的局部变量,在函数退出之后,该变量会被销毁(引用计数机制)。如果没有用var声明,那么该变量就成了全局变量,并且可以在函数内外都可以访问到(不要这么做,很不好维护)。 - 变量提升
在使用 var 的时候,如果变量声明在变量使用的下面,浏览器也不会报错,因为该变量会自动提升到函数作用域的头部,也就是变量提升。
let
- 作用域
let的使用和 var 差不多,最大的区别是:let声明的范围是块作用域,而var声明的是函数作用域,=而函数作用于包括块作用域,所以var的作用域限制也会适用于let,同时,let不允许在同一个块作用域中出现冗余声明 - 暂时性死区
let和var的另一个重要区别就是,let声明的变量不会在作用域中被提升,在let声明之前的执行瞬间被称为“暂时性死区”,在此阶段引用后任何后面才会声明的变量都会报错:ReferenceError。 - 全局声明
let在全局作用域内声明的变量不会成为 window 对象的属性,而var声明的变量就可以。
var name = "小明"; console.log(window.name); //小明 let name = "小明"; console.log(window.name); //undefined
- 声明
如果一个变量使用 let 声明,但是之前该变量已经被使用或者被声明,那么该变量就会报错,因为let的作用域是块,并且不会检查块之前前面的变量。 - 经典 for循环
for(var i = 0; i < 5; i++){ //do something }
- 在上面的代码中,变量 i 会渗透到循环体外,所以每次更改的 i 都是累加结束后退出循环的值,如果把 var 改成 let,那么变量 i 的作用域就变成了for循环内,并且在for循环外是没办法使用 i 的,理解了这个之后,下面的经典面试题应该就没问题了。
//经典作用域面试题 for (var i = 0; i < 5; ++i) { setTimeout(() => console.log(i), 0) } //5,5,5,5,5 for (let i = 0; i < 5; ++i) { setTimeout(() => console.log(i), 0) } //1,2,3,4,5
const
const的用法基本和let相同,唯一一个重要的区别就是用 const 来声明变量的时候,必须同时初始化变量,并且该变量为不可修改。
这里注意,const指向的是变量的引用,如果是声明了一个值类型的变量,那么该变量不可更改,如果是声明了一个引用类型的变量(比如对象),则可以修改对象的属性。
for (const i = 0; i < 5; ++i) { } //会报错,因为for循环属于迭代变量,迭代变量会自增
只有在变量不会被修改的情况下,才可以使用 const。
数据类型
JavaScript中的数据类型为7个:Undefined
、Null
、Boolean
、Number
、String
、Symbol
和 Object
。要想判断变量哪种数据类型,常用的方式为:
- typeof:自带操作符,可以简单判断变量
- Object.prototype.toString.call():通过原型链的方式判断
undefined
undefined类型只有一个值,就是 undefined,当使用 var 或者 let 声明了变量,但是没有初始化时,变量就是undefined,undefined === undefined,不用 var 或者 let,直接使用一个变量,它就不是 undefined。
Null
Null类型其实是一个对象,typeof null;
会返回一个"object",所以在初始化一个对象的时候,可以把它初始化为 null。
undefined 是由 null 派生出来的,所以 null == undefined,同时它们两个转化为布尔值的话,都是 false。
Boolean
这里注意一下,布尔值字面量 true 和 false 是区分大小写的,所以 True 和 False 不是布尔值。
Number
一般情况下,默认数字是十进制的,如果想改为八进制或者十六进制的话,数字的首位必须是0。带小数点的数字最好要写全,虽然 let a = .1;
不会报错,但是最好不要这样写。使用科学计数法的话,一个数字之后使用 e
,再加上一个要乘的10的多少次幂,比如:
let float = 3.125e7 // 等于 31250000
在JavaScript中,最大的数字是 5e-324
,最小的数字是 1.797 693 134 862 315 7e+308
,超出范围的数字会返回一个 Infinity
。在使用number的时候,千万要注意精度问题。有一个很特殊的值叫 NaN
,它表示 不是一个数字,注意它不是一个错误,NaN != NaN。
重点来了!数字转换:
- true 返回 1,false 返回 0
- null 返回 0
- undefined 返回 NaN
- 字符串
- 包含数字,返回 该数字的十进制
- 空字符串,则返回 0
- 除此之外,返回 0
- 对象,调用 valueof(),如果转换结果是 NaN,调用 toString(),再按照转换字符串的规则转换
String
一旦创建了一个字符串,它的值就是不可变的,要想修改它的值,必须销毁原字符串,然后将包含新值的另一个字符串保存到该变量中,比如:
let a = "abc"; a = a + "def"; // a被定为abc,然后a被定位为abcdef,最后销毁原来的abc和def
symbol
symbol是原始值,并且唯一不可变,主要用在私有属性上,用 symbol 声明的两个变量互不相等。如果向想声明一个对象,可以使用 Object()
:
var sym = Symbol("foo"); typeof sym; // "symbol" var symObj = Object(sym); // Symbol {Symbol(foo)} console.log(symObj.description) // "foo"
有关symbol的api,可以看这里。
Object
Object是所有对象的基类,每个Object实例都有如下属性和方法:
- Constructor:用于创建当前对象的函数
- hasOwnProperty(name):用于判断当前对象实例上是否有name这个属性
- isPrototypeOf(object):用于判断当前对象是否是另一个对象的原型
- propertyIsEnumerable(name):用于判断属性name是否可以使用 for-in 枚举
- toLocalString():返回对象的字符串,该字符串反映对象在本地化执行环境
- toString():返回对象的字符串
- valueOf():返回对象对应的字符串、数值或者布尔值