ECMAScript 新特性

1. ECMAScript 与Javascript的关系

2. ECMAScript的发展过程

3. ECMAScript 2015 (ES6) 的新特性


关于ECMAScript 以及 它 和Javasctipt的关系:

ECMAScript 是 脚本语言 、缩写为ES, 是Javascript 的标准化规范. Javascript 是 ECMAScript 的扩展语言.  ECMAScript 提供最基本的语法,约定编写规则。 (语言层面)不能直接完成实际应用开发

Javascript 实现了ECMAScript 的语言标准 + 扩展 => 在浏览器中操作DOM 和 BOM

在浏览器环境中: Javascript = ECMAScript + Web APIs(即 DOM + BOM)

在node.js 环境中: Javascript = ECMAScript + Node APIs(即 fs, net 等)

Javascript 语言本身就是 ECMAScript. 


ES2015 概述

超长连接: https://262.ecma-international.org/6.0/

重点变化(4类) 

1. 解决原有语法问题: let const 提供的块级作用域

2. 对原有语法增强:解构 展开 参数默认值 模板字符串 等

3. 新方法,功能,对象: promise proxy object.assign

4. 新数据类型、数据结构: symbol set map ..

前言: node.js setup  : 安装 nodemon : 监视文件变化


ES2015 let 与块级作用域

作用域scope: 代码中的一个(成员)它(能起作用的范围)

  • 全局作用域 global scope
  • 函数作用域 functional scope 
  • 块级作用域  ( { let i = 0 } )
// let 声明的成员只会在所声明的块中生效

if (true) {
  var foo = 'var'
  let joo = 'let'
  console.log(foo) //'var'
  console.log(joo) //"let"

}
console.log(foo)   // 'var' 
console.log(joo)   // undefined

这是两个互不想干的 i

for(let i = 0; i < 3; i++) {
    let i = "foo"
    console.log(i)
}
// "foo"
// "foo"
// "foo"



for(let i = 0; i < 3; i++) let i = "foo"
console.log(i)
// 在变量声明之前使用var变量 : 不会报错,而是返回 undefined

console.log(i)     // 此时 i 已经声明,只是没赋值 / 术语:变量声明的提升 bug
var i = 4; 

// 在变量声明之前使用let变量 : 报错: cannot access i before initialization
console.log(j)
let j = 5;  


// 提升
// 案例: let 应用场景:循环绑定事件,事件处理函数中获取正确索引 

var elements = [{}, {}, {}]
for (var i = 0; i < elements.length; i++) {
  elements[i].onclick = function () {
    console.log(i)
  }
}
elements[2].onclick()

var elements = [{}, {}, {}]
for (var i = 0; i < elements.length; i++) {
  elements[i].onclick = (function (i) {
    return function () {
      console.log(i)
    }
  })(i)
}
elements[0].onclick()

var elements = [{}, {}, {}]
for (let i = 0; i < elements.length; i++) {
  elements[i].onclick = function () {
    console.log(i)
  }
}
elements[2].onclick()

ES2015 const

常量/恒量

const : 只读 

声明 const 变量的两个注意点: 1. 不可被修改 2. 声明时需要赋值

// 1. 不可被修改
// 会报错: TypeError: Assignment to constant variable.

const name = 'joe'

name ="jack"

// 2.声明变量时需要赋值
// 会报错:SyntaxError: Missing initializer in const declaration

const name

name = 'zce'

注: 不可被修改 means: 不能在声明后重新指向一个新的内存地址。 可以修改const中的属性

const obj = {}
obj.name = "joe"       // valid

obj= {
  name  : "joe"        // TypeError: Assignment to constant variable. 
                       // 改变内存指向
}

obj= {}                // TypeError: Assignment to constant variable.
                       // 改变内存指向

最佳: 不用var /  主const /  辅let


数组的解构

Destructuring(动词:因此它是一种方式)

1. 解构数组制定位置成员:  const [ ,  , bar] =  arr, 获取index 2 成员

2. 定义: 将一个较大的数组or对象  改成 较小的数组or对象 的方式

3. const a = array【0】   // es2015 之前也有数组的解构, 

4. ... speard operator  它和数组解构没有关系. 

