前端进阶之路 - part2 -【ECMscript新特新】

294 阅读8分钟

ECMAScript概述

  1. ES也是一门脚本语言,通常把它看做JavaScript的标准化规范,

  2. 但实际上JavaScript是ECMAScript的扩展语言。

  3. ECMAScript只提供了最基本的语法,而JS实现了这些语法并且做了一些扩展,可以在浏览器环境中可以操作dom和bom,在node环境中可以做一些文件读写的操作。

  4. JavaScript@Web = ECMAScript + Web APIs = ECMAScript + (BOM + DOM);

  5. JavaScript@Node.js = ECMAScript + Node APIs = ECMAScript + (fs + net + etc.)

  6. 故:JavaScript语言本身指的就是ECMAScript。

ES2015概述:【ES2015的新特性,大致可以归为4大类:】

  1. 解决原有语法上的一些问题或者不足
  2. 对原有语法进行增强
  3. 全新的对象、全新的方法、全新的功能
  4. 全新的数据类型和数据结构(symbol、set、map、etc.)
let与块级作用域
  1. 作用域——某个成员能够起作用的范围
  2. 在ES2015之前,只有两种作用域:- 全局作用域 - 函数作用域
  3. 在ES2015中新增: - 块级作用域
const
  1. 声明的成员一旦声明了就不能修改,且必须付初始值。
  2. const是指声明的变量的内存地址不能改变,但是内存中的值可以修改。
数组的解构
// 数组的解构
const arr = [1, 2, 3]
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3


// 只获取数组中第三个成员,方法,前面两个用逗号隔开,只声明第三个
const arr = [1, 2, 3]
const [, , c] = arr;
console.log(c); // 3


// 提取数组当前位置开始的所有成员(注意:三个点的用法只能在解构成员的最后使用)
const arr = [1, 2, 3]
const [foo, ...rest] = arr;
console.log(rest); // [2, 3]


// 可以给提取到的成员设置默认值,如果没有提取到值,就会赋为默认值
const arr = [1, 2, 3]
const [a, b, c, d = 'default value'] = arr;
console.log(a, b, c, d); // 1 2 3 default value
对象的解构
const obj = { name: 'zzz', age: 18}

const { name } = obj;
console.log(name); // 'zzz'


// 使用上面的方法缺陷在于容易出现重名的情况,可使用重命名的方式解决;设置默认值方法如下
const obj = { name: 'zzz', age: 18}

const { name: objName, size: objSize = 'test' } = obj;
console.log(objName, objSize); // 'zzz' 'test'
模板字符串
字符串的扩展方法 【这一组方法主要用于字符串的查找】
  1. includes()
  2. startsWith()
  3. endsWith()
const msg = 'Error: foo is undefined.'
const result1 = msg.startsWith('Error');
const result2 = msg.endsWith('.');
const result3 = msg.includes('foo');
console.log(result1, result2, result3); // true true true
参数默认值
// 函数参数的默认值
function foo(enable = true) { 
    // 方式三, 注意:带有默认值的参数,应该在函数参数的最后
  // enable = enable || true;
    // 方式一:采用断路运算的方式赋默认值.缺点在于,如果只为false,也会被默认值覆盖
  enable = enable === undefined ? true : enable;
    // 方式二
}
剩余参数
function foo(first, ...args) { // 这种方式只能出现在形参最后一位,且只能使用一次
  console.log(args) // [ 2, 3, 4 ]
}

foo(1,2, 3, 4)
展开数组
const arr = ['aa', 'bb', 'cc'];
console.log(arr[0], arr[1], arr[2]); // aa bb cc
console.log.apply(console, arr); // aa bb cc
console.log(...arr); // aa bb cc
箭头函数
  1. 箭头函数不会改变this的指向,也就是说在箭头函数的外面拿到的this是什么,在箭头函数内部拿到的this也就是什么
对象字面量的增强
const bar = '123'
const obj = {
  foo: 123,
  // bar: bar,
  bar,
  // methond1: function() {
  //   console.log('method111');
  // }
  method1() {
    console.log('method222')
  },
  [1 + 1]: 123,
  [Math.random()]: 123
}

console.log(obj);
Object.assign : 【将多个源对象中的属性复制到一个目标对象中】
const source1 = {
  a: 123,
  b: 123
}

const target = {
  a: 456,
  c: 444
}
const source2 = {
  d: 333,
  c: 666
}
const source3 = {
  r: 333,
  b: 666
}

// const result = Object.assign(target, source1);
// console.log(target); // { a: 123, c: 444, b: 123 }
// console.log(result === target);// true

