ES6

 

let 与 const

var 和 let 区别

var 和 let 都是用来声明变量,但是两者有很大的区别

1、let 变量不能被重复声明

// 使用 let
let star;
let star;

报出:
let star;
    ^
SyntaxError: Identifier 'star' has already been declared   // 语法错误

// 使用 var
var star; 
var star;
// 将不会报出语法错误

2、let 拥有块级作用域,也称’暂时性死区’,不影响作用域链的效果

// 使用 let 
{
  let star = 'hello world';
}
console.log(star);

报出:
console.log(star)
            ^
ReferenceError: star is not defined      // 引用错误


// 使用 var
{
  var star = 'hello world';
}
console.log(star);  // 正常输出 'hello world'

3、let 不存在变量提升,var 存在变量提升

// 使用 let
console.log(cat);
let cat = 'xiaobai';

报出:
console.log(cat)
            ^
ReferenceError: Cannot access 'cat' before initialization      // 引用错误

// 使用 var
console.log(cat);    // cat 变量被提升,输出 undefined
var cat = 'xiaobai';

举个经典例子:

样式代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .item {
      float: left;
      margin: 30px;
      width: 100px;
      height: 100px;
      border: 1px solid #ff6600;
    }
  </style>
</head>
<body>
  <div>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>

  <script src="./let.js"></script>
</body>
</html>

js代码:

let items = document.querySelectorAll('.item');

for (var i = 0; i < items.length; i++) {
  items[i].onclick = function () {
    items[i].style.background = 'blue';
  }
}

效果如上图所示,当我们点击第一,第二,或者第三个块时,类型错误,就是没有找到 item[i] 这个变量,这是由于使用 var 定义的变量。

在for循环中这个块中使用var声明的变量,默认就是全局变量,在 window 上,可以直接访问到。而在for循环这个块中访问到的是全局的变量 i , i++ 在执行完之后,此时在 window.i = 3

这时就用到了,let 声明变量,就会在for循环这个块中,产生一个块级作用域,与全局作用域无关,items[i] 就是我们想要的变量。


const 特性

const 的特性 基本和 let 一致,比如,变量不能被重复声明,拥有块级作用域,不存在变量提升。

但是 const 也有自己的特性:

1、const 声明的变量为常量,潜规则写法是,变量名都要大写,比如 const STAR = 'white';

2、const 声明变量,必须被赋值;

3、const 声明的变量为常量,因此不能被重新赋值,但是对象和数组除外,因为数组和对象里面的值被改变时,引用的内存地址没有发生变化,所以不会出现错误;

解构赋值

ES6 允许按照一定模式从数组和对象中提取值,对变量进行解构赋值。

解构赋值最大程度上解决了,ES5 的利用属性取值,比如 obj.a

对象解构赋值的几种方式:

1、完全解构

const CAT = {
  a: 10,
  b: 20,
  c: 'nihao'
}

const {a, b, c} = CAT

2、不完全解构

const CAT = {
  a: 10,
  b: 20,
  c: 'nihao'
}

const {a, b} = CAT   // 只取出 a, b

3、剩余运算符

const CAT = {
  a: 10,
  b: 20,
  c: 'nihao'
}

const {a, ...res} = CAT
console.log(res)   // 输出 {a: 20, c: 'nihao'}

4、默认值

const {a, b = 20} = {a: 10}

数组解构:

1、数组完全解构

const NUM = [1, 2, 3];
const [a, b, c] = NUM;

2、嵌套数组解构

const NUM = [1, [2], 3];
const [a, [b], c] = NUM;  // NUM 数组里面有一个嵌套的数组,此时必须用 [b] 来解构 [2]

模板字符串

ES6 引入新的声明字符串的方式 `` , 对比 ‘’, “” 的有点:

1、内容可直接换行,不用再使用 ‘+’ 拼接

2、可以直接拼接变量

let white = '小白';
let cat = `<ul>
            <li>你好,${white}</li>
          </ul>`;
