② 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. 特点

  1. 不属于顶层对象 window

  2. 不允许重复声明

  3. 不存在变量提升

  4. 暂时性死区

  5. 块级作用域

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
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'
posted on 2022-05-16 20:26  pleaseAnswer  阅读(27)  评论(0编辑  收藏  举报