② ES6 必备知识
1 新的声明方式
1.1 作用域
对象 | 类型 |
---|---|
global/window | 全局作用域 |
function | 函数作用域(局部作用域) |
{} | 块级作用域 |
this | 动态作用域 |
1.2 新的声明方式 let
1. 不属于顶层对象 window
- var 声明的顶层对象与全局变量挂钩,污染全局变量
var a = 5
console.log(a);
b = 6
console.log(b);
// 顶层对象与全局变量挂钩,污染全局变量
console.log(window.a);
console.log(window.b);
delete a
console.log(a);
// delete 只能删除对象属性 不能删除变量
delete b
console.log(b);
2. 不允许重复声明
3. 不存在变量提升
console.log(a); // undefined
var a = 5
// var a
// console.log(a);
// a = 5
console.log(c); // Uncaught ReferenceError: Cannot access 'c' before initialization
let c= 5
4. 暂时性死区
- 在代码块内,使用
let
命令声明变量之前,该变量都是不可用的
// a = b 赋值时,b还没声明
function foo(a = b, b = 3) {
console.log(a, b);
}
foo()
5. 块级作用域
for(var i = 0; i < 3; i++) {
console.log('循环内', i)
}
console.log('循环外', i); // 3
for(let j = 0; j < 3; j++) {
console.log('循环内', j)
}
console.log('循环外', j); // Uncaught ReferenceError: j is not defined
if(false) var a = 5
if(false) let b = 5 // Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context
for(var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
})
}
// 闭包:内部函数调用外部函数的变量,外部函数的变量不被释放
for(var i = 0; i < 3; i++) {
(j => {
setTimeout(() => {
console.log(j);
});
})(i)
}
for(let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
})
}
// babel 编译之后
var _loop = function _loop(i) {
setTimeout(() => {
console.log(i);
})
}
for(var i = 0; i < 3; i++) {
_loop(i)
}
1.3 新的声明方式 const
1. 特点
-
不属于顶层对象
window
-
不允许重复声明
-
不存在变量提升
-
暂时性死区
-
块级作用域
2. ES5 定义常量
Object.defineProperty(window, 'PI', {
value: 3.14,
writable: false
})
console.log(PI); // 3.14
PI = 5
console.log(PI); // 3.14
3. ES6 定义常量
const a = 5
a = 6 // Uncaught TypeError: Assignment to constant variable.
const b
b = 5 // Uncaught SyntaxError: Missing initializer in const declaration
![](https://img2022.cnblogs.com/blog/1891336/202205/1891336-20220516202646214-616739682.png)
const obj = {
name: 'zhouzhou',
age: 34
}
console.log(obj);
obj.school = 'imooc'
console.log(obj);
const arr = [1, 2, 3]
arr.push(4)
console.log(arr);
- 浅层冻结对象,使得对象不能被改变
Object.freeze(obj)
const obj = {
name: 'zhouzhou',
age: 34,
skill: {
name: 'code',
year: 3
}
}
Object.freeze(obj)
console.log(obj);
obj.school = 'imooc'
console.log(obj);
obj.skill.year = 5
console.log(obj);
2 解构赋值
2.1 数组解构
let [a, b, c] = [1, 2, 3]
console.log(a, b, c);
let [a, b, [c, d]] = [1, 2, [3, 4]]
console.log(a, b, c, d);
// 默认值是惰性的
let [a, b, c, d = 5] = [1, 2, [3, 4], 6]
console.log(a, b, c, d);
2.2 对象解构
let user = {
name: 'zhouzhou',
age: 18
}
let { name, age } = user
console.log(name, age);
// 别名
let user = {
name: 'zhouzhou',
age: 18
}
let { name: uName, age: uAge } = user
console.log(uName, uAge);
2.3 字符串解构
let str = 'imooc'
let [a, b, c, d, e] = str
console.log(a, b, c, d, e);
2.4 参数解构
function foo([a,b,c]) {
console.log(a,b,c);
}
let arr = [1,2,3]
foo(arr)
function foo({name, age = 12}) {
console.log(name, age);
}
let obj = { name: 'zhpouzhou', age: 18 }
foo(obj)
function foo() {
let obj = { name: 'zhpouzhou', age: 18 }
return obj
}
let {name, age} = foo()
console.log(name, age);
2.5 提取 json 数据
let json = '{ "a": "hello", "b": "world" }'
let { a, b } = JSON.parse(json)
console.log(a, b);
3 数组的各种遍历方式
3.1 ES5 数组方法
1. for
- 可使用
break
退出循环
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
2. forEach
- 不支持
break
continue
arr.forEach(function(ele, index, array) {
console.log('forEach', ele, index, array);
})
3. map
- 不改变原数组的值
let result = arr.map(function(value) {
value += 1
return value
})
console.log('map', arr, result);
4. filter
- 过滤出符合要求的值,不改变原数组
let filterRes = arr.filter(function(value) {
return value == 2
})
console.log('filter', arr, filterRes);
5. some
- 返回值 true | false
let someRes = arr.some(function(value) {
return value == 2
})
console.log('some', arr, someRes);
6. every
- 返回值 true | false
let everyRes = arr.every(function(value) {
return value == 2
})
console.log('every', arr, everyRes);
7. reduce
- 求和
let sum = arr.reduce(function(prev, cur, index, arr) {
return prev + cur
})
console.log('reduceSum', sum);
- 求最大值
let max = arr.reduce(function(prev, cur) {
return Math.max(prev, cur)
})
console.log('reduceMax', max);
- 去重
let reduceRes = arr.reduce(function(prev, cur) {
prev.indexOf(cur) == -1 && prev.push(cur)
return prev
}, [])
console.log(reduceRes);
8. for..in
Array.prototype.foo = function() {
console.log('foo');
}
for(let index in arr) {
console.log(index, arr[index]);
}
3.2 ES6 数组方法
1. find
let res = arr.find(function(value) {
return value == 2
})
console.log(arr, res);
2. findIndex
let indexRes = arr.findIndex(function(value) {
return value == 2
})
console.log(indexRes);
3. for..of
for(let item of arr) {
console.log(item);
}
Array.prototype.values()
for(let item of arr.values()) {
console.log(item);
}
Array.prototype.keys()
for(let item of arr.keys()) {
console.log(item);
}
Array.prototype.entries()
for(let [index, item] of arr.entries()) {
console.log(index, item);
}
4 数组的扩展
4.1 伪数组
let divs = document.getElementsByTagName('div')
console.log(divs); // HTMLCollection []
console.log(divs instanceof Array); // false
let divs3 = document.querySelectorAll('.xx')
console.log(divs3); // NodeList []
console.log(divs3 instanceof Array); // false
function foo() {
console.log(arguments, arguments instanceof Array);
}
foo(1, 'imooc', true)
ES5 伪数组 -> 数组:slice
let arr = Array.prototype.slice.call(divs3)
console.log(arr); // []
console.log(arr instanceof Array); // true
4.2 Array.from()
let arrLike = {
0: 'es6',
1: 'es7',
2: 'es8',
length: 3
}
let arrRes = Array.from(arrLike)
console.log(arrRes); // ['es6', 'es7', 'es8']
4.3 Array.of()
let arr1 = new Array(1, 2)
console.log(arr1); // [1, 2]
let arr2 = new Array(3)
console.log(arr2); // [empty × 3]
let arr3 = Array.of(1, 2)
console.log(arr3); // [1, 2]
let arr4 = Array.of(3)
console.log(arr4); // [3]
let arr5 = Array.of(1, true, 'imooc', [1,2,3])
console.log(arr5); // [1, true, 'imooc', Array(3)]
4.4 元素替换 copyWithin()
let arr = [1, 2, 3, 4, 5]
let arr2 = arr.copyWithin(1, 3) // (起始被替换位置,替换的位置, 终止位置)
console.log(arr2); // [1, 4, 5, 4, 5]
4.5 元素填充 fill()
let arr = new Array(3).fill(7)
console.log(arr); // [7, 7, 7]
let arr1 = [1,2,3,4,5]
arr1.fill('imooc', 1, 3) // (替换元素, 被替换起始位置, 被替换终止位置)
console.log(arr1); // [1, 'imooc', 'imooc', 4, 5]
let arr2 = [1,2,3,4,5]
arr2.fill(0)
console.log(arr2); // [0, 0, 0, 0, 0]
4.6 includes()
indexOf
不能检测NaN
let arr = [1, 2, 3, NaN]
console.log(arr.indexOf(2)); // 1
console.log(arr.indexOf(4)); // -1
console.log(arr.indexOf(NaN)); // -1
console.log(NaN == NaN); // false
console.log(arr.includes(NaN)); // true
5 函数的参数
5.1 默认参数
function foo(x, y = 'world') {
// y = y || 'world'
console.log(x, y)
}
foo('hello', 0)
// 形参重名
// Argument name clash
function foo(x, x, y = 'world') {
console.log(x, y)
}
foo('hello', 0)
function foo(x, y = 'world', z) {
console.log(x, y, z)
}
foo('hello',0)
5.2 与解构赋值结合
function foo({ x, y = 5 }) {
console.log(x, y);
}
foo() // Cannot read properties of undefined (reading 'x')
- 与解构赋值结合
function ajax(url, {
body = '',
method = 'GET',
headers = {}
} = {}) {
console.log(method);
}
ajax('http://baidu.com')
ajax('http://baidu.com', { method: 'POST' })
5.3 length 属性
- 函数的长度 = 函数没有默认值的参数个数
function foo(x, y = 3, z = 3) {
console.log(x, y);
}
console.log(foo.length);
5.4 作用域
let x = 1
// 函数内部的x 是函数作用域的x,而不是全局的x
function foo(x, y = x) {
console.log(y); // 2
}
foo(2)
let x = 1
// y = x时没找到x,会沿着作用域链往外找
function foo(y = x) {
let x = 2
console.log(y); // 1
}
foo()
// ReferenceError: x is not defined at foo
function foo(y = x) {
let x = 2
console.log(y);
}
foo()
5.5 函数的 name 属性
console.log((new Function).name); // anonymous 匿名函数
function foo(x, y) {
console.log(this, x, y);
}
foo.bind()
foo.bind({ name: 'zhouzhou' })() // {name: 'zhouzhou'}
foo.bind({ name: 'zhouzhou' }, 1, 2)() // {name: 'zhouzhou'} 1 2
foo.bind({ name: 'zhouzhou' })(1, 2) // {name: 'zhouzhou'} 1 2
console.log((function(){}).bind({}).name); // bound
6 扩展运算符与剩余参数运算符
...
-
扩展运算符:把数组或者类数组展开成用逗号隔开的值
-
剩余参数运算符:把逗号隔开的值组合成一个数组
6.1 扩展运算符
function foo(a, b, c) {
console.log(a, b, c);
}
let arr = [1, 2, 3]
console.log(...arr);
foo(...arr)
1. 合并数组
// 合并数组
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
// ES5
Array.prototype.push.apply(arr1, arr2)
console.log(arr1);
// ES6
arr1.push(...arr2)
console.log(arr1);
2. 字符串 -> 数组
let str = 'imooc'
let arr = [...str]
console.log(arr);
6.2 剩余参数运算符
// es5
function foo(x, y, z) {
console.log(arguments);
let sum = 0
Array.prototype.forEach.call(arguments, function(item) {
sum += item
})
return sum
}
console.log(foo(1, 2)); // 3
console.log(foo(1, 2, 3)); // 6
// es6
function foo(x, y, z) {
console.log(arguments);
let sum = 0
Array.from(arguments).forEach(function(item) {
sum += item
})
return sum
}
console.log(foo(1, 2)); // 3
console.log(foo(1, 2, 3)); // 6
// 不确定参数时
function foo(...args) {
console.log(args);
let sum = 0
args.forEach(function(item) {
sum += item
})
return sum
}
console.log(foo(1, 2));
console.log(foo(1, 2, 3));
function foo(x, ...args) {
console.log(x, args);
}
foo(1, 2) // 1, [2]
foo(1, 2, 3) // 1, [2, 3]
let [x, ...y] = [1, 2, 3]
console.log(x); // 1
console.log(y); // [2, 3]
7 箭头函数
7.1 ES5 中函数声明方式
// 存在函数预定义
function sum1(x, y) {
return x + y
}
// var变量提升 let不存在变量提升
let sum2 = function(x, y) {
return x + y
}
7.2 箭头函数
let sum = (x, y) => {
return x + y
}
console.log(sum(4,5));
let sum = (x, y) => x + y
console.log(sum(4,5));
1. this 指向定义时所在的对象,而不是调用时所在的对象
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', function() {
setTimeout(() => {
console.log(this); // DOM节点
}, 1000);
setTimeout(function() {
console.log(this); // window对象
}, 1000);
})
2. 不可以当做构造函数
// 类
// function People(name, age) {
// this.name = name
// this.age = age
// }
// People is not a constructor at <anonymous>
let People = (name, age) => {
this.name = name
this.age = age
}
let p1 = new People('zhouzhou', 12)
console.log(p1);
3. 不可以使用 arguments 对象
// let foo = function() {
// console.log(arguments);
// }
// arguments is not defined at foo
let foo = () => {
console.log(arguments);
}
// 使用rest运算符代替arguments
let foo = (...args) => {
console.log(args); // [1, 2, 3]
}
foo(1, 2, 3)
8 对象的扩展
1. 属性简洁表达法
- 键值对同名,只写键名
let name = 'zhouzhou'
let age = 12
let s = 'school'
let obj = {
name,
age,
[s]: 'imooc'
}
console.log(obj);
2. 属性名表达式
let name = 'zhouzhou'
let obj = {
name,
study() {
console.log(this.name + '正在学习');
}
}
obj.study()
3. Object.is
console.log(Object.is(2, '2')); // false
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false
let obj1 = { name: 'zhou', age: 12 }
let obj2 = { name: 'zhou', age: 12 }
console.log(Object.is(obj1, obj2)); // false
let obj3 = obj1
console.log(Object.is(obj1, obj3)); // true
4. 扩展运算符与 Object.assign()
let x = { a: 3, b: 4 }
let y = { ...x }
let z = { a: 6 }
Object.assign(z, x)
console.log(y); // {a: 3, b: 4}
console.log(z); // {a: 3, b: 4}
5. in
let x = { a: 3, b: 4 }
console.log('a' in x); // true
console.log('aa' in x); // false
let arr = [1, 2, 3]
console.log(3 in arr); // false 数组下标3位置是否有值
6. 对象的遍历方式
let obj = {
name: 'zouzhou',
age: 12,
schoole: 'imooc'
}
for..in
for(let key in obj) {
console.log(key, obj[key]);
}
Object.keys()
Object.keys(obj).forEach(key => {
console.log(key, obj[key]);
})
Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj).forEach(key => {
console.log(key, obj[key]);
})
Reflect.ownKeys()
Reflect.ownKeys(obj).forEach(key => {
console.log(key, obj[key]);
})
9 深拷贝与浅拷贝
9.1 浅拷贝
let obj1 = { name: 'zouzou', age: 12 }
let obj2 = obj1
console.log(obj2);
obj1.age = 18
console.log(obj2);
1. Object.assign()
let target = {
a: {
b: {
c: 1
},
e: 4,
f: 5,
g: 6
}
}
let source = {
a: {
b: {
c: 1
},
e: 2,
f: 3
}
}
Object.assign(target, source)
console.log(target); // { a: { b: {c: 1}, e: 2, f: 3 }}
9.2 深拷贝
1. JSON
let obj1 = { name: 'zouzou', age: 12 }
// 对象 -> JSON
let str = JSON.stringify(obj1)
// JSON -> 对象
let obj2 = JSON.parse(str)
obj1.age = 18
console.log(obj2);
2. 函数封装 -- 递归
let checkType = data => {
return Object.prototype.toString.call(data).slice(8, -1)
}
let deepClone = target => {
let targetType = checkType(target)
let result
if(targetType === 'Object') {
result = {}
} else if(targetType === 'Array') {
result = []
} else {
return target
}
for(let i in target) {
let value = target[i]
let valueType = checkType(value)
if(valueType === 'Object' || valueType === 'Array') {
result[i] = deepClone(value) // 递归
} else {
result[i] = value
}
}
return result
}
let arr = [1, 2, { age: 12 }]
let arr2 = deepClone(arr)
arr2[2].age = 18
let obj = {
name: 'zouzou',
hobby: ['coding', 'eating']
}
let obj2 = deepClone(obj)
obj2.hobby[0] = 'sleeping'