console.log(cat);

直接输出:
<ul>
    <li>你好,${white}</li>
</ul>

rest 参数

rest 参数,用于获取函数的实参,代替 arguments

当我们使用 arguments 时:

function date() {
  console.log(arguments);
}
date(1, 2, 3, 4);

打印台输出:

可以看到 arguments 原型中 constructor 属性为 Object,这就说明了 arguments 并不是数组,因此不能使用数组的方法,因此在处理多个参数时,并不能使用更加方便的数组方法进行处理。

接下来,我们再看一下 rest 获取参数的类型:

function date(...args) {
  console.log(args);
}
date(1, 2, 3, 4);

打印台输出可以清楚的看到,rest 获取到的参数时数组类型,可以使用数组的方法进行操作它。

rest 参数必须放到参数的最后面:

function data(a, b, ...args) {
  console.log(a);  // 1
  console.log(b);  // 2
  console.log(args); // [3, 4]
}
data(1, 2, 3, 4);

扩展运算符

... 扩展运算符可以将 数组 转化为 逗号 分隔的参数序列。

const arr = [1, 2, 3]
function foo() {
    console.log(arguments) // 1, 2, 3
}
foo(...arr)

应用:

数组的合并

const arr1 = [1, 2, 3]
	  arr2 = [4, 5, 6]
const newArr = [...arr1, ...arr2]
console.log(newArr) // [1, 2, 3, 4, 5, 6]

数组的克隆

const arr = [1, 2, 3]
const newArr = [...arr]
console.log(newArr) // [1, 2, 3]

将伪数组或类数组转换成真正的数组

function foo() {
    const args = [...arguments]
    console.log(args)  // [1, 2, 3]
}
foo(1, 2, 3)

Symbol 新增数据类型

ES6 新引入的基础数据类型,表示独一无二的值,是一种类似于字符串的类型。

Symbol 特点:

值是唯一的,用来解决命名冲突
不能与其他数据类型进行运算
定义的对象属性,不能使用 for···in 遍历,但是可以用Reflect.ownKeys 来获取对象的所有键名
Symbol 的创建:
 

const s1 = Symbol('1')
// 或者:
const s2 = Symbol.for('1')

// 给对象添加 Symbol 类型的属性,保护对象属性的安全性
const obj = {
	name: 'xiaobai',
    [Symbol('say')]: function() {
        console.log('说话')
    }
}
obj.[Symbol('say')]()

// 或者
const obj1 = {
	up: '',
    dowm: ''
}
const methods = {
    up: Symbol(),
    dowm: Symbol()
}
obj[methods.up] = function() {
	
}
obj[methods.down] = function() {
	
}
// 这样创建的 up 和 dowm 方法是唯一的,不会和obj1中的up,dowm 属性发生冲突,保护了属性的安全。

迭代器(Iterator)

迭代器是一种接口,为不同的数据结构提供统一的访问机制。任何数据结构只要部署了 Iterator 接口,就可以进行遍历。

ES6 新的遍历方式,for···of 循环,Iterator 接口主要供 for···of 使用。

可使用 for···of 循环的数据:

Array,arguments,set,map,String,NodeList
 

const arr = ['red', 'black', 'blue']

for(let i of arr) {
	console.log(i)  // 'red' 'black' 'blue'
}

for(let i in arr) {
    console.log(i)  // 1, 2, 3
}

如何使用 for...of 遍历自定义的数组呢,比如对象中不包含 迭代器(Iterator),但是可以自定义一个迭代器。

// 直接使用 for...of 遍历对象
const obj = {
  arr: ['red', 'blue', 'green']
}

for(let i of obj) {
  console.log(i) // Uncaught TypeError: obj is not iterable
}

// 给对象添加一个迭代器
const obj = {
  color: ['red', 'blue', 'green'],

  [Symbol.iterator]() {
    let index = 0
    return {
      next: () => {
        if (index < this.color.length) {
          const res = { value: this.color[index], done: false }
          index++
          return res
        }else {
          return { value: undefined, done: true }
        }
      }
    }
  }
}

