系统化学习ECMAScript 2015

老生常谈: const let var

闭包是函数作用域为了摆脱 全局作用域带来的影响。
有了ES2015我们可以使用块级作用域来解决全局作用域带来的影响。

for 有两层作用域 这两个分别有自己的作用域。

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

解析: 
let i = 0;

if (i < 3) {
    console.log(i)
}
i ++ 

const 和 let 的区别 const只声明了只读特性。
const 声明必须赋值。
const 不允许修改它指向的内存地址。但是可以修改他的属性。
最佳实践: 不用var 主用const 配合let.
总结

const 配合let 可以让我们知道我们声明的变量是可读写的。还是只读的。减少不可预测的结果。

数组的解构

当结构提取的成员小于要结构的数据时,会从左到解构出来。
当结构提取的成员大于要结构的数据时,多余的会返回undefind.类似于为定义了没有赋值的变量。

const arr = [ 100, 200, 300 ];

const [a, ...res] = arr;
console.log(a, res)
// 100 [ 200, 300 ]
// 赋默认值。
const [a, , , d=2 ] = arr;
console.log(d)
对象的解构

根据健匹配值。

const obj = {name: 'zce', age: 18};
const name = 'yoom';
// 如果结构出现同名可以起个别名。 也可以添加默认值。
const { name: objName = "123" } = obj;
console.log(objName, name)
模版字符串的高级用法
const res = console.log `打印`
输出 : [ '打印' ];


const name = 'tom';
const gender = 'true'
function myTagFunc (val, name, gender) {
  console.log(val, name, gender) // 输出: [ 'hey, ', ' is a ', '' ] 'tom' 'true'
  // 返回值等于res的值。
  return val[0] + name+ val[1] + gender + val[2]
}
const res = myTagFunc`hey, ${name} is a ${gender}`
console.log(res) //  hey, tom is a true

扩展方法:

const message = `Error: foo is not defind.`

console.log(message.startsWith('')) // 判断字符串一某某开头 返回布尔值 true
console.log(message.endsWith('。')) // 判断字符串一某某结尾 返回布尔值 false
console.log(message.includes('foo')) // 字符串包含某某     返回布尔值 true

默认值参数

带有默认值的参数 需要放在参数最后面。

剩余参数

在es2015之前js接收剩余参数使用arguments接收。

之前:
function foo () {
    console.log(arguments) // [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4 }
}
foo(1,2,3,4);

es2015: 
function foo (first, ...args) {
    console.log(first, args)  // 1 [ 2, 3, 4 ] 
}
foo(1,2,3,4);
彻底弄懂箭头函数

箭头函数表达式的语法比函数表达式更简洁, 它并没有自己的this, arguments super 或new target. 箭头函数表达式更适用于哪些本来需要匿名函数的对方。并且它不能用作构造函数。

高级语法:

// 加括号的函数体返回对象的字面量
params => ({foo: bar}) ;
// 支持剩余参数和默认参数。 参数支持解构。
没有单独的this.

在箭头函数出现之前。每一个新函数根据它是被如何调用的来定义这个函数的this值。

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this.当前作用域当中的this, 任何方式都没有办法改变它的this.

while 阻断主进程谁也执行不了,等我执行完才行。

对象字面量的增强

const bar = '345';
const obj = {
  foo: 123,
  // 定义的变量和名字一致的话可以这样简写
  bar,
  // 函数名一样 的话或者匿名也可以简写。
  method1() {
    console.log(this, 888)
  }
  // 如果这个属性名是个变量的话 可以加方括号写。
  [Math.random()]: 123;
}
console.log(obj);
obj.method1()
Object.assign 扩展方法

Object.assign 是深拷贝吗????? 不是。只是对其可枚举的属性值的拷贝。
如果它是对一个对象的引用。它仅仅会 复制其引用值。

const source1 = {
  a: 123,
  b: 123
}
const source2 = {
  a: 789,
  d: 789
}
const target = {
  a: 456,
  c: 456
}
// Object.assign() 右边的对象合并到左边,如果两个对象有相同的健,则右边替换左边的值。如果右边有左边没有的话,则新加上这个属性。
const result = Object.assign(target, source1, source2)

