基础知识
0. 基础
如何引入 JS 代码?
如果在 HTML 中引入 JavaScript 代码,则通过<script></script>包裹;如果在 HTML 中引入 JavaScript 文件,则通过<script src="文件地址"></script>引入。
JavaScript 的组成?
ECMAScript:JavaScript 的语法标准,包括变量、表达式、运算符、函数、if/for语句等;
浏览器环境:
DOM:Document Object Model(文档对象模型),操作页面上的元素的API,比如让盒子移动、变色、改变大小、轮播图等等;
BOM:Browser Object Model(浏览器对象模型),操作浏览器部分功能的API,比如弹框、控制浏览器跳转、获取浏览器分辨率等等。
Node.js 环境
......
1. 变量/常量
1.1 变量声明
ES5 中,使用
var定义全局变量(如今开发中尽量不要出现var了)。ES6 中,使用
let定义局部变量,使用const定义常量。
var、let、const 的区别
var 声明的变量会挂载在 window 对象上(会污染),而 let 和 const 声明的变量不会
var 声明的变量存在变量提升,let 和 const 声明的变量不存在变量提升,要先声明再使用
var 声明不存在块级作用域,let 和 const 声明存在块级作用域
同一作用域下,var 可以重复声明变量,let 和 const 不能重复声明变量
let 和 const 存在暂时性死区(声明语句必须放在使用之前)
const 一旦声明必须赋值,声明后不能再修改(当然如果是对象类型则另说)
1.2 解构赋值
ES6 允许按照一一对应的方式,从数组或者对象中提取值,再将提取出来的值赋值给变量。解构赋值的拷贝是浅拷贝,如果一个键的值是复合类型的值(数组、对象、函数),那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
数组的解构赋值
易错点:
如果变量在一一对应没有找到对应值,那么多余的变量会被赋值为 undefined
解构赋值时,左边允许有默认值,但在没匹配到的情况下才使用
右边存在
undefined时,左边则使用默认值;若右边存在null时,左边则为null,相当于有值
对象的解构赋值
字符串的解构赋值
函数参数的解构赋值
应用
2. 数据类型
基本数据类型:参数赋值的时候,传数值
String 字符串
Number 数值
Boolean 布尔值
null 空值
undefined 未定义
symbol
引用数据类型:参数赋值的时候,传地址
Object 对象(Function, Array, Date, RegExp, String, Boolean, Number, Error 等)
2.1 数据类型转换/识别
数据类型2.2 符号 Symbol
Symbol 是一种新的原始数据类型,每一个 Symbol 值都是不相等的,主要用作对象属性名(作为标识符),可以保证不会与其他属性名产生冲突,Symbol 值通过 Symbol 函数生成,let s = Symbol();。
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
Symbol.for() 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。symbol() 不会搜索是否存在给定key值的symbol,直接创建新的symbol值。
Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key,注意通过symbol()生成的不登记,因此不适用。
2.3 ES6 Set/Map
2.2.1 Set
Set 类似于数组,但是成员的值都是唯一的,没有重复的值。
属性:
Set.prototype.constructor:构造函数,默认就是Set函数。Set.prototype.size:返回Set实例的成员总数。
实例方法:
Set.prototype.add(value):添加某个值,返回 Set 结构本身。Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。Set.prototype.clear():清除所有成员,没有返回值。
遍历操作 - keys方法和values方法的行为完全一致:
Set.prototype.keys():返回键名的遍历器,Set.prototype.values():返回键值的遍历器Set.prototype.entries():返回键值对的遍历器Set.prototype.forEach():使用回调函数遍历每个成员
2.2.2 Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键,Map 结构提供了“值—值”的对应。
Map 与其他数据之间的转换
Map 与数组
Map 与对象
Map 与 JSON
2.2.3 WeakSet 和 WeakMap
WeakSet的成员只能是对象,而不能是其他类型的值。WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用。WeakSet 不能遍历,也没有size属性。
WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。WeakMap的键名所指向的对象,不计入垃圾回收机制。WeakMap不能遍历,也没有size属性。
2.4 易错点
如果在引号里面使用相同的引号,则需要用 \ 进行转义。
字符串 + 运算,如果前面两个以上为数值类型,则 + 作数字运算,直到遇到第一个字符串,则 + 又变成字符串拼接。
直接使用字面量创建字符串与对象创建是不同的。
undefined表示一个声明了没有赋值的变量,变量只声明的时候默认就是undefined;null 的数据类型是 object,null 表示一个空,变量值如果想变为 null,必须手动设置。
如果布尔对象无初始值或者其值为0、-0、null、undefined、""、NaN、false,则对象的值为 false。否则,其值为 true(即使当自变量为字符串 "false" 时)!
3. 操作/运算符
3.1 自增和自减
a++:先把 a 的值赋值给表达式,然后 a 再自增
++a:a 先自增,然后再把自增后的值赋值给表达式
3.2 逻辑运算的妙用
与运算的返回结果:(以多个非布尔值的运算为例)
如果第一个值为false,则执行第一条语句,并直接返回第一个值;不会再往后执行。
如果第一个值为true,则继续执行第二条语句,并返回第二个值(如果所有的值都为true,则返回的是最后一个值)。
或运算的返回结果:(以多个非布尔值的运算为例)
如果第一个值为true,则执行第一条语句,并直接返回第一个值;不会再往后执行。
如果第一个值为false,则继续执行第二条语句,并返回第二个值(如果所有的值都为false,则返回的是最后一个值)。
3.3 非数值的比较
对于非数值进行比较时,会将其转换为数字然后再比较。
如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而是比较Unicode编码。
任何值和NaN做任何比较都是false。
3.4 运算符优先级
优先级从高到低:
()++、--!、~、+(单目)、-(单目)、typeof、void、delete%、*、/+(双目)、-(双目)<<、>>、>>><、<=、>、>===、!==、===、!==&、^、|、&&、||?:=、+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、^=、|=,
4. 语句
if 语句推荐使用 return 的写法
switch-case 的缺点在于 case 的值只能判断等于,而不能有其他判断,这个较 if 语句较弱,且 break 不写则会继续进行下一个 case。
循环结构有三种:while、do-while、for,一般while循环解决无法确定循环次数的,能够确定循环次数的多采用 for 循环。
continue 和 break
break立即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)
continue立即跳出当前循环,继续下一次循环
还有一个非常容易被忽视的特性"标签",用于控制流,一个标签可以被用于 break , continue 语句去更精确地控制流。 通过标签可以跳出指定的循环,而不是仅仅就近原则循环。
5. 函数
5.1 函数声明
fn() 和 fn 的区别
fn():调用函数,调用之后,还获取了函数的返回值。fn:函数对象,相当于直接获取了整个函数对象。
注意,函数如果通过function fun(){}形式声明,则整个函数会在所有的代码执行之前就被创建完成,即声明提升,而函数如果通过const fun = () => {}形式声明,则不存在声明提升,需要先声明再使用。
5.2 箭头函数
如果返回对象,需要再加一层 (),否则花括号被解释为代码块
let getTempItem = id => ({ id: id, name: "Temp" });函数体内的
this对象,就是定义时所在的对象,而不是使用时所在的对象。不可以当作构造函数,也就是说,不可以使用
new命令。不可以使用
arguments对象,该对象在函数体内不存在,但可以通过剩余运算符来弥补。不可以使用
yield命令,因此箭头函数不能用作 Generator 函数。
5.3 默认值设置
函数设置默认值,函数的 length 属性,将返回没有指定默认值的参数个数。
与解构赋值同用时需要注意 - 函数参数的默认值先生效,然后解构赋值的默认值生效。
5.4 ... 剩余运算符
剩余参数允许我们将不确定数量的剩余的元素放到一个数组中,其区别于arguments变量,arguments对象是类似数组,需要先将其转变为数组 Array.prototype.slice.call()。
扩展运算符和剩余参数是相反的。剩余参数是将剩余的元素放到一个数组中;而扩展运算符是将数组或者对象拆分成逗号分隔的参数序列,例如...[1,2,3]得到的就是1 2 3这个序列。
5.5 类数组 arguments
在调用函数时,浏览器每次都会传递进两个隐含的参数:
函数的上下文对象 this
封装实参的对象 arguments
arguments 是一个类数组对象,在调用函数时,我们所传递的实参都会在 arguments 中保存。
arguments.length:返回函数实参的个数
arguments[0] = 99:arguments 可以修改元素
arguments 是类数组对象,可以遍历,但不具有数组的 push()、pop() 等方法,需要通过 [...arguments] 或 Array.from(arguments) 进行转化为数组
5.6 立即调用的函数表达式 IIFE
IIFE的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
5.7 构造函数
构造函数是一种特殊的函数,主要用来创建和初始化对象,也就是为对象的成员变量赋初始值,普通函数是直接调用,而构造函数需要使用 new 关键字来调用。
注意区分静态成员与实例成员
静态成员:在构造函数上添加的成员称为静态成员,只能由构造函数本身访问。
实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象访问。
6. 对象
在 JavaScript 中,对象具有特征(属性)和行为(方法),其是是一组无序的相关属性和方法的集合。对象主要包括以下几类:
内置对象(ES标准中定义的对象)
宿主对象(如浏览器提供的对象)
自定义对象(开发人员自定义对象)
6.1 ES6 属性扩展
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。
ES6中允许用表达式作为对象的属性名,方法名也适用,但是属性名表达式与简洁表示法,不能同时使用,方法名无关。
6.2 对象属性遍历
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性) - 由于引入继承,不建议使用Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
6.3 自定义对象
6.4 Object 对象
Object 对象7. Class 类
传统生成实例对象是通过构造函数实现,引入了 Class(类)这个概念,可以通过class关键字定义类。实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上),类的所有方法都定义在类的prototype属性上面,如下面的 toString。
对某个属性设置存值函数和取值函数可以拦截该属性的存取行为:
7.1 静态成员/公有成员
7.2 Class 继承
原型链/继承8. Proxy 对象
Proxy 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。具体的拦截操作详见 ES6 - proxy。
9. Iterator 遍历器
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口,即for...of;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
原生具备 Iterator 接口的数据结构:
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
调用 Iterator 接口的场合:
解构赋值
扩展运算符
yield*
for...of
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如
new Map([['a',1],['b',2]]))Promise.all()
Promise.race()
10. 模块化
模块化11. 异步相关内容
Promise 对象、Generator 函数、async 函数、定时器等相见异步操作章节。
异步操作最后更新于
这有帮助吗?