for (let i of obj) {
  console.log(i)  // 'red' 'blue', 'green'
}

生成器(generator)

生成函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全相同。

使用

function * gen() {
  console.log('red')
  yield '1'
  console.log('blue')
  yield '2'
  console.log('green')
  yield '3'
}

const iterator = gen()
iterator.next() // 'red'
iterator.next() // 'blue'
iterator.next() // 'green'

yield 主要用作代码隔断,生成器(generator)在执行的时候必须使用生成器(iterator)的next() 迭代。一个 next() 只能迭代一段 yield 代码。

解决异步回调

function one() {
  setTimeout(() => {
    console.log(1)
    iterator.next()
  }, 1000);
}

function two() {
  setTimeout(() => {
    console.log(2)
    iterator.next()
  }, 2000);
}

function three() {
  setTimeout(() => {
    console.log(3)
  }, 3000);
}

function * gen() {
  yield one()
  yield two()
  yield three()
}

const iterator = gen()
iterator.next()

Promise

Promise 是 ES6 引入的异步编程解决方案。语法上 Promise 是一个构造函数,用来封装异步操作,并可以获取成功或失败的结果。

基本使用:

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    const data = 'hello world'
    // 成功返回的结果
    resolve(data)
    // 失败返回的结果
    // reject(data)
  }, 1000)
})

p.then(res => {
  console.log(res)  // 'hello world'
}, err => {
  console.log(err)
})

Promise 封装读取文件

const fs = require('fs')
const p = new Promise((resolve, reject) => {
  fs.readFile('./文件.md', (err, data) => {
    if(err) reject(err)
    resolve(data)
  })
})

p.then(res => {
  console.log(res.toString())
}, err => {
  console.log(err)
})

Promise封装 Ajax请求

const p = new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest()
  xhr.open('GET', 'https://www.baidu.com')
  xhr.send()
  xhr.onreadystatechange = () => {
    if(xhr.readyState === 4) {
      if(xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response)
      }else {
        reject(xhr.status)
      }
    }
  }
})

p.then(res => {
  console.log(res)
}, err => {
  console.error(err)
})

Set 集合

ES6 新的数据结构 Set(集合),虽然类似于数组,但是成员的每一个值都是唯一的。集合实现了迭代器(iterator)接口,所以可以使用扩展运算符(...)for...of进行遍历。

集合的属性和方法:

  • size:返回集合的元素个数
  • add:增加一个新元素,返回当前集合
  • delete:删除元素,返回一个Boolean值
  • has:检测集合中是否包含某个元素,返回Boolean值
  • clear:清空集合
const set = new Set(['red', 'blue', 'green'])

const res1 = set.has('red')
console.log(res1)  // true

const r2 = set.size
console.log(r2)  // 3

set.add('white')
console.log(set) // Set(4) {"red", "blue", "green", "white"}

set.delete('red')
console.log(set) // Set(3) {"blue", "green", "white"}

set.clear()
console.log(set) // Set(0) {}

Set集合的应用:

数组去重

const arr1 = [1, 2, 3, 3, 4, 2, 5]

const res1 = [...new Set(arr1)]
console.log(res1)  // [1, 2, 3, 4, 5]

两个数组取交集

const arr1 = [1, 2, 3, 3, 4, 2, 5]
const arr2 = [4, 5, 6, 7, 5, 6]

const res2 = [...new Set(arr1)].filter(item => {
  const s = new Set(arr2)
  if(s.has(item)) {
    return true
  }else {
    return false
  }
})
console.log(res2) // [4, 5]
// 或者
const res3 = [...new Set(arr1)].filter(item => new Set(arr2).has(item))
console.log(res3) // [4, 5]

两个数组并集(数组合并)

const arr1 = [1, 2, 3, 3, 4, 2, 5]
const arr2 = [4, 5, 6, 7, 5, 6]