console.log(target === result, target) // true

function func (obj) {
 // 用来复制一个新的对像。 
  let newObj = Object.assign({}, obj)
  // 在函数内部进行操作。而不改变外面的值。
  newObj.name = 'func obj';
  console.log(newObj, 2)
}
const obj = {name: 'global obj'};
func(obj);
console.log(obj);
Object.is 判断两个值是否相等 (感觉用处不大)
console.log(
  // +0 === -0
  // NaN === NaN
  // 判断出NaN等于NaN
  Object.is(NaN, NaN),
  // 判断出+0不等于-0
  Object.is(-0, +0)

)
Object.defineProperty 和 Proxy


Object.defineProperty 监听不到对象的删除操作。Proxy可以。

const person = {
  name: 'zce',
  age: 20
};
// 第一个参数没目标代理函数。第二个参数是个对象其中又一个监听删除 deleteProperty方法。并且返回一个新的对象。
const personProxy = new Proxy(person, {
 // 一个是代理的对象。一个是传过来的需要删除属性。 删除后原对象属性即被删除。
  deleteProperty(target, property) {
    console.log('delete', property);
    delete target[property];
  }
})
delete personProxy.age;
console.log(personProxy, person, personProxy ===person) // { name: 'zce' } { name: 'zce' } false


Proxy专门为对象做访问代理器的。对象的读写都可以监听到。

const person = {
  name: 'zce',
  age: 20
};
// Proxy 第一个参数是需要代理的对象。 第二个参数是一个对象。这个对象有get set deleteProperty 方法
const personProxy = new Proxy(person, {
// get方法有两个参数。一个是代理的对象。一个是传过来的属性。
// 这个属性可能有也可能没有。
  get (target, property) {
   // 判断如果有这个属性则返回。 没有的话返回默认值。 
    return property in target ? target[property] : '你要的东西我没有';
  },
  // set方法。有三个参数。target 代理的对象。 property:传过来的属性。这个属性可能有也可能没有。没有的话则是新添加的属性。
  有的话则是更新旧属性。 里面可以做你想要的逻辑判断。
  set(target, property, value){
    if (property === 'age' && !Number.isInteger(value)) {
      throw new TypeError(`${value} is not an int`)
    }
    target[property] = value
  }
})
personProxy.age = true;
console.log(personProxy.name);
console.log(personProxy.a);
console.log(personProxy);

在VUE中会重写数组当中的方法。替换数组原型上的方法。从而达到监听的目的。而Proxy可以很好的监听数组的变化。

proxy 监听数组

const list = [];
// 第一个参数是个数组。
通过set监听bush的数据。
const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value,0);
    target[property] = value;
    return true;
  }
})
listProxy.push(100)
listProxy.push(10)
set 0 100 0 // 输出 输出两边不知道为什么。
set length 1 0
set 1 10 0
set length 2 0

class

es6以前我们创建一个函数实例对象。需要写一个函数,在函数里面this.实例的属性。在prototype上创建实例的方法。
es6为我们提供了class关键字来创建实例。在construrtor里面写属性。在class关键字创建的这个对象里面可以写实例的方法。class LKWineList extends Component :extends可以使用这个关键字继承。

class Person {
    constructor(name) {
        this.name = name
    } 
    say () {
        console.log(`hi, my name is ${this.name}`)
    }
}
const p = new Person('tom');
p.name 

static

在es2015中可以创建一个类的静态方法。使用类名可以直接访问。但是这类的静态方法指向
这个类而不是这个实例。

class Person {
  static say (name) {
    return new Person(name) 
  }
  constructor(props) {
    console.log(props)
  }
  created() {
    console.log(123)
  }
}
const p = Person.say('333')
p.created()

extends

使用关键字继承。

// extends 继承关键字
class Student extends Person {
  constructor(number){
    super() // 是否继承父类的方法。
    this.number = number;
  }
  hello () {
    super.created(); // 调用父集类的方法。
    console.log(this.number)
  }
}
const s = new Student('jack', 100);
s.hello()

