系统化学习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