简单总结了一下,其实只是语法层面的变化,内部并没有什么区别
var、let、const
var 和 let 的区别
都是用来声明变量
var 没有块级作用域,会导致一些不必要的麻烦
let 有块级作用域,是更完美的 var
我基本不用var
1. var 可声明前置
并且可以重复声明
a = 1
var a
var a = 2
// 不报错
2. let 不可以声明前置
a = 1
let a
// 报错
3. let 不可重复声明
let a = 1
let a = 2
// 报错
let a = 1
var a = 2
// 报错
4. let 存在块级作用域
作用域可以认为是两个大括号之间的区域
function fn() {
let a = 1
console.log(a)
}
console.log(a)
// 报错
5. let 暂时性死区
在 let 声明变量之前都是该变量的死区,在死区内不可使用该变量
这也需要拿出来说?
const
用来声明常量
拥有 let 的特性,但是被声明的常量必须赋值,而且值不可改变!
被 const 声明的常量不可改变
示例1:
const a = 1
a = 2 // 报错
能理解!简单嘛!
示例2:
const obj = { a: 1 }
obj.a = 2 // 不报错
obj = { a: 2 } // 报错
啊你骗人,你明明说了不可改变,那为什么 obj.a = 2 不报错?!?!
我们先来说说示例1:
示例1的 a 是简单类型,所以直接赋值的话,相当于改变 a 的值
再说说示例2:
- 这里的 obj 是属于复杂类型,或者引用类型的时候,那 obj 存的就是 { a: 1 } 的地址啊!那只要地址不变,那就没有问题啊!
那给 obj.a = 2,那 obj 里面存的地址变没变啊?
因为指向的还是这个对象,只不过对象里面的东西发生了改变。
- 但是这么写 obj = { a: 2 },这个意思是我新生成了个对象,然后赋值给 obj,那这个 obj 的地址是不是变了呀?那就会报错嘛!
哦哦...似懂非懂
小结
- 请大量地使用 let,你都用 ES6 的语法了,还用什么 var
- 你觉得不可变的,那就用 const,比如引用一个模块、定义一个全局的url
解构赋值
按照一定模式,从数组和对象中提取值变量,对变量进行赋值,直接看代码!
数组的解构赋值
1. 基本用法
// ES5 写法
let a = 1
let b = 2
let c = 3
// 或
let a = 1, b = 2, c = 3
// ES6 解构赋值
let [a, b, c] = [1, 2, 3]
// 这种情况下,只要值对应得上,依然可以解构
let [a, b] = [1, 2, 3]
let [a, [b], c] = [1, [2], 4]
// 这种就直接报错啦,左边是个数组,右边都不是数组
let [a] = 1;
2. 默认值
跟函数的默认参数类似,哦?没学过?后面会说 链接
let [a] = [1]
// 1
let [a] = []
// undefined 不设置默认值,默认等于undefined
let [a, b = 2] = [1]
// 1 2
let [a = 1, b = 2] = [2]
// 2 2
let [a, b = 2] = [1, 3]
// 1 3
let [a = 1] = []
// 1
let [a = 1] = [null]
// null 因为 null 不严格等于 undefined,所以默认值不生效
默认值:设置了,就用你设置的;没设置,就用 undefined
对象的解构赋值
前置知识
let [name, age] = ['heycn', 22]
let a = { name, age }
// 等同于
let a = { name: name, age: age }
1. 基本用法
let { name, age } = { name: 'heycn', age: 22 }
name // "heycn"
age // 22
2. 默认值
不设置,默认值就是 undefined!
let { x, y = 2 } = { x: 1 }
x // 1
y // 2
函数的解构赋值
function add([a, b] = [1, 2]) {
return a + b
}
add() // 3
作用
// 我在 vscode 写完格式的话的时候,vscode 会有骚操作,请在浏览器上运行!
let [x, y] = [1, 2]; 一定要加分号!这是在数组前面!
[x, y] = [y, x]
// [2, 1]
字符串、数组、函数、对象
字符串
1. 多行字符串
let str = `
Hi
这是多行字符串
是不是很方便
`
// 但是在转义后的时候会有问题
2. 模板字符串
可以更方便的拼接啦!
let name = 'heycn'
let helloWorld = `我是${name}`
helloWorld // "我是heycn"
数组
1. 拓展运算符
也叫展开运算符,将一个数组转为用逗号分隔的参数序列,可以更方便的插入
let a = [1, 2, 3]
console.log(...a)
// 1 2 3
let a = [1, 2, 3]
let b = [...a, 4, 5]
b // [1, 2, 3, 4, 5]
2. 运用:函数参数的拓展
function sort(...arr) {
console.log(arr.sort())
}
sort(2, 4, 1, 3)
// [1, 2, 3, 4]
3. 运用:类数组对象转数组
let ps = document.querySelectorAll('p')
Array.from(ps).forEach(p => {
console.log(p.innerText)
})
[...p].forEach(p=>{console.log(p.innerText)})
函数
1. 函数的默认值
设置了,就用你设置的;没设置,就用 undefined
很好理解,没什么好讲
function myName(name = 'heycn') {
console.log(`My name is ${name}`)
}
myName() // My name is heycn
myName('小陈') // My name is 小陈
2. 函数的默认值:这两种写法的区别?
多看两遍就能悟出来了
// 函数 fn1
function fn1({ x = 0, y = 0 } = {}) {
return [x, y]
}
// 函数 fn2
function fn2({ x, y } = { x: 0, y: 0 }) {
return [x, y]
}
// 函数没有参数的情况
fn1() // [0, 0]
fn2() // [0, 0]
// x 和 y 都有值的情况
fn1({ x: 3, y: 8 }) // [3, 8]
fn2({ x: 3, y: 8 }) // [3, 8]
// x 有值,y 无值的情况
fn1({ x: 3 }) // [3, 0]
fn2({ x: 3 }) // [3, undefined]
// x 和 y 都无值的情况
fn1({}) // [0, 0]
fn2({}) // [undefined, undefined]
// 传递新的东西
fn1({ z: 3 }) // [0, 0]
fn2({ z: 3 }) // [undefined, undefined]
- fn1:调用函数需要你传递一个对象,如果你没有传对象就是用**默认值对象 {} **,默认值对象里面都是 undefined
- fn2:参数需要是一个对象,如果没传对象,就是用默认值对象 { x: 0, y: 0} ,如果传了对象,就使用你传递的对象
3. 箭头函数
箭头函数没有没有 this , 一开始看会有点不适应,多写就能明白了
let fn = n => {n + 1} // 只有一个参数的话,小括号可以省略
// 等价于
let fn = function (n) {return n + 1}
let fn = () => 1 // 注意对比返回值
// 等价于
let fn = function () {return 1}
let fn = (a, b) => a + b // 看出区别了吗,直接 return 可以省略大括号
// 等价于
let fn = function (a, b) {return a + b}
对象
1. 属性的简写
let name = 'heycn'
let age = 22
let people = { name, age }
// {name: "heycn", age: 22}
2. 函数的简写
let helloWorld = {
hello() {
console.log('Hello')
},
world() {
console.log('World')
}
}
helloWorld.hello() // Hello
helloWorld.world() // World
模块:导出与导入
ES6 在导入和导出方面又有哪些改变呢?
导出
1. 写法1
// index.js
export let name = 'heycn'
export let age = '22'
export function getName() {}
2. 写法2
// index.js
let name = 'heycn'
let age = '22'
export function getName() {}
export { name, age, getName }
3. 默认导出
export default
// index.js
export default function () {
console.log('HelloWorld')
}
导入
1. 示例1
import { name, age, getName } from './index.js' // 这也相当于是个解构赋值
2. 导入 - 默认导出的模块
import fn from './index.js'
类 和 继承
说实话 这我很少用啊...可是面试会被问啊!
类
1. 构造函数
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello() {
console.log(`hello, ${this.name}, i am ${this.age} years old`)
}
}
2. 静态方法
class EventCenter {
static fire() {
return 'fire'
}
static on() {
return 'on'
}
}
继承
多写几遍就行了
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello() {
console.log(`hello, ${this.name}, i am ${this.age} years old`)
}
}
class Student extends Person {
constructor(name, age, score) {
super(name, age)
this.score = score
}
sayScore() {
console.log(`hello, ${this.name}, i am ${this.age} years old, i get ${this.score}`)
}
}