set

作用数组去重。

const s = new Set();
s.add : add方法添加一个元素。如果后面添加的元素里面已经有了会忽略这个元素。
s.size: 获取new Set() 的长度。
s.has: 判断new Set() 里面有没有这个值。返回true false.
s.delete: 删除某一个元素, 返回剩下的额元素。
s.clear()  清空set.
for of 或者 forEach遍历。
const arr = [1,2,3,33,2,1];
const result = new Array(new Set(arr));
const res = [...new Set(arr)]
console.log(res, result)

Map 类似与对象。

Map 和对象的别。Map可以任何类型作为健。而对象会将他们tostring()的结果作为健。
导致健名重复。或者不可用。

const obj = {}
obj[true] = 'value';
obj[123] = 'value';
obj[{a: 1}] = 'value';
// console.log(Reflect.ownKeys(obj))
// console.log(obj['[object Object]'])
const m = new Map();
const tom = {name: 'tom'}
m.set(tom, 90)
console.log(m)
console.log(m.get(tom))
m.forEach((val, key) => {
  console.log(val, key)
})

Symbol 一种全新的原始数据类型。

Symbol() 创建出来是不会重复的。
最主要的功能为对象添加一个 独一无二的属性名。

// shared.js =============
   const cache = {}

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

cache['foo'] = Math.random()

// b.js ==================
cache['foo'] = '123'


console.log(cache);

const s1 = Symbol.for('foo');
const s2 = Symbol.for('foo');
s1 === s2 // for方法可以是两个字符串相等。
console.log(Symbol.for(true) === Symbol.for('true') // 都会先变成字符串再生成Symbol.

const obj = {}
console.loh(obj.toString() // '[object Onject]' // toString标签。
// 可以自定义标签。
const  obj = {
    [Symbol.toStringTag]: XObject
}
console.log(obj.toString) // [object XObject]

for in 循环枚举 不到该属性。

Object.getOwnPropertySymbols(obj) // 可以获取Symbol设置的属性名。

所以Symbol适合设置对象的私有属性。

for of

for in 遍历健值对。

for of 可以遍历所有的。

const m = new Map()
m.set('foo', '123')
m.set('bar', '345')
for (let [key, value] of m) {
    console.loog(key, value)
}

当我们使用for of 遍历对象的时候发现会报错。
是因为可以被遍历的都会有个一个迭代器的方法。
实现迭代器

const obj = {
    store: ['foo', 'bar', baz]
    [Symbol.inerator]: function () {
    let index = 0;
    const self = this
    
        return {
            next: function () {
                const result = {
                    value: self.store[index],
                    done: index >= self.store.length
                }
                index ++
                return ++
            }
        }
    }
}
for (const item of obj) {
    console.log(item)
}

实现迭代器的意义。就是对外提供统一的遍历接口。让外部不用担心数据内部的数据结构是怎么样的。

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  // 提供遍历数据
  each: function () {
    const all = [].concat(this.life, this.learn, this.work);
    for (const e of all) {
      console.log(e)
    }
  },
  // 提供统一的遍历方法迭代器。
  [Symbol.iterator]: function() {
    const all = [...this.life, ...this.learn, ...this.work];
    let index = 0;
    return {
      next: function () {
        return {
          value: all[index],
          done: index++ >= all.length
        }
      }
    }
  }
}
for (const e of todos) {
  console.log(e)
}
console.log('---------------')
todos.each()

生成器函数

生成器内部实现了一个迭代器

function * foo () {
  console.log('1111');
  yield 100;
  console.log('2222');
  yield 200;
  console.log('3333');
  yield 300;
}
const genrator = foo();
console.log(genrator.next())
console.log(genrator.next())
console.log(genrator.next())
console.log(genrator.next())

生成器函数的应用。

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  // 提供遍历数据
  each: function () {
    const all = [].concat(this.life, this.learn, this.work);
    for (const e of all) {
      console.log(e)
    }
  },
  // 提供统一的遍历方法迭代器。
  [Symbol.iterator]: function * () {
    const all = [...this.life, ...this.learn, ...this.work];
    for (const e of all) {
        yield e
    }
   
  }
}
for (const e of todos) {
  console.log(e)
}