const res4 = [...new Set(arr1), ...new Set(arr2)]
console.log(res4) // [1, 2, 3, 4, 5, 4, 5, 6, 7]

数组差集

const arr1 = [1, 2, 3, 3, 4, 2, 5]
const arr2 = [4, 5, 6, 7, 5, 6]

const res5 = [...new Set(arr1)].filter(item => !new Set(arr2).has(item))
console.log(res5) // [1, 2, 3]

Map

ES6 新的数据结构。类似于对象,键值对的集合。但是‘键’的范围不限于字符串。各种类型的值(包括对象)都可以当做键。Map 也实现了 iterator 接口,可以使用扩展运算符(...)for...of遍历。

Map 的属性和结构

  • size:返回Map元素的个数
  • set:增加一个新元素,返回当前 Map
  • get:返回键名对象的键值
  • has:检测 Map 中是否含某个元素,返回Boolean值
  • clear:清空集合

使用

const map = new Map()

map.set('name', 'zhangsan')
map.set('age', 18)
map.set('say', function() {
  console.log('hello')
})

console.log(map)  // {"name" => "zhangsan", "age" => 18, "say" => ƒ}

console.log(map.size) // 3

const res1 = map.get('name')
console.log(res1)  // '张三'

const res2 = map.has('age')
console.log(res2)  // true

const res3 = map.delete('say')
console.log(res3)  // true

对象(Object)方法的扩展

Object.is

判断两个值是否相等,相当于全等于(===),但是不能判断 NaN 和 (-0, 0)

console.log(Object.is(123, 123))  // true
console.log(Object.is('red', 'red'))  // true
console.log(Object.is(NaN, NaN))  // true
console.log(Object.is(-0, 0))  // false

Object.assign

对象合并,后一个对象中的属性值会覆盖前一个对象上的属性值,如果前一个对象中不存在后一个对象中的某个属性,就会在对象中添加这个属性。

const data1 = {
  name: 'zhangsan',
  age: 15,
  color: 'red'
}

const data2 = {
  name: 'zhangsan',
  age: 15,
  color: 'blue',
  height: 60
}

const data = Object.assign(data1, data2)
console.log(data)  // {name: "zhangsan", age: 15, color: "blue", height: 60}

Object.getPrototypeOf 和 Object.setPrototypeOf

const obj = {
  name: 'xiaobai'
}
const obj1 = {
  arr: [1, 2, 3]
}

Object.setPrototypeOf(obj, obj1)
console.log(obj)  // obj.__proto__.obj1 = arr
console.log(Object.getPrototypeOf(obj, obj1)) // {arr: [1, 2, 3]}

Object.values

Object.values 返回的是一个对象所有可枚举的属性值的数组

const stu = {
  name: 'zhangsan',
  age: 17,
  height: '60kg'
}

console.log(Object.keys(stu))  // ["name", "age", "height"]
console.log(Object.values(stu)) // ["zhangsan", 17, "60kg"]

Object.entries

Object.entries 返回一个给定对象自身可遍历的属性 [key, value] 的数组,还可将对象转化成一个二维数组

const stu = {
  name: 'zhangsan',
  age: 17,
  height: '60kg'
}

console.log(Object.entries(stu)) // [Array(2), Array(2), Array(2)]
                                 //  ["name", "zhangsan"]

Object.getOwnPrototyDescriptors

返回指定对象所有自身属性的描述对象

const stu = {
  name: 'zhangsan',
  age: 17,
  height: '60kg'
}

console.log(Object.getOwnPropertyDescriptors(stu))
// {name: {…}, age: {…}, height: {…}}
// name: {
//    configurable: true
//    enumerable: true
//    value: "zhangsan"
//    writable: true
//  }

Object.fromEntries

创建对象,接收的是一个二维数组,数组里面传键值对形式数组,可以接收 Map 数据格式

const stu1 = Object.fromEntries([
  ['name', 'zhangsan'],
  ['age', 18]
])

console.log(stu1) // {name: "zhangsan", age: 18}