const result = Object.assign(target, source1, source2, source3);
console.log(target); // { a: 123, c: 666, b: 666, d: 333, r: 333 }
console.log(result === target);// true
Object.is :【判断两个对象是否相等】
console.log(
  // 0 == false // true
  // 0 === false // false
  // +0 === -0 // true
  // NaN === NaN // false
  // Object.is(+0, -0) // false
  Object.is(NaN, NaN) // true
);
Promise
  1. 一种更优的异步编程解决方案
  2. 解决了传统异步贬称各种回调函数嵌套过深的问题
Async / Await 【异步编程后面具体介绍】
生成器 【避免异步编程中回调嵌套过深,从而去提供更好的异步解决方案】
// Generator 函数

// function * foo () {
//   console.log('zce')
//   return 100
// }

// const result = foo()
// console.log(result.next())
/*
zce
{ value: 100, done: true }
*/

function * foo () {
  console.log('1111')
  yield 100
  console.log('2222')
  yield 200
  console.log('3333')
  yield 300
}

const generator = foo()

console.log(generator.next()) // 第一次调用,函数体开始执行,遇到第一个 yield 暂停
console.log(generator.next()) // 第二次调用,从暂停位置继续,直到遇到下一个 yield 再次暂停
console.log(generator.next()) // 。。。
console.log(generator.next()) // 第四次调用,已经没有需要执行的内容了,所以直接得到 undefined done为true
生成器应用
// Generator 应用

// 案例1:发号器

function * createIdMaker () {
  let id = 1
  while (true) {
    yield id++
  }
}

const idMaker = createIdMaker()

console.log(idMaker.next().value)
console.log(idMaker.next().value)
console.log(idMaker.next().value)
console.log(idMaker.next().value)

// 案例2:使用 Generator 函数实现 iterator 方法

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  [Symbol.iterator]: function * () {
    const all = [...this.life, ...this.learn, ...this.work]
    for (const item of all) {
      yield item
    }
  }
}

for (const item of todos) {
  console.log(item)
}
for循环
  1. for——遍历普通的数组

  2. for...in——遍历键值对

  3. for...of——以后会作为遍历所有数据结构的统一方式,拿到的是数组中的每一个元素

Proxy【代理对象】
// Object.defineProperty
// Proxy 为对象设置访问代理器
const person = {
  name: 'zwss',
  age: 20
}

const personProxy = new Proxy(person, {
  get(target, property) {
    console.log(target, property) // { name: 'zwss', age: 20 } name
    return 100;
  },
  set(target, property, value) {

  }
});

console.log(personProxy.name); // 100
// 代理访问属性的值是get方法的返回值
// Object.defineProperty
// Proxy 为对象设置访问代理器
const person = {
  name: 'zwss',
  age: 20
}