ECMAScript 2016

includes判断数组是否有这个值。返回布尔值。

const arr = ['foo', 1, NaN, false];
console.log(arr.indexOf('foo'))
console.log(arr.indexOf(1))
console.log(arr.indexOf(NaN)) // 不能判断
console.log(arr.includes(NaN)) // 可以判断并返回布尔值。
console.log(arr.indexOf(false))

指数运算符

console.log(Math.pow(2, 10); // 二的十次方
console.log(2 ** 10)  // 二的十次方 ECMAScript 2016

ECMAScript 2017

对象扩展方法
Object.values() // 获取对象的值。
Object.entries()

const obj = {
  foo: 'values',
  bar: 'values'
};
console.log(Object.entries(obj))
console.log(new Map(Object.entries(obj)));
const map = new Map(Object.entries(obj));
for (const e of map) {
  console.log(e[0])
  console.log(e[1])
}

// 输出
[ [ 'foo', 'values' ], [ 'bar', 'values' ] ]
Map { 'foo' => 'values', 'bar' => 'values' }
foo
values
bar
values

Object.getOwnPropertyDescriptors§;

深度复制内部属性。

const p = {
  firstName: 'lei',
  lastName: 'wang',
  get fullName () {
    return this.firstName + this.lastName
  }
}
const cp = Object.assign({}, p)
console.log(p) // { firstName: 'lei', lastName: 'wang', fullName: [Getter] }
console.log(cp) // { firstName: 'lei', lastName: 'wang', fullName: 'leiwang' } // 将fullname执行结果复制了
const des = Object.getOwnPropertyDescriptors(p); // 获取对象所有属性包含是可读写
const p2 = Object.defineProperties({}, des);
console.log(p2) // { firstName: 'lei', lastName: 'wang', fullName: [Getter] } 全部复制了
p2.firstName = '333';
console.log(p2.fullName) // 333wang 修改互不影响
console.log(p.fullName) // leiwang

老生常谈: const let var

闭包是函数作用域为了摆脱 全局作用域带来的影响。
有了ES2015我们可以使用块级作用域来解决全局作用域带来的影响。

for 有两层作用域 这两个分别有自己的作用域。

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

解析: 
let i = 0;

if (i < 3) {
    console.log(i)
}
i ++ 

const 和 let 的区别 const只声明了只读特性。
const 声明必须赋值。
const 不允许修改它指向的内存地址。但是可以修改他的属性。
最佳实践: 不用var 主用const 配合let.
总结

const 配合let 可以让我们知道我们声明的变量是可读写的。还是只读的。减少不可预测的结果。

数组的解构

当结构提取的成员小于要结构的数据时,会从左到解构出来。
当结构提取的成员大于要结构的数据时,多余的会返回undefind.类似于为定义了没有赋值的变量。

const arr = [ 100, 200, 300 ];

const [a, ...res] = arr;
console.log(a, res)
// 100 [ 200, 300 ]
// 赋默认值。
const [a, , , d=2 ] = arr;
console.log(d)
对象的解构

根据健匹配值。

const obj = {name: 'zce', age: 18};
const name = 'yoom';
// 如果结构出现同名可以起个别名。 也可以添加默认值。
const { name: objName = "123" } = obj;
console.log(objName, name)
模版字符串的高级用法
const res = console.log `打印`
输出 : [ '打印' ];


const name = 'tom';
const gender = 'true'
function myTagFunc (val, name, gender) {
  console.log(val, name, gender) // 输出: [ 'hey, ', ' is a ', '' ] 'tom' 'true'
  // 返回值等于res的值。
  return val[0] + name+ val[1] + gender + val[2]
}
const res = myTagFunc`hey, ${name} is a ${gender}`
console.log(res) //  hey, tom is a true

扩展方法:

const message = `Error: foo is not defind.`

console.log(message.startsWith('')) // 判断字符串一某某开头 返回布尔值 true
console.log(message.endsWith('。')) // 判断字符串一某某结尾 返回布尔值 false
console.log(message.includes('foo')) // 字符串包含某某     返回布尔值 true

默认值参数

带有默认值的参数 需要放在参数最后面。

剩余参数

在es2015之前js接收剩余参数使用arguments接收。

之前:
function foo () {
    console.log(arguments) // [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4 }
}
foo(1,2,3,4);

es2015: 
function foo (first, ...args) {
    console.log(first, args)  // 1 [ 2, 3, 4 ] 
}
foo(1,2,3,4);
彻底弄懂箭头函数

箭头函数表达式的语法比函数表达式更简洁, 它并没有自己的this, arguments super 或new target. 箭头函数表达式更适用于哪些本来需要匿名函数的对方。并且它不能用作构造函数。

高级语法:

// 加括号的函数体返回对象的字面量
params => ({foo: bar}) ;
// 支持剩余参数和默认参数。 参数支持解构。
没有单独的this.

在箭头函数出现之前。每一个新函数根据它是被如何调用的来定义这个函数的this值。

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this.当前作用域当中的this, 任何方式都没有办法改变它的this.

while 阻断主进程谁也执行不了,等我执行完才行。

对象字面量的增强

const bar = '345';
const obj = {
  foo: 123,
  // 定义的变量和名字一致的话可以这样简写
  bar,
  // 函数名一样 的话或者匿名也可以简写。
  method1() {
    console.log(this, 888)
  }
  // 如果这个属性名是个变量的话 可以加方括号写。
  [Math.random()]: 123;
}
console.log(obj);
obj.method1()
Object.assign 扩展方法

Object.assign 是深拷贝吗????? 不是。只是对其可枚举的属性值的拷贝。
如果它是对一个对象的引用。它仅仅会 复制其引用值。

const source1 = {
  a: 123,
  b: 123
}
const source2 = {
  a: 789,
  d: 789
}
const target = {
  a: 456,
  c: 456
}
// Object.assign() 右边的对象合并到左边,如果两个对象有相同的健,则右边替换左边的值。如果右边有左边没有的话,则新加上这个属性。
const result = Object.assign(target, source1, source2)

console.log(target === result, target) // true

function func (obj) {
 // 用来复制一个新的对像。 
  let newObj = Object.assign({}, obj)
  // 在函数内部进行操作。而不改变外面的值。
  newObj.name = 'func obj';
  console.log(newObj, 2)
}
const obj = {name: 'global obj'};
func(obj);
console.log(obj);
Object.is 判断两个值是否相等 (感觉用处不大)
console.log(
  // +0 === -0
  // NaN === NaN
  // 判断出NaN等于NaN
  Object.is(NaN, NaN),
  // 判断出+0不等于-0
  Object.is(-0, +0)

)
Object.defineProperty 和 Proxy


Object.defineProperty 监听不到对象的删除操作。Proxy可以。

const person = {
  name: 'zce',
  age: 20
};
// 第一个参数没目标代理函数。第二个参数是个对象其中又一个监听删除 deleteProperty方法。并且返回一个新的对象。
const personProxy = new Proxy(person, {
 // 一个是代理的对象。一个是传过来的需要删除属性。 删除后原对象属性即被删除。
  deleteProperty(target, property) {
    console.log('delete', property);
    delete target[property];
  }
})
delete personProxy.age;
console.log(personProxy, person, personProxy ===person) // { name: 'zce' } { name: 'zce' } false


Proxy专门为对象做访问代理器的。对象的读写都可以监听到。

const person = {
  name: 'zce',
  age: 20
};
// Proxy 第一个参数是需要代理的对象。 第二个参数是一个对象。这个对象有get set deleteProperty 方法
const personProxy = new Proxy(person, {
// get方法有两个参数。一个是代理的对象。一个是传过来的属性。
// 这个属性可能有也可能没有。
  get (target, property) {
   // 判断如果有这个属性则返回。 没有的话返回默认值。 
    return property in target ? target[property] : '你要的东西我没有';
  },
  // set方法。有三个参数。target 代理的对象。 property:传过来的属性。这个属性可能有也可能没有。没有的话则是新添加的属性。
  有的话则是更新旧属性。 里面可以做你想要的逻辑判断。
  set(target, property, value){
    if (property === 'age' && !Number.isInteger(value)) {
      throw new TypeError(`${value} is not an int`)
    }
    target[property] = value
  }
})
personProxy.age = true;
console.log(personProxy.name);
console.log(personProxy.a);
console.log(personProxy);

在VUE中会重写数组当中的方法。替换数组原型上的方法。从而达到监听的目的。而Proxy可以很好的监听数组的变化。

proxy 监听数组

const list = [];
// 第一个参数是个数组。
通过set监听bush的数据。
const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value,0);
    target[property] = value;
    return true;
  }
})
listProxy.push(100)
listProxy.push(10)
set 0 100 0 // 输出 输出两边不知道为什么。
set length 1 0
set 1 10 0
set length 2 0