5. 解构的语法  const 【变量名1,,变量名2,...rest 】 = 数组 // ...rest 其实就是展开多个变量名

// 原始数组
const arr = [1,2,3]

// //以前提取数组中变量的方法
// const foo = arr[0]      
// const joo = arr[1]
// const zoo = arr[2]
// console.log(foo,joo,zoo)  // 1 2 3

// 解构方法1: 对应

const [foo,joo,zoo] = arr
console.log(foo,joo,zoo)  // 1 2 3

const [ , ,boo,xxj] = arr     // 若不需要留空// index 对号入座
const[zzz] = arr      
console.log(zzz)      // 1           // 不够长度没关系
console.log(boo,xxj)  // 3 undefined // 对不上号的提取结果undefined

// 解构方法2: ...rest         //...rest : 解构从当前位置index:1 开始向后的所有成员
const [ioo, ...rest] = arr   
console.log(rest)            // TYPE: array            // [2,3]
console.log(...rest)         // TYPE: array 中的成员    // 2 3 

// 设置默认值:  xxx =‘string’ yyy = 123 // 正常赋值
const [jjj,hhh, yyy =123, xxx='name'] = arr
console.log(jjj,hhh,yyy,xxx)  // 1 2 123 'name'


对象的解构

前言: 与数组类似,以属性名匹配。而不是顺序

重点看: 设置默认值 + 变量名冲突(重命名语法)

const { 提取变量的名 : 重命名的名  =  default vaule  } = obj(从这个对象中提取)

// 原始object
const obj = {name: 'guohai', age:18}

// //以前提取object中属性的方法
// const name = obj.name   
// const age = obj.age
// console.log(name,age)  // guohai, 18

// 解构: 对应属性名
const { name } = obj
console.log(name)  // guohai

// 设置默认值
const { random = 'default' , another} = obj
console.log(random)   // default
console.log(another)  // undefined : 匹配不到就返回undefined


// 与当前作用域中的变量重名 
const age = 99
//const { age } = obj  
const { age: objName } = obj       //重新命名
console.log(objName)   // 返回18    //使用objName 调用  

`ES2015 `模板字符串` template literal`

  • 换行 
  • 使用 `something, ${ 变量/js 语句 }`  javascript expression , ${}返回值输出到字符串中
  • 包裹使用 `something something\` something \` something `
const name = 'guohai'
const string = `As Dalian Science and \`Technology\` Welfare 
                Card is too much; the room falls in love;
                the two places are separated and the speed 
                is fast to liberate ${name}drunkenness`   

//  1.可用 \`,
//  2.可换行, 
//  3.可用expression 差值表达式 ${name},任何标准js语句,返回值加入string

`带标签的模板字符串 tagged template literal`

作用: 对模板字符串加工, 检查等

const name = 'guohai'
const sex = 'true'

//作用: 对模板字符串加工
function tagFunc (string, name, sex) { //is array. the result of string.split()
    console.log(string)     //以表达式分割string ['hey, my name is ', 'i am a ', '.']

    console.log(string[0], name, string[1], sex ? 'man' : 'woman', string[2])
}


const result = tagFunc `hey, my name is ${name}, i am a ${sex}.`

`字符串 の 扩展功能`

1. includes()

2. startsWith()

3. endsWith()


ES2015 参数

参数默认值:以前用逻辑判断做,'短路运算是什么?'  function foo( enable= true) { }

                      没有传递参数 或 传递值为undefined 时 使用 enable = true

                      若有多个形参数, 带有默认参数的形参要出现在形参列表的最后。 (问: 如果有多个带有默认值的形参呢? 如何写)


// function foo () {
//   console.log(arguments)
// }

function foo (first, ...args) {
  console.log(args)
}

foo(1, 2, 3, 4)

ES2015 展开数组

温习 apply()方法

// 展开数组参数
const arr = ['foo', 'bar', 'baz']
// console.log(
//   arr[0],
//   arr[1],
//   arr[2],
// )
// console.log.apply(console, arr)
console.log(...arr)

ES2015 箭头函数

简化,没有this机制 ()=>{}


ES2015 对象

对象字面量的增强 Enchanced Object Literals

