一、初识 ES6
1. let 和 const
let
和 var 一样,都是用来声明变量
的,变量的值是可以更改的const
是用来声明常量
的,常量一旦初始化后就不可以重新赋值了- const在声明时必须进行初始化
赋值
let name = '嘟嘟'
let age = 18
const sex = '女'
- 当希望在初始化后不能进行重新赋值的情况下,就需要使用const
- const 声明的常量,允许在不重新赋值的情况下进行修改(引用类型)
const person = {
name:'dudu',
age:18
}
person.age = 20
console.log(person.age) // 20
- 在不确定需要声明的类型时,可以先声明为const ,后续如果需要更改再改为let
2. let、const、var的区别
2.1 重复声明
- 重复声明:已经存在的变量或常量,又进行了一次声明
- var 允许重复声明
- let、const不允许重复声明
function fun(name) {
let name = 'dudu'
}
fun('嘟嘟')
2.2 变量提升
- var会提升变量的声明到当前作用域的顶部,即 “ 可以先使用后声明 ”
console.log(name)
var name = 'dudu'
- let、const不存在变量提升,即必须 “ 先声明后使用 ”
2.3 暂时性死区
- 暂时性死区:只要作用域内存在let、const,则他们所声明的常量或变量就自动“绑定”这个区域,不会再受外部作用域的影响
let name = 'dudu'
function fun() {
// 该作用域内存在let,则会绑定这个内部作用域,
// console的时候只能在内部查找对应的name,不会去找外部的,
// 所以会报错
console.log(name)
let name = '嘟嘟'
}
fun()
- var 不存在暂时性死区
2.4 window对象的属性和方法
- 全局作用域中,var声明的变量或function声明的函数,会自动变成window对象的属性或方法(可以通过window.xxx使用)
var name = 'dudu'
function fun() { }
console.log(window.name) // 'dudu'
console.log(window.fun === fun) // true
2.5 块级作用域
- 块级作用域:function(){}、for(){}、while(){}、do{}while()、if(){}、switch等
- 对象虽然有花括号,但是没有作用域
- var 没有块级作用域
- let、const存在块级作用域
二、 模板字符串 ``
- 模板字符串即反引号 ``(键盘左上角esc键的下面那个键,英文状态下按才可以)
- 模板字符串拼接变量是通过
${变量}
let name = '嘟嘟'
const info = `hello,我是${name}`
- 模板字符串中,所有的空格、换行、缩进都会被保留输出(怎么写的就怎么输出)
- 模板字符串如果要输出 ` 或 \ ,则需要通过转义字符 \
console.log(`输出一个反引号 \``)
console.log(`输出反斜杠 \\ `)
- 模板字符串的注入
${}
,括号内部可以放:常量、变量、对象属性、调用函数、JS表达式等最终可以得到一个值
的
三、 箭头函数
- 箭头函数的写法:
() => {}
- 箭头函数是匿名函数,如果需要在其他地方调用,则可以将其赋值给常量或变量
onst add = (x,y) => {
return x + y
}
console.log(add(3,4))
3.1 箭头函数的化简
3.1.1 单个参数
- 单个参数的箭头函数可以不写参数的圆括号,即 :
参数 => {}
const add = x => {
return x + 5
}
- 多个参数或者没有参数,则不能省略圆括号
3.1.2 单行函数体
- 单行函数体,可以同时省略花括号{}和 return关键字, 即:
() => 单行函数体
const add = (x,y) => x + y
3.1.3 单行对象
- 单行对象,可以省略函数体的花括号和return关键字,然后
在对象的花括号{}外面加一个圆括号()
// 化简前
const add = (x,y) => {
return {
value: x + y
}
}
// 化简后
const add = (x,y) => ({
value: x + y
})
3.2 this指向
3.2.1 普通函数中的this指向
- 全局作用域中 this 指向 window 对象
普通函数只有在调用函数时才能确定this指向
,只和谁调用有关,和在哪儿调用无关
- 规则一:
对象打点调用函数时,this 指向打点的对象
对象.方法()
var obj1 = {
a:1,
b:2,
fn() {
console.log(this.a+this.b)
}
}
var obj2 = {
a:3,
b:4,
fn:obj1.fn
}
obj2.fn() // obj2调用的,所以this是obj2。然后函数也是引用类型,进行赋值的时候会指向同一个堆,所以会打印出 7
function outer() {
var a = 20
var b = 12
return {
a:33,
b:44,
fn() {
console.log(this.a+this.b)
}
}
}
outer().fn() // outer()返回一个对象,所以最后也是构成了对象.方法的调用,this就会指向返回的对象,所以会打印出77
- 规则二:
圆括号直接调用函数,则 this 指向window对象
函数()
var obj1 = {
a:1,
b:2,
fn() {
console.log(this.a+this.b)
}
}
var a = 3
var b = 4
var fn = obj1.fn
fn() //通过函数直接调用,this指向window对象,则结果会返回7
function fn() {
return this.a + this.b
}
var a = 1
var b =2
var obj = {
a:3,
b:fn(),
fn:fn
}
var result = obj.fn() //通过对象的形式调用,this指向obj对象,a=3,b:fn()相当于全局调用了fn方法,b中的this指向window,所以b=3
console.log(result) // 6
- 规则三:
数组(类数组对象)枚举出函数进行调用 ,this 指向这个数组(类数组对象)
类数组对象
:所有的键名为自然数序列(从0开始)且有length属性的对象arguments对象
是最常见的类数组对象,它是函数的实参列表
数组 [下标 ] ()
function fun() {
arguments[3]()
}
fun('A','B','C',function() {
console.log(this[1]) // this指向arguments类数组对象'A','B','C',function(),结果输出B
})
- 规则四:
IIFE中的函数,this 指向window对象
(function() {
…
})()
var a = 1
var obj = {
a:2,
fun:(function(){
var a = this.a; //IIFE中的this指向window,则a=1
return function() {
// a 在函数体内部,则a=1
// return 返回了一个函数
console.log(a + this.a) // 3
}
})()
}
obj.fun() //点的方式调用函数,则this指向obj对象,则this.a=2
- 规则五:
定时器、延时器调用函数,this 指向 window对象
setInterval(函数,时间)
setTimeout(函数,时间)
var obj = {
a:1,
b:2,
fun() {
console.log(this.a + this.b)
}
}
var a = 3
var b = 4
setTimeout(obj.fun, 2000); //this指向window,则this.a=3,this.b=4
setTimeout(() => {
obj.fun() //对象点方法的形式调用函数,则this指向obj对象,this.a=1、this.b=2
}, 2000);
- 规则六:
事件处理函数的上下文是绑定事件的DOM元素
DOM元素.onclick = function() {
//当函数内部有其他函数,比如定时器时,要考虑this的指向
// 必要时需要备份this,即 var _this = this,这时在内部的函数中就可以用_this指向需要的DOM
}
- 规则七:构造函数的 this 指向构造函数实例化后生成的对象
3.2.2 箭头函数中的 this 指向
- 箭头函数没有自己的 this ,它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,即它会继承父级的 this
3.3 不适用箭头函数的场景
- 作为构造函数时,不适合用箭头函数
- 需要 this 指向调用对象的时候,如给DOM绑定事件时、对象中的方法、原型的方法
- 需要使用 arguments 时,不适合用箭头函数,因为箭头函数没有arguments
四、 解构赋值
4.1 数组的解构赋值
4.1.1 解构赋值的原理
- 模式(结构)的匹配:右侧是数组,则左侧也为数组 []
[] = [1,2,3]
- 索引值相同的完成赋值
[a,b,c] = [1,2,3] // a=1,b=2,c=3
- 可忽略:如果不需要赋值的,可以使用逗号跳过
// 获取1,4,6
const [a,[,,b],c] = [1,[2,3,4,5],6]
console.log(`${a} ${b} ${c}`) // 1 4 6
4.1.2 数组解构赋值的默认值
- 当匹配不到数据或者匹配到的是undefined(只能是undefined,null不可以)就会使用默认值
- 默认值通过在左侧进行设置
const [a=1,b=2] = []
- 如果默认值是表达式,默认值表达式是惰性求值的(只有用到默认值时才会执行)
4.1.3 常见的类数组的解构赋值
- arguments
用于获取传递的参数,是一个类数组对象
function fun() {
console.log(arguments) // Arguments(3) [2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
fun(2,3,4)
- arguments的解构赋值和数组一样
- NodeList
一个类数组对象
<p>我是1</p>
<p>我是2</p>
<p>我是3</p>
<script>
const [p1,p2,p3] = document.querySelectorAll('p')
console.log(p1) //<p>我是1</p>
console.log(p3) // <p>我是3</p>
</script>
4.1.4 函数参数的解构赋值
const array = [6,21]
const add = ([x,y]) => x+y
console.log(add(array)) //27
4.1.5 交换变量
let x = 92;
let y = 23;
[x,y] = [y,x]
console.log(x,y) // 23 92
4.2 对象的解构赋值
4.2.1 对象解构赋值的原理
- 模式(结构)匹配:左侧为花括号{}
- 属性名相同的完成赋值
const {name,age} = {
name:'dudu',
age:23
}
console.log(name)
console.log(age)
- 属性名和属性值相同可以简写
- 在解构赋值时,如果需要更改属性名,可以通过修改左侧
原属性名:修改后的属性名
{
name:name ===> 简写为name即可
name:nickname // 修改成了nickname
}
4.2.2 对象解构赋值的注意事项
- 默认值
- 当对象的属性值严格等于(===)undefined时,对应的默认值才会生效
- 默认值是通过
等号=
设置的
const {name='嘟嘟',age} = {
age:23
}
console.log(name) // 嘟嘟
console.log(age) // 23
- 如果默认值是表达式,默认值表达式是惰性求值的(只有用到默认值时才会执行)
- 将一个已经声明的变量用于解构赋值
- 此时需要用圆括号包裹解构赋值的内容
let name = '嘟嘟';
({name}= {name:'dudu'})
console.log(name) // dudu
- 对象的解构赋值可以获取到继承的属性
- 函数参数作为对象时的解构赋值,参数的圆括号不可以省略
const info = ({name,age}) => console.log(`我是${name},今年${age}岁~~`)
let person = {
name:'嘟嘟',
age:18
}
info(person)
- 对象的结构赋值如果有不需要的属性,直接不写即可,不需要用逗号占位
const PLAYER = {
nickname:"一条贪吃蛇",
master:'东海龙王',
skill:[{
skillName:'龙吟',
mp:'100',
time:6000
},{
skillName:'龙卷雨击',
mp:'400',
time:3000
},{
skillName:'龙腾',
mp:'900',
time:6000
}]
}
const { master } = PLAYER //取第二个元素时,不用用逗号忽略掉第一个,可以直接取
console.log(master) //'东海龙王'
const {skill:[skill1,{skillName},{skillName:skillName3}]} = PLAYER
console.log(skillName) //龙卷雨击
console.log(skillName3) // 龙腾
4.3 其他类型的解构赋值
4.3.1 字符串的解构赋值
- 数组形式
通过顺序匹配(空格分隔)
let str = 'hello'
const [a,b,,,c] = str
console.log(a+' '+b+' '+c) // h e o
- 对象形式
let str = 'hello'
const {0:a,1:b,4:c} = str
console.log(a+' '+b+' '+c) // h e o
4.3.2 数值和布尔值的解构赋值
- 会先将等号右边的值转换为对象,再进行对象的解构赋值
4.3.3 undefined 和 null 的解构赋值
- 因为undefined和null无法转换为对象,使用他们的解构赋值会报错
五、对象字面量的增强
5.1 属性和方法的简洁表示法
- 属性:键名和变量名或者常量名一致时,可以简写为一个
- 方法:可以省略冒号和function关键字
let name = 'dudu'
const person = {
name, // 相当于:name:name
sayhello() {} // sayhello:function() {}
}
5.2 方括号语法
- ES6之前的方括号语法:参考 文章 访问属性的讲解
- ES6 的方括号语法可以写在对象字面量中
const prop = 'name'
const person = {
[prop]:'嘟嘟'
}
console.log(person) // {name: '嘟嘟'}
- 方括号里可以放值或者通过计算可以得到的值(表达式)
六、函数参数的默认值
- 调用函数的时候传参了,就用传递的参数;如果没有传参,就用默认值
- 默认值直接用
等号
赋值即可 - 不传参数,或者明确的传递undefined作为参数,只有在这两种情况下默认值才生效
- 表达式默认值是惰性求值的
- 函数参数的默认值,最好从参数列表的右边开始设置。如果从左边开始,调用函数使用默认值时需要把对应参数的值设置为undefined
const multiply = (x=2,y) => x*y
console.log(multiply(undefined,4))