const personProxy = new Proxy(person, {
    // 监视属性读取
  get(target, property) {
    return property in target ? target[property] : 'default';
  },
    // 监视属性设置
  set(target, property, value) {
    if(property === 'age') {
      if(!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an int`)
      }
    }
    target[property] = value
  }
});
personProxy.age = 100;
personProxy.gender = true;
console.log(personProxy.name); // zwss
console.log(personProxy.xxxx); // default
Reflect
  1. 统一的对象操作API

  2. Reflect属于一个静态类,不能够使用new Reflect方式使用对象,只能通过静态的方式调用方法Reflect.get()

  3. Reflect内部封装了一系列对对象的底层操作(总共14个静态方法,其中有一个被废弃掉了)

  4. Reflect成员方法就是Proxy处理对象的默认实现

// Reflect 对象
const obj = {
  foo: '123',
  bar: '234'
}

const proxy = new Proxy(obj, {
  get(target, property) {
    console.log('watch logic~')
    return Reflect.get(target, property)  }
})

console.log(proxy.foo);
// Reflect 对象
const obj = {
  foo: '123',
  bar: '234'
}

// console.log('name' in obj); // false
// console.log(delete obj['age']); // true
// console.log(Object.keys(obj)); // [ 'foo', 'bar' ]

console.log(Reflect.has(obj, 'name'));
console.log(Reflect.deleteProperty(obj, 'age'));
console.log(Reflect.ownKeys(obj));
set
  1. set的内部成员是不允许重复的,也就是每一个值在set中都是唯一的。
// Set 数据结构

const s = new Set()

s.add(1).add(2).add(3).add(4).add(2)

// console.log(s)

// s.forEach(i => console.log(i))

// for (let i of s) {
//   console.log(i)
// }

// console.log(s.size)

// console.log(s.has(100))

// console.log(s.delete(3))
// console.log(s)

// s.clear()
// console.log(s)

// 应用场景:数组去重

const arr = [1, 2, 1, 3, 4, 1]

// const result = Array.from(new Set(arr))
const result = [...new Set(arr)]

console.log(result)

// 弱引用版本 WeakSet
// 差异就是 Set 中会对所使用到的数据产生引用
// 即便这个数据在外面被消耗,但是由于 Set 引用了这个数据,所以依然不会回收
// 而 WeakSet 的特点就是不会产生引用,
// 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。
map
// Map 数据结构

const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{ a: 1 }] = 'value'

console.log(Object.keys(obj)) // [ '123', 'true', '[object Object]' ],故用对象去存键,不可行
console.log(obj['[object Object]']) // value
// 与对象最大的区别就是可以使用任意类型作为键,而对象只能使用字符串作为键
const m = new Map()

const tom = { name: 'tom' }

m.set(tom, 90)

console.log(m)

console.log(m.get(tom))

// m.has()
// m.delete()
// m.clear()

m.forEach((value, key) => {
  console.log(value, key)
})

// 弱引用版本 WeakMap
// 差异就是 Map 中会对所使用到的数据产生引用
// 即便这个数据在外面被消耗,但是由于 Map 引用了这个数据,所以依然不会回收
// 而 WeakMap 的特点就是不会产生引用,
// 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。
Symbol
  1. 一种全新的原始数据类型, 表示一个独一无二的值。
// Symbol 数据类型

// 场景1:扩展对象,属性名冲突问题

// // shared.js ====================================

// const cache = {}

// // a.js =========================================

// cache['a_foo'] = Math.random()

// // b.js =========================================

// cache['b_foo'] = '123'

// console.log(cache)

// =========================================================

const s = Symbol()
console.log(s)
console.log(typeof s)
// Symbol()
// symbol
// 通过symbol创建的对象永远是独一无二的,永远不会重复

// 两个 Symbol 永远不会相等

console.log(
  Symbol() === Symbol()
) // false



// Symbol 描述文本

// console.log(Symbol('foo'))
// console.log(Symbol('bar'))
// console.log(Symbol('baz'))

// 使用 Symbol 为对象添加用不重复的键

// const obj = {}
// obj[Symbol()] = '123'
// obj[Symbol()] = '456'
// console.log(obj)

// 也可以在计算属性名中使用

// const obj = {
//   [Symbol()]: 123
// }
// console.log(obj)

// =========================================================

// 案例2:Symbol 模拟实现私有成员

// a.js ======================================

const name = Symbol()
const person = {
  [name]: 'zce',
  say () {
    console.log(this[name])
  }
}
// 只对外暴露 person

// b.js =======================================

// 由于无法创建出一样的 Symbol 值,
// 所以无法直接访问到 person 中的「私有」成员
// person[Symbol()]
person.say()
ES2016概述
// ECMAScript 2016
// Array.prototype.includes ---------------------
const arr = ['foo', 1, NaN, false];

// console.log(arr.indexOf('foo')) // 0
// console.log(arr.indexOf('bar')) // -1
// console.log(arr.indexOf('NaN')) // -1
// console.log(arr.includes('foo')) // true
// console.log(arr.includes(NaN)) // true

// 指数运算符------------------------------------
console.log(Math.pow(2, 10)); // 之前的用法
console.log(2 ** 10); // ES2016中的指数运算符
ES2017概述
  1. Object.values
const obj = {
  foo: 'value1',
  bar: 'value2'
}

// Object.values------------------------------------
console.log(Object.values(obj)) // [ 'value1', 'value2' ]
  1. Object.entries
const obj = {
  foo: 'value1',
  bar: 'value2'
}

// Object.entries-----------------------------------
console.log(Object.entries(obj)) // [ [ 'foo', 'value1' ], [ 'bar', 'value2' ] ]

for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}
/*
foo value1
bar value2
*/

console.log(new Map(Object.entries(obj))) // Map { 'foo' => 'value1', 'bar' => 'value2' }
  1. Es6 常用字符串方法

let str='apple banana pear';
console.log(str.indexOf('apple'));   //0  indexOf返回下标
 
// 判断是否存在
if(str.indexOf('apple')>-1){
    alert(true);
}else{
    alert(false);

————————————————
版权声明:本文为CSDN博主「面壁思过程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Candy_mi/article/details/94381432

console.log(str.includes('apple'))  // includes返回false true
</script>
 
 
<script>
// 1.判断字符串是否以谁开头
console.log(str.startsWith('ap'))   //返回false true
 
//2.字符串是否是以谁结尾
console.log(str.endsWith('pear'))  //返回false true
 
//3.重复字符串
let str1='牧马人';
console.log(str1.repeat(3))   //牧马人牧马人牧马人    数字为正整数
 
//4.字符串填充
let str3='tw'
console.log(str3.padStart(3,'a'));  //往前填充  3是总长度