class

es6以前我们创建一个函数实例对象。需要写一个函数,在函数里面this.实例的属性。在prototype上创建实例的方法。
es6为我们提供了class关键字来创建实例。在construrtor里面写属性。在class关键字创建的这个对象里面可以写实例的方法。class LKWineList extends Component :extends可以使用这个关键字继承。

class Person {
    constructor(name) {
        this.name = name
    } 
    say () {
        console.log(`hi, my name is ${this.name}`)
    }
}
const p = new Person('tom');
p.name 

static

在es2015中可以创建一个类的静态方法。使用类名可以直接访问。但是这类的静态方法指向
这个类而不是这个实例。

class Person {
  static say (name) {
    return new Person(name) 
  }
  constructor(props) {
    console.log(props)
  }
  created() {
    console.log(123)
  }
}
const p = Person.say('333')
p.created()

extends

使用关键字继承。

// extends 继承关键字
class Student extends Person {
  constructor(number){
    super() // 是否继承父类的方法。
    this.number = number;
  }
  hello () {
    super.created(); // 调用父集类的方法。
    console.log(this.number)
  }
}
const s = new Student('jack', 100);
s.hello()

set

作用数组去重。

const s = new Set();
s.add : add方法添加一个元素。如果后面添加的元素里面已经有了会忽略这个元素。
s.size: 获取new Set() 的长度。
s.has: 判断new Set() 里面有没有这个值。返回true false.
s.delete: 删除某一个元素, 返回剩下的额元素。
s.clear()  清空set.
for of 或者 forEach遍历。
const arr = [1,2,3,33,2,1];
const result = new Array(new Set(arr));
const res = [...new Set(arr)]
console.log(res, result)