const map = new Map()
map.set('name', 'lisi')
map.set('age', 17)
const stu2 = Object.fromEntries(map)

console.log(stu2) // {name: "lisi", age: 17}

数组(Array)方法扩展

includes

includes 方法用来检测数组中是否包含某个元素,返回 Boolean 值

const arr = ['red', 'blue', 'green', 'white']

console.log(arr.includes('red')) // true
console.log(arr.includes('black')) // false

flat 和 flatMap

flat 是将多维数组转换成低维数组

const arr1 = [1, 2, 3, [4, 5, 6, [7, 8]]]

console.log(arr1.flat())  // [1, 2, 3, 4, 5, 6, [7, 8]]
// 传参表示深度
console.log(arr1.flat(2)) // // [1, 2, 3, 4, 5, 6, 7, 8]

flatMap 遍历数组之后,如果返回结果是多维数组,转换成低维数组

const arr2 = [1, 2, 3, 4]
const res = arr2.flatMap(item => [item * 10])
console.log(res) // [10, 20, 30, 40]

async 与 await

async 和 await 两种语法结合,可以让异步代码看起来像同步代码。

async

  • async 函数返回值为 promise 对象
  • promise 对象结果由 async 函数执行的返回值决定

await

  • await 函数必须写在 async 函数中
  • await 右侧的表达式一般为 promise 对象
  • await 返回的是 promise 的成功值
  • await 的 promise 失败了,就会抛出异常,需要通过 try…catch 捕获处理

使用

读取文件

const fs = require('fs')

const p1 = new Promise((resolve, reject) => {
  fs.readFile('./let.js', (err, data) => {
    if(err) reject(err)
    resolve(data)
  })
})

const p2 = new Promise((resolve, reject) => {
  fs.readFile('./map.js', (err, data) => {
    if(err) reject(err)
    resolve(data)
  })
})

async function foo() {
  const res1 = await p1
  const res2 = await p2
  console.log(res1.toString())
  console.log(res2.toString())
}

foo()

发送 Ajax 请求

function Ajax(type='GET', url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(type, url)
    xhr.send()
    xhr.onreadystatechange = function () {
      if(xhr.readyState === 4) {
        if(xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.response)
        }else {
          reject(xhr.status)
        }
      }
    }
  })
}

async function foo() {
  const res1 = await Ajax('GET', 'https://www.baidu.com')
  const res2 = await Ajax('GET', 'https://www.sina.com')
  console.log(res1)
  console.log(res2)
}

foo()

可选链操作符

?. 当对象层数比较深,使用可选链操作符,可以免去层级判断。

如果不使用可选链操作符,一般使用 && 来连接判断

function foo(config) {
  const db = config && config.db && config.db.host
  console.log(db)
}

foo({
  db: {
    host: '127.0.0.1',
    post: 3306
  }
})

使用可选链操作符

function foo(config) {
  const db = config ?. db ?. host
  console.log(db)
}

foo({
  db: {
    host: '127.0.0.1',
    post: 3306
  }
})
xhr = new XMLHttpRequest()
xhr.open(type, url)
xhr.send()
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
}else {
reject(xhr.status)
}
}
}
})
}

async function foo() {
const res1 = await Ajax(‘GET’, ‘https://www.baidu.com’)
const res2 = await Ajax(‘GET’, ‘https://www.sina.com’)
console.log(res1)
console.log(res2)
}

foo()



# 可选链操作符

`?.` 当对象层数比较深,使用可选链操作符,可以免去层级判断。

如果不使用可选链操作符,一般使用 `&&` 来连接判断

```js
function foo(config) {
  const db = config && config.db && config.db.host
  console.log(db)
}

foo({
  db: {
    host: '127.0.0.1',
    post: 3306
  }
})

使用可选链操作符

function foo(config) {
  const db = config ?. db ?. host
  console.log(db)
}

foo({
  db: {
    host: '127.0.0.1',
    post: 3306
  }
})

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值