语法: 计算属性名:【表达式】:值  ;表达式的计算结果作为属性的名
计算属性名规定的属性会放在属性列表开头,但是顺序对于object来说不重要

const bar = "345"

const obj = {   
    //1
    foo : "123",  
    // bar : bar     // before es2015
    bar // es2015    //属性名 与 变量名一致 => 省略

    //2
    functionName : function(){ console.log('before es2015')}  // before es2015
    function2015 () { console.log('es2015')}  // es2015

    //3
    //计算属性名:【表达式】:值   // 表达式的计算结果作为属性的名
    //计算属性名规定的属性会放在开头,但是顺序对于object来说不重要
    [1+1]: 123
}

ES2015 对象扩展方法 之 Object.assign

语法: Object.assign (目标对象,源对象1,源对象2 .... )

作用: 用后面对象的值 覆盖 目标对象的 值

返回值 === 目标对象

const target = {
    a : 1,
    b : 2
}
const source1 = {
    a : 3,
    b : 5
}
const source2 = {
    a : 7,
    b : 8,
    c : 10
}
const result= Object.assign(target, source1, source2)

console.log(result)             // 最后面的依次覆盖 结果为 { a: 7, b: 8, c: 10 }
console.log(target)             // 结果为: { a: 7, b: 8, c: 10 }
console.log(result === target)  // true 

// 应用场景
function func (obj) {
  obj.name = 'change obj'
  console.log(obj)  // obj 形参 实参 和 外部变量指向同一地址, 因此一样   //1  { name: 'change obj' }

  const funcObj = Object.assign({}, obj)  // 赋值到一个全新的空对象上{} => 不影响外部   
  funcObj.name = 'func obj' 
  console.log(funcObj)//2  { name: 'func obj' }
}
const obj = { name: 'global obj' }   
func(obj)
console.log(obj) //3 { name: 'change obj' }

ES2015 对象扩展方法 之 Object.is

//== 会在比较前转换数据类型 === 严格对比

console.log(0 == false);  // returns true,  隐式转换

//=== 特列
console.log( +0 === -0 ); // returns true, 但是希望得到 false
console.log(NaN === NaN); // returns false, 实际中希望得到 true
 
console.log(Object.is(0, false)) // false  
console.log(Object.is(NaN,NaN)) // true
console.log(Object.is(+0,-0))   // false

ES2015 对象扩展方法 之 Proxy 代理

监视目标对象的属性读写 : ES2015 之前 : Object.defineProperty

对象访问代理器(名字不同是因为功能更强大) : proxy ,也可以监视 数组【array】

const person = {
    name: 'joe',
    age: 18
}

// proxy (代理对象, {代理处理对象}) 2个变量 、 代理处理对象就是函数集合体啦
const personProxy = new Proxy( person, {
  //get (代理对象,外部访问代理对象属性的名字) {},
    get (target, property) {     
         console.log(target, property) // {person}  , name 
         return property in target ? target [property] : 'not found'              
        // RETURNED VALUE IS : 外部访问这个属性得到的结果
    }, 

  //set (代理对象,外部访问代理对象属性的名字,写入的值) {},
    set (target, property, value) {
        // 也可以在辅助前做检查,比如数据类型检查
        // 为目标对象赋值
        target[property] = value
        console.log(target, property, value)
    },

  //deleteProperty (代理对象,需要删除的属性的名) {}
    deleteProperty (target, property) {
        delete target[name]
    }
})


delete personProxy.age               // 触发 //语法有点奇怪
personProxy.gender = 'male'          // 触发

console.log(personProxy.name)        // 触发

Proxy 的一些 方法 (待我详细调查)

  • get
  • set
  • has
  • deleteProperty
  • getPropertyOf
  • isExtensible
  • preventExtensions
  • getOwnPropertyDescriptor 
  • defineProperty 
  • ownKeys
  • apply
  • construct 

  • 问题:new Proxy(target,「方法」)会继承target的方法吗?在下例中listProxy使用了list 数组的push()方法, 同理, 是否会继承object的方法()
// proxy 监视 数组

const list = []

const listProxy = new Proxy (list, {
    set(target, property, value){
        //  console.log(property, value)
         target[property] = value
         return true   // 不可以忘记 : 代表设置成功
    }
})