Map 类似与对象。

Map 和对象的别。Map可以任何类型作为健。而对象会将他们tostring()的结果作为健。
导致健名重复。或者不可用。

const obj = {}
obj[true] = 'value';
obj[123] = 'value';
obj[{a: 1}] = 'value';
// console.log(Reflect.ownKeys(obj))
// console.log(obj['[object Object]'])
const m = new Map();
const tom = {name: 'tom'}
m.set(tom, 90)
console.log(m)
console.log(m.get(tom))
m.forEach((val, key) => {
  console.log(val, key)
})

Symbol 一种全新的原始数据类型。

Symbol() 创建出来是不会重复的。
最主要的功能为对象添加一个 独一无二的属性名。

// shared.js =============
   const cache = {}

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

cache['foo'] = Math.random()

// b.js ==================
cache['foo'] = '123'


console.log(cache);

const s1 = Symbol.for('foo');
const s2 = Symbol.for('foo');
s1 === s2 // for方法可以是两个字符串相等。
console.log(Symbol.for(true) === Symbol.for('true') // 都会先变成字符串再生成Symbol.

const obj = {}
console.loh(obj.toString() // '[object Onject]' // toString标签。
// 可以自定义标签。
const  obj = {
    [Symbol.toStringTag]: XObject
}
console.log(obj.toString) // [object XObject]

for in 循环枚举 不到该属性。

Object.getOwnPropertySymbols(obj) // 可以获取Symbol设置的属性名。

所以Symbol适合设置对象的私有属性。

for of

for in 遍历健值对。

for of 可以遍历所有的。

const m = new Map()
m.set('foo', '123')
m.set('bar', '345')
for (let [key, value] of m) {
    console.loog(key, value)
}

当我们使用for of 遍历对象的时候发现会报错。
是因为可以被遍历的都会有个一个迭代器的方法。
实现迭代器

const obj = {
    store: ['foo', 'bar', baz]
    [Symbol.inerator]: function () {
    let index = 0;
    const self = this
    
        return {
            next: function () {
                const result = {
                    value: self.store[index],
                    done: index >= self.store.length
                }
                index ++
                return ++
            }
        }
    }
}
for (const item of obj) {
    console.log(item)
}

实现迭代器的意义。就是对外提供统一的遍历接口。让外部不用担心数据内部的数据结构是怎么样的。

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  // 提供遍历数据
  each: function () {
    const all = [].concat(this.life, this.learn, this.work);
    for (const e of all) {
      console.log(e)
    }
  },
  // 提供统一的遍历方法迭代器。
  [Symbol.iterator]: function() {
    const all = [...this.life, ...this.learn, ...this.work];
    let index = 0;
    return {
      next: function () {
        return {
          value: all[index],
          done: index++ >= all.length
        }
      }
    }
  }
}
for (const e of todos) {
  console.log(e)
}
console.log('---------------')
todos.each()

生成器函数

生成器内部实现了一个迭代器

function * foo () {
  console.log('1111');
  yield 100;
  console.log('2222');
  yield 200;
  console.log('3333');
  yield 300;
}
const genrator = foo();
console.log(genrator.next())
console.log(genrator.next())
console.log(genrator.next())
console.log(genrator.next())

生成器函数的应用。

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  // 提供遍历数据
  each: function () {
    const all = [].concat(this.life, this.learn, this.work);
    for (const e of all) {
      console.log(e)
    }
  },
  // 提供统一的遍历方法迭代器。
  [Symbol.iterator]: function * () {
    const all = [...this.life, ...this.learn, ...this.work];
    for (const e of all) {
        yield e
    }
   
  }
}
for (const e of todos) {
  console.log(e)
}