listProxy.push(2)  //可
listProxy[1] = 200 //可

console.log(listProxy)

ES2015 Reflect  静态类

如果在Proxy中没有设置get set 等方法成员方法: 就相当于设置了一个get set 等方法并将参数交给Relfect的 get set 等 方法。

Reflect 内部封装了一系列对对象的底层操作

//Reflect 的意义: 统一处理OBJECT

console.log('name' in obj)      // obj 有没有 ’name‘
console.log(delete obj['age'])  // delete obj[property]
console.log(Object.keys(obj))   // obj的所有属性名

console.log(Reflect.has(obj,'name'))      // obj 有没有 ’name‘
console.log(Reflect.deleteProperty(obj,'age'))  // delete obj[property]
console.log(Reflect.ownKeys(obj))   // obj的所有属性名

ES2015 Reflect + Proxy の 正确打开方式

整个数据结构和方法都被objProxy复制走了吗. 这里可以用 objProxy.属性名来触发

const obj = {
  foo : '123',
  bar : '456'
}

const objProxy = new Proxy (obj, {
  set(target, property, value) {
  // 添加监视逻辑   // 具体操作交给REFLECT
  return Reflect.set(target, property, value)
  }
})

objProxy.foo                // 触发 

console.log(objProxy.name = 'gg')   //123
console.log(objProxy)       // { foo: '123', bar: '456', name: 'gg' }
console.log(obj)            // { foo: '123', bar: '456', name: 'gg' }

ES2015 Promise

here will be a link 

// 基本用法

// promise 对象接受一个函数作为参数, 这个函数接受两个函数作为参数,分别是成功和失败回调函数

Const promise = new Promise(resolve, reject) {
    resolve (100)
    // reject (200)
    // 1/2 选择一个执行
})

promise.then((value)=>{console.log(value)}, ()=>{}) // then 返回一个promise
//结果是100 

ES2015 Class 

基本定义:

// 1. 定义一个函数作构造函数
function Person (name) {
  this.name = name
}
//2. 定义函数的原型对象 // 共享
Person.prototype.say = function () {
  console.log(`hi, my name is ${this.name}`)
}

//class
Class person {
    constructor (name) {
        this.name = name
    }
    say () {
        console.log('say hello')
    }
    static create(name){ // STATIC 
//因为该方法时放在类上,因此this指向的是类。而不是实例对象本身
        return new person(name)
    }
}
const jack = new person('jack')
jack.say()

静态方法 + 实例方法

静态方法:通过类型本身(class)调用 static ES2015中通过static 关键词添加 静态方法和变量

                 static 方法因为是挂载在类本身, this 指向不是某一个实例对象而是类本省

实例方法: 通过实例对象(instance)调用 

类的继承 extends  + super() 关键词

class Student extends Person {  // extendS
    constructor (number, name){
        // this 放在最前面
        super(name)  // 继承父类的name 变量
        this.number = number
    }
    hello() {
        super.say()  // 继承父类Person的say方法
        
    }
}

ES2015 全新 数据结构 - - Set - - 是一个类

可以理解为集合, 与数组类似,内容不允许重复, 是一个类, 通过new 关键词创建(27课)。

实例方法: add(), 向实例中添加数据。 add()方法返回集合本身 => 可以链式调用

                  forEach( i => console.log(i)),遍历对象

                  for ( let item of arr ) { console.log ( item ) }

                  .size 获取set实例的长度。 

                  .has('something') 实例中是否有 'something' 

                  .clear() 清除所有

// set类の实例方法展示: 
var s = new Set () 
s.add(1).add(22).add(3) // 向实例中添加数据。 add()方法返回集合本身 => 可以链式调用
s.forEach( i => console.log(i)) //遍历对象
//for ( let item of s ) { console.log ( item ) } //遍历对象
s.size  //获取set实例的长度。 
s.has('something')// 实例中是否有 'something' 
s.clear() //清除所有


//去重
const arr = [1,2,3,3,1]
const noRepeat = new set (arr)  // set 返回一个set 的实例对象 // 伪数组 
const result = Array.from(noRepeat) // 将伪数组 转化为数组

                        

ES2015 全新 数据结构 - - Map - - 是一个类