ECMAScript 2016

includes判断数组是否有这个值。返回布尔值。

const arr = ['foo', 1, NaN, false];
console.log(arr.indexOf('foo'))
console.log(arr.indexOf(1))
console.log(arr.indexOf(NaN)) // 不能判断
console.log(arr.includes(NaN)) // 可以判断并返回布尔值。
console.log(arr.indexOf(false))

指数运算符

console.log(Math.pow(2, 10); // 二的十次方
console.log(2 ** 10)  // 二的十次方 ECMAScript 2016

ECMAScript 2017

对象扩展方法
Object.values() // 获取对象的值。
Object.entries()

const obj = {
  foo: 'values',
  bar: 'values'
};
console.log(Object.entries(obj))
console.log(new Map(Object.entries(obj)));
const map = new Map(Object.entries(obj));
for (const e of map) {
  console.log(e[0])
  console.log(e[1])
}

// 输出
[ [ 'foo', 'values' ], [ 'bar', 'values' ] ]
Map { 'foo' => 'values', 'bar' => 'values' }
foo
values
bar
values

Object.getOwnPropertyDescriptors§;

深度复制内部属性。

const p = {
  firstName: 'lei',
  lastName: 'wang',
  get fullName () {
    return this.firstName + this.lastName
  }
}
const cp = Object.assign({}, p)
console.log(p) // { firstName: 'lei', lastName: 'wang', fullName: [Getter] }
console.log(cp) // { firstName: 'lei', lastName: 'wang', fullName: 'leiwang' } // 将fullname执行结果复制了
const des = Object.getOwnPropertyDescriptors(p); // 获取对象所有属性包含是可读写
const p2 = Object.defineProperties({}, des);
console.log(p2) // { firstName: 'lei', lastName: 'wang', fullName: [Getter] } 全部复制了
p2.firstName = '333';
console.log(p2.fullName) // 333wang 修改互不影响
console.log(p.fullName) // leiwang
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值