类似于对象Object,是key -value pair,

对象中的 key 只能是 string,如果不是string , 就会用toString()返回一个string 作为key。

下面是关于这个问题的展示, Map就是为了解决这个问题

const obj = {}

obj[true] = 'boolean'
obj[123] = 'number'
obj[{a:1}] = 'object'

console.log(Object.keys(obj))       // obj的所有属性名
console.log(Reflect.ownKeys(obj))   // obj的所有属性名

// result is :  ['true', '123', '[object Object]'] 

Map 可以用任意数据类型作为key (与object的最大区别)

const m = new Map()  // 利用 new Map ( )创建一个map 对象
const tom = {name : 'tom' }   // 准备一个object 作为 key
m.set({tom, 90}) // m.set(key, value) 
console.log(m)   //result is:  Map { {name : 'tom' } => 90 }

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

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

ES2015 全新 数据结构 - - Symbol - - 是一个类

作用: 表示一个独一无二的值, 目前最大作用, 为对象OBJECT 添加一个unique属性名

symbol 可以注册 object 的 key, 其不会被转化为 string

symbol.for('somthing')

const cache= {
   [symbol()] = 'qqq'
}

// a.js 
cache ['a_foo']  = Math.random() 
// b.js  
cache ['b_foo'] = '123' 


// 解决key value pair 中 key 重复命名的问题。 约定 const [文件名_名] = 'value'
// 这可以规避问题 但不能解决


cache [key]  = value // 个人, 我不常这样为object 添加值。 可以记忆一波 

cache[symbol()] = '789'
cache[symbol()] = '456'

//获取symbol注册的 key value pair
let s = Symbol.for("something");
obj[s] = 1
console.log(obj[s])

ES2015 for ... of ... 循环

可以使用‘break’ 终止循环, 伪数组也可以遍历

// 遍历 array + array alike 数组 + 伪数组
for( item of arr) {
    if ( item === 'stop') {
        // some code
        break 
    }
} 

// 遍历 map
const map  = new Map()
map.set('foo', 123) // (key, value)

// 拿到[key, value]
for( item of map) {
    console.log(item)  // ['foo', 123] 
}
// 直接拿到key value
for( [key, value] of map) {  // 数组解构语法[]
    console.log(key, value)  //  foo  123
}

//! 不可以直接 遍历 object, 因为 object 中没有 Iterator 可迭代接口

Iterator 可迭代接口, 是一个对象

迭代器模式: 不需要担心被调用数据的结构是否发生了变化。对外提供统一遍历接口

arr [ symbol.iterator]( ).next()

在arr 中挂在了一个Symbol.iterator()方法, 其返回一个带有next()方法的对象,不断调用next()来遍历

//For of 内部原理

const set = new Set([123,456,789])

//浏览器查看
// Set 中有一个 iterator 方法,调用它()得到迭代器 Array Iterator
const iterator = set[Symbol.iterator]()

//迭代器 Array Iterator 中有一个next()方法
iterator.next()
iterator.next()
iterator.next()


手写 iterator + todo task   33/34 

const obj  = {                        // iterable: 有一个iterator() 方法
    store: ['foo','bar','baz'],
    [Symbol.iterator] : function (){ 
        
        let index =0    
        const self = this

             
        return {                      // iterator: iterator ()方法返回的迭代器
            next: function (){        
                   const result = {   
                           value: self.store[index],
                           done: index >= self.store.length
                           }
                    index ++
                    return result   // iteration result: next() 返回的对象 ()
                  }
               }
    }
}

for(const item of obj){
    console.log(item)
}

生成器函数 generator ()

惰性执行 有Symbol.iterator 接口, 配合 yield 使用

function * foo (){
  console.log('111') 
  yield 100 

}
 const generator = foo()  // 返回一个生成器对象
 console.log(generator.next())
 console.log(generator.next())

//  console.log(foo().next())   // 错误方法: 重新开始
//  console.log(foo().next())   // 错误方法: 重新开始


//调用生成器函数会返回一个generator对象,生成器对象,

//这个对象有一个next()方法
// generator 也有 iterator 接口


//配合 yield() 使用   === 暂停

发号器 、iterator接口 手写 36课

test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值