文章目录
概述
- ECMAScript是一门脚本语言,缩写为ES
- 通常看作为JavaScript的标准化规范
- 实际上JavaScript是ECMAScript的扩展语言
- ECMAScript只提供了最基本的语法
- JavaScript语言本身指的就是ECMAScript
- 2015年开始,ES保持每年一个版本的迭代
- 很多人也把ES2015称之为ES6
- 也有很多人将ES6泛指ES2015之后的所有新版本
(浏览器中的JavaScript)
(node环境中的JavaScript)
(ES各个版本)
变化
- 解决原有语法上的一些问题或者不足。例如let、const上的块级作用域等
- 对原有语法进行增强。例如…展开、参数默认值、模板字符串等
- 全新的对象、全新的方法、全新的功能。例如Promise等
- 全新的数据类型和数据结构。例如Symbol、Set、Map等
let
作用域
- 全局作用域
- 函数作用域
- 块级作用域
var 和 let 区别
作用域
- var:全局作用域和函数作用域
- let:块级作用域
(第一种)
if (true) {
var value = "123"
}
console.log(value) // 123
if (true) {
let value = "123"
}
console.log(value) // ReferenceError: value is not defined
(第二种)
for (var i = 0; i < 3; i++) {
for (var i = 0; i < 3; i++) {
console.log(i)
}
console.log("外循环:", i)
}
// 打印结果
// 0
// 1
// 2
// 外循环: 3
for (let i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++) {
console.log(i)
}
console.log("外循环:", i)
}
// 打印结果
// 0
// 1
// 2
// 外循环: 0
// 0
// 1
// 2
// 外循环: 1
// 0
// 1
// 2
// 外循环: 2
(第三种)
var elements = [{}, {}, {}]
for (var i = 0; i < elements.length; i++) {
elements[i].fun = function () { // 此处的 function 只是声明,并没有运行。在调用时才运行
console.log(i)
}
}
// i 是全局变量,此时的 i = 3
elements[0].fun()
elements[1].fun()
elements[2].fun()
// 打印结果
// 3
// 3
// 3
(可以通过闭包来解决上述问题)
var elements = [{}, {}, {}]
for (var i = 0; i < elements.length; i++) {
elements[i].fun = function (i) {
return function () { // 闭包缓存了 i 的值,在调用时会使用到
console.log(i)
}
}(i) // 此处要调用
}
elements[0].fun()
elements[1].fun()
elements[2].fun()
// 打印结果
// 0
// 1
// 2
var elements = [{}, {}, {}]
for (let i = 0; i < elements.length; i++) {
elements[i].fun = function () {
console.log(i)
}
}
elements[0].fun()
elements[1].fun()
elements[2].fun()
// 打印结果
// 0
// 1
// 2
let 在 for 循环中的特别之处
- 此处的 i 有两个作用域:一个是 for 循环条件内部;一个是 for 循环体内部
for (let i = 0; i < 3; i++) {
let i = "asd"
console.log(i)
// 打印结果
// asd
// asd
// asd
变量提升问题
- var 将变量的声明自动提到最前方
- let 则不可以
// var 的变量已经声明,但是在此处没有赋值
console.log(value)
var value = "asd"
// 打印结果
// undefined
// 直接报错
console.log(value)
let value = "asd"
// 打印结果
// ReferenceError: Cannot access 'value' before initialization
const
- 在let基础上多了“只读”属性,是指变量在声明过后不允许再被修改
const name = "asd"
name = "qqq"
// 打印结果
// TypeError: Assignment to constant variable.
- 不允许修改是指,不能修改变量的内存指向,而不是不允许修改值
const obj = {}
obj.name = "qwe"
console.log(obj)
// 打印结果
// { name: 'qwe' }
- 变量声明的同时,必须要赋值
const name
name = "asd"
// 打印结果
// SyntaxError: Missing initializer in const declaration
解构
数组的解构
- 将变量放入对应的位置,可以拿到对应的值
const arr = [20, 50, 10]
const [num1, num2, num3] = arr
console.log(num1, num2, num3)
// 打印结果
// 20 50 10
- 只是获取其中某些值,需要保留数据的基本结构。只能放在最后位置
const arr = [20, 50, 10]
const [, num2,] = arr
console.log(num2)
// 打印结果
// 50
- 可以添加 … 表示从当前位置开始提取剩下的值
const arr = [20, 50, 10]
const [num1, ...rest] = arr
console.log(rest)
// 打印结果
// [ 50 , 10 ]
- 解构的参数 > 数组个数时,返回 undefined
const arr = [20, 50, 10]
const [num1, num2, num3, more] = arr
console.log(more)
// 打印结果
// undefined
- 在解构中,可以设置默认值
const arr = [20, 50, 10]
const [num1, num2, num3, more="new value"] = arr
console.log(more)
// 打印结果
// new value
对象的解构
- 以对象的key作为解构途径
const obj = { name: "asd", age: 12 }
const { name } = obj
console.log(name)
// 打印结果
// asd
- 对 对象解构中的变量 进行重命名
const obj = { name: "asd", age: 12 }
const name = "qwe"
const { name: objName } = obj
console.log(name)
console.log(objName)
// 打印结果
// qwe
// asd
- 进行重命名之后的,使用原来的变量会报错
const obj = { name: "asd", age: 12 }
const { name: objName } = obj
console.log(name)
// 打印结果
// ReferenceError: name is not defined
- 添加默认值
const obj = { name: "asd", age: 12 }
const { gender: objGender = "Female" } = obj
console.log(objGender)
// 打印结果
// Female
模板字符串
- 使用反引号来创建字符串
- 反引号中,使用反斜杠来转义反引号
const str = `hello es2015, this is a \`string\``
console.log(str)
// 打印结果
// hello es2015, this is a `string`
- 支持换行
const str = `hello es2015,
this is a \`string\``
console.log(str)
// 打印结果
// hello es2015,
//
// this is a `string`
- 支持插值表达式 ${}
- 插值表达式内,可以进行数学运算、接受方法返回值等
const name = "Eilsen"
const str = `my name is ${name}, my age is ${3 + 5}, -----${Math.random()}`
console.log(str)
// 打印结果
// my name is Eilsen, my age is 8, -----0.4345345433454454
- 使用方法名,给模板字符串打上标签
const name = 'tom'
const gender = false
function myTagFunc (strings, name, gender) {
console.log("function inner: ", strings, name, gender)
const sex = gender ? 'man' : 'woman'
return strings[0] + name + string[1] + sex + strings[2]
}
const result = myTagFunc`hello, ${name} is a ${gender}.`
console.log("outside result: ", result)
// 打印结果
// function inner: [ 'hello,' , ' is a ' , '.' ] tom false
// outside result: hello, tom is a woman.
字符串扩展方法
startsWith()
const message = 'today is a good day!'
console.log( message.startsWith( "today" ))
// 打印结果
// true
endsWith()
const message = 'today is a good day!'
console.log( message.endsWith( "day!" ))
// 打印结果
// true
includes()
const message = 'today is a good day!'
console.log( message.includes( "good" ))
// 打印结果
// true
参数默认值
- 在参数列表内,使用=设置默认值
- 有多个参数时,带有默认值的参数必须放在最后
function example ( param1, param2 = true ){
console.log( param1 , param2 )
}
example("abc")
// 打印结果
// abc true
剩余参数
- 使用 …args 方式来设置
- …args 只能使用一次,且 args 是数组
- 当有多个参数时,…args 只能放在最后
- 可以代替 arguments 对象来获取参数
function example ( param1, ...args ){
console.log( param1 , args )
}
example("abc" , 1 , 4 , 3 , 6 , false )
// 打印结果
// abc [ 1 , 4 , 3 , 6 , false ]
展开数组
const arr = [ 'apple' , 'banana' , 'grape' ]
// 原始方式1
console.log(
arr[0],
arr[1],
arr[2],
)
// 原始方式2
console.log.apply( console , arr )
// 展开数组
console.log( ...arr )
// 打印结果
// 'apple' 'banana' 'grape'
// 'apple' 'banana' 'grape'
// 'apple' 'banana' 'grape'
箭头函数
原始函数转换为箭头函数
- 使代码更简短、易读
// 原始函数
function example (value) {
return value * value
}
console.log("example : ", example(5) )
// 箭头函数
const example2 = value => value * value
console.log("example2 : ", example2(5) )
// 打印结果
// 25
// 25
箭头函数不会改变this指向
- 在普通函数里,this指向的是当前对象
- 在箭头函数里,this指向的是箭头函数外部的this指向
/** 普通函数 */
const person = {
name: "Linda",
say: function () {
console.log(`hello, I am ${this.name}`)
},
sayAsync: function () {
// 使用闭包来缓存this的指向
// const _this = this
setTimeout(function () {
//此时的function是放在全局环境下,所以this指向的是全局环境
console.log(`async: hi, my name is ${this.name}`)
// 使用闭包来缓存this的指向
// console.log(`async: hi, my name is ${_this.name}`)
}, 1000)
}
}
person.say()
person.sayAsync()
// 打印结果
// hello, I am Linda
// async: hi, my name is undefined
/** 箭头函数 */
const person = {
name: "Linda",
say: () => {
// 此时的 this 指向的是调用person的对象
// 在 node环境 中,this = {}
// 在 window环境中, this = window对象
console.log(`hello, I am ${this.name}`)
},
sayAsync: function () {
setTimeout(() => {
// 箭头函数则是永远指向不变
console.log(`async: hi, my name is ${this.name}`)
}, 1000)
}
}
person.say()
person.sayAsync()
// 打印结果
// hello, I am undefined
// async: hi, my name is Linda
对象字面量的增强
const name = "Linda"
const obj = {
id:123,
// 属性名和变量名一致,可以直接写变量名
name, // name == name : name
// 普通方法可以缩写
// method: function(){
// console.log("method function")
// }
method(){
console.log("method function")
},
// 计算属性名
[ 1 + 2 ]: 123,
[ Math.random() ]: 222,
}
对象常用方法
Object.assign()
- 将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
console.log(returnedTarget);
console.log(target === returnedTarget)
// 打印结果
// { a: 1, b: 4, c: 5 }
// { a: 1, b: 4, c: 5 }
// true
Object.is()
- 判断两个值是否为同一个值
console.log(
0 == false, // true
0 === false, // false
Object.is(0, false) // false
)
console.log(
+0 == -0, // true
+0 === -0, // true
Object.is(+0, -0) // false
)
console.log(
NaN == NaN, // false
NaN === NaN, // false
Object.is(NaN, NaN) // true
)
Proxy()
- 代理:用于定义基本操作的自定义行为
// 目标对象
const person = {
name: "Linda",
age: 22,
}
const proxy = new Proxy(person, {
// get()方法用于进行获取值之前的操作
get(target, property) {
// target:目标对象
// property:属性名
//可以判断该属性是否存在,不存在默认输出default
return property in target ? target[property] : "default"
},
// set()方法用于,为对象设置值之前的操作
set(target, property, value) {
// target:目标对象
// property:属性名
// value:设置的值
// 可以对输入的数据做检测
if (property === "age") {
if (!Number.isInteger(value)) {
throw new TypeError(`${value} is not an integer`)
}
}
// 设置值
target[property] = value
},
// 删除对象中的属性
deleteProperty(target, property) {
delete target[property]
}
})
console.log(proxy.name) // Linda
console.log(proxy.xxx) // default
proxy.gender = "f"
console.log(person) // { name: 'Linda', age: 22, gender: 'f' }
console.log(proxy) // { name: 'Linda', age: 22, gender: 'f' }
console.log(person === proxy) // false
delete proxy.name
console.log(person) // { age: 22, gender: 'f', class: '1A' }
proxy.age = "hahaha" // TypeError: hahaha is not an integer
- 其他方法
Reflect
- Reflect 是一个内置对象
- 提供拦截javascript操作的方法
- Reflect不是一个函数对象,因此他是不可构造的
Reflect.get()
- Reflect.get( target, propertyKey[, receiver] )
- target:需要取值的目标对象
- propertyKey:需要获取的值的键值
- receiver:如果target对象中指定了getter,receiver则为getter调用时的this值。
// Objectvar obj = { x: 1, y: 2 };
Reflect.get(obj, "x");
// 1
// Array
Reflect.get(["zero", "one"], 1);
// "one"
Reflect.set()
- Reflect.set(target, propertyKey, value[, receiver])
- 在一个对象上设置一个属性
- target:设置属性的目标对象。
- propertyKey:设置的属性的名称。
- value:设置的值。
- receiver:如果遇到 setter,receiver则为setter调用时的this值。
// Objectvar obj = {};
Reflect.set(obj, "prop", "value"); // true
obj.prop; // "value"
// Arrayvar arr = ["duck", "duck", "duck"];
Reflect.set(arr, 2, "goose"); // true
arr[2]; // "goose"
// It can truncate an array.
Reflect.set(arr, "length", 1); // true
arr; // ["duck"];
// With just one argument, propertyKey and value are "undefined".
var obj = {};
Reflect.set(obj); // true
Reflect.getOwnPropertyDescriptor(obj, "undefined");// { value: undefined, writable: true, enumerable: true, configurable: true }
Reflect.setPrototypeOf()
- Reflect.setPrototypeOf(target, prototype)
- 可设置对象的原型(即内部的 [[Prototype]] 属性)为另一个对象或 null,如果操作成功返回 true,否则返回 false。
- target:设置原型的目标对象。
- prototype:对象的新原型(一个对象或 null)。
Reflect.setPrototypeOf({}, Object.prototype); // true
// It can change an object's [[Prototype]] to null.
Reflect.setPrototypeOf({}, null); // true
// Returns false if target is not extensible.
Reflect.setPrototypeOf(Object.freeze({}), null); // false
// Returns false if it cause a prototype chain cycle.
var target = {};var proto = Object.create(target);
Reflect.setPrototypeOf(target, proto); // false
Reflect.deleteProperty()
- Reflect.deleteProperty( target, propertyKey )
- target:删除属性的目标对象。
- propertyKey:需要删除的属性的名称。
var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
Reflect.deleteProperty(arr, "3"); // true
arr; // [1, 2, 3, , 5]
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
Reflect.ownKeys()
- Reflect.ownKeys(target)
- 返回一个由目标对象自身的属性键组成的数组
- target:检查是否可扩展的目标对象。
Reflect.ownKeys({z: 3, y: 2, x: 1}); // [ "z", "y", "x" ]
Reflect.ownKeys([]); // ["length"]
var sym = Symbol.for("comet");
var sym2 = Symbol.for("meteor");
var obj = {[sym]: 0, "str": 0, "773": 0, "0": 0,
[sym2]: 0, "-1": 0, "8": 0, "second str": 0};
Reflect.ownKeys(obj);
// [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
// Indexes in numeric order,
// strings in insertion order,
// symbols in insertion order
Reflect.apply()
- Reflect.apply( target, thisArgument, argumentsList )
- 通过指定的参数列表,发起对目标函数的调用
- target:目标函数
- thisArgumenttarget:函数调用时绑定的this对象
- argumentsListtarget:函数调用时传入的实参列表,该参数应该是一个类数组的对象。
Reflect.apply(Math.floor, undefined, [1.75]);
// 1;
Reflect.apply("".charAt, "ponies", [3]);
// "i"
Reflect.construct()
- Reflect.construct( target, argumentsList[, newTarget] )
- target:被运行的目标构造函数
- argumentsList:类数组,目标构造函数调用时的参数。
- newTarget(可选):作为新创建对象的原型对象的constructor属性,默认值为target。
Reflect.apply(Math.floor, undefined, [1.75]);
// 1;
Reflect.apply("".charAt, "ponies", [3]);
// "i"
Reflect.defineProperty()
- Reflect.defineProperty( target, propertyKey, attributes )
- target:目标对象。
- propertyKey:要定义或修改的属性的名称。
- attributes:要定义或修改的属性的描述。
const student = {};
Reflect.defineProperty(student, "name", {value: "Mike"}); // true
student.name; // "Mike"
Reflect.getOwnPropertyDescriptor()
- Reflect.getOwnPropertyDescriptor( target, propertyKey )
- 如果在对象中存在,则返回给定的属性的属性描述符。否则返回 undefined
- target:需要寻找属性的目标对象。
- propertyKey:获取自己的属性描述符的属性的名称
Reflect.getOwnPropertyDescriptor("foo", 0);
// TypeError: "foo" is not non-null object
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x");
// {value: "hello", writable: true, enumerable: true, configurable: true}
Reflect.getOwnPropertyDescriptor({x: "hello"}, "y");
// undefined
Reflect.getOwnPropertyDescriptor([], "length");
// {value: 0, writable: true, enumerable: false, configurable: false}
Reflect.getPrototypeOf()
- Reflect.getPrototypeOf( target )
- 返回指定对象的原型
- target:获取原型的目标对象。
Reflect.getPrototypeOf({}); // Object.prototype
Reflect.getPrototypeOf(Object.prototype); // null
Reflect.getPrototypeOf(Object.create(null)); // null
Reflect.getPrototypeOf('foo') // Throws TypeError
Reflect.has()
- Reflect.has( target, propertyKey )
- 作用与 in 操作符 相同
- target:目标对象.
- propertyKey:属性名,需要检查目标对象是否存在此属性。
Reflect.has({x: 0}, "x"); // true
Reflect.has({x: 0}, "y"); // false
// 如果该属性存在于原型链中,返回true
Reflect.has({x: 0}, "toString");
// Proxy 对象的 .has() 句柄方法
obj = new Proxy({}, {
has(t, k) { return k.startsWith("door"); }});
Reflect.has(obj, "doorbell"); // true
Reflect.has(obj, "dormitory"); // false
Reflect.isExtensible()
- Reflect.isExtensible(target)
- 判断一个对象是否可扩展
- target:检查是否可扩展的目标对象。
var empty = {};
Reflect.isExtensible(empty); // === true
Reflect.preventExtensions(empty);
Reflect.isExtensible(empty); // === false
var sealed = Object.seal({});
Reflect.isExtensible(sealed); // === false
var frozen = Object.freeze({});
Reflect.isExtensible(frozen); // === false
Reflect.isExtensible(1);
// TypeError: 1 is not an object
Reflect.preventExtensions()
- Reflect.preventExtensions(target)
- 阻止新属性添加到对象
- target:检查是否可扩展的目标对象。
// Objects are extensible by default.var empty = {};
Reflect.isExtensible(empty); // === true
// ...but that can be changed.
Reflect.preventExtensions(empty);
Reflect.isExtensible(empty); // === false
Reflect.preventExtensions(1);
// TypeError: 1 is not an object
Set
- Set是一个类型
- Set 内的值不允许重复
- 添加已存在的值,该值会被忽略掉
/** 创建、添加 */
const s = new Set()
// add()方法返回Set对象,可以链式调用
s.add(3).add(6).add(54).add(45)
console.log(s)
// 打印结果
// Set { 3, 6, 54, 45 }
/** 遍历 */
const s = new Set()
s.add(3).add(6).add(54).add(45)
// forEach()方法
s.forEach(i => console.log(i))
// for...of...方法
for (let i of s) {
console.log(i)
}
/** 常用方法 */
const s = new Set()
s.add(3).add(6).add(54).add(45)
// 获取长度
console.log(s.size) // 4
// 查询是否有指定值
console.log(s.has(45)) // true
console.log(s.has(100)) // false
// 删除指定值
console.log(s.delete(45)) // true
console.log(s) // Set { 3, 6, 54 }
console.log(s.delete(500)) // false
// 清空
s.clear()
console.log(s) // Set {}
/** 与数组交互 */
const arr = [3, 67, 3, 7, 4, 7, 5, 0]
// 为数组去重
const s = new Set(arr)
console.log(s) // Set { 3, 67, 7, 4, 5, 0 }
// Set转换为数组
console.log(Array.from(s)) // [ 3, 67, 7, 4, 5, 0 ]
console.log([...s]) // [ 3, 67, 7, 4, 5, 0 ]
Map
- 和Object一样,都是键值对集合
- 与Object不同的是,Object的键最终都会转为字符串类型
const m = new Map()
const person = {
name: "Tom",
age: 24,
}
//Map对象可以存放不同类型的键
m.set(person, "class A")
m.set(true, "123")
m.set(111, 222)
console.log(m) // Map { { name: 'Tom', age: 24 } => 'class A', true => '123', 111 => 222 }
// 遍历
m.forEach((value, key) => {
console.log(key, value)
})
// get()方法
console.log(m.get(true)) // 123
// has()方法
console.log(m.has(person)) // true
// delete()方法
m.delete(111)
console.log(m) // Map { { name: 'Tom', age: 24 } => 'class A', true => '123' }
// clear()方法
m.clear()
console.log(m) // Map {}
Symbol
- Symbol是个类型
- 每创建一个Symbol都是独一无二的
- 可以通过Symbol中的for()静态方法,与一个字符串相关联,并复用已有的Symbol
- 主要用在Object中,可以避免对象属性名重复;也可以作为私有属性,禁止外界直接访问
- 可以通过Object.getOwnPropertySymbols()获取所有Symbol属性
- 可以改变对象的toString标签
const sy = Symbol()
// Symbol是个类型
console.log(typeof sy) // symbol
// 每个Symbol都是独一无二的
console.log(Symbol() == Symbol()) // false
console.log(Symbol() === Symbol()) // false
//可以通过Symbol中的for()静态方法,与一个字符串相关联,并复用已有的Symbol
const s1 = Symbol.for("example")
const s2 = Symbol.for("example")
console.log(s1 === s2) // true
// for() 会对传入的值自动toString()
console.log(Symbol.for(true) === Symbol.for("true")) // true
// 可以用在Object的属性名上
const obj = {
[Symbol()]: "456"
}
obj[Symbol()] = "123"
console.log(obj) // { [Symbol()]: '456', [Symbol()]: '123' }
// 可以用在Object的私有属性上,外界无法直接访问
const name = Symbol()
const person = {
[name]: "Linda",
say: function () {
console.log(`hello ${this[name]}, nice to meet you`)
}
}
person.say() // hello Linda, nice to meet you
for (let item in person) {
console.log(item)
}// normalKey say
console.log(Object.keys(person)) // [ 'normalKey', 'say' ]
console.log(JSON.stringify(person)) // {"normalKey":"normal"}
// 可以通过Object.getOwnPropertySymbols()获取所有Symbol属性
console.log(Object.getOwnPropertySymbols(person)) // [ Symbol() ]
//可以改变对象的toString标签
const obj1 = {}
console.log(obj1.toString()) // [object Object]
obj1[Symbol.toStringTag] = "myObj"
console.log(obj1.toString()) // [object myObj]
for…of 与 iterator
- 使用for…of循环是以实现Iterable接口为前提
- 数组、Set对象、Map对象都已实现了Iterable接口,而Object对象并没有,所以Object使用for…of循环会报错
(数组)
(Set对象)
(Map对象)
(Object对象)
for…of的工作原理
// 调用 被遍历对象的 迭代器Iterable
// 通过 迭代器的 next() 方法获取对象数据
const arr = [1,5,3,7]
const arrIterator = arr[Symbol.iterator]()
console.log(arrIterator.next()) // { value: 1, done: false }
console.log(arrIterator.next()) // { value: 5, done: false }
console.log(arrIterator.next()) // { value: 3, done: false }
console.log(arrIterator.next()) // { value: 7, done: false }
console.log(arrIterator.next()) // { value: undefined, done: true }
console.log(arrIterator.next()) // { value: undefined, done: true }
解析迭代器
- Iterable : 可迭代接口,内部必须要有个用于返回迭代器的 iterator 方法
- Iterator : 迭代器接口,内部必须要有个用于迭代的 next() 方法
- IterationResult : 迭代结果接口,内部必须有 value属性 和 done属性
const obj = {
store: ["as", "sd", "df", "fg"],
[Symbol.iterator]: function () { // Iterable : 可迭代接口,内部必须要有个用于返回迭代器的 iterator 方法
let idx = 0 // 循环对象下标
let self = this // 使用闭包特性,将当前对象缓存
return {
next: function () { // Iterator : 迭代器接口,内部必须要有个用于迭代的 next() 方法
let result = { // IterationResult : 迭代结果接口,内部必须有 value属性 和 done属性
value: self.store[idx],
done: idx >= self.store.length
}
idx++
return result
}
}
}
}
for (const item of obj) {
console.log("for inner:", item)
}
// 打印结果
// for inner: as
// for inner: sd
// for inner: df
// for inner: fg
Generator生成器
- Generator生成器也是实现了 Iterator接口
- 使用 * 声明一个函数为Generator生成器函数
- 使用 yield 关键词 暂停该函数的运行,并返回相关的值
- Generator生成器函数返回的是Generator对象
- 可使用 next() 方法 继续执行Generator函数,并传递参数、接受返回值
function* example() {
console.log(11111)
const param1 = yield 100
console.log("param1:", param1)
console.log(22222)
const param2 = yield 200
console.log("param2:", param2)
console.log(33333)
const param3 = yield 300
console.log("param3:", param3)
}
const g = example()
console.log(g)
// Object [Generator] {}
console.log(g.next(1))
// 11111
// { value: 100, done: false }
console.log(g.next(2))
// param1: 2
// 22222
// { value: 200, done: false }
console.log(g.next(3))
// param2: 3
// 33333
// { value: 300, done: false }
console.log(g.next(4))
// param3: 4
// { value: undefined, done: true }
ES2016 (ES7) 概述
Array.prototype.includes
- 检查数组中是否包含指定元素
const arr = ["assd", 123, NaN, true]
//原始方式 indexOf()
console.log(arr.indexOf(true)) // 3
console.log(arr.indexOf(777)) // -1
// includes() 方法
console.log( arr.includes(true) ) // true
console.log( arr.includes(777) ) // false
指数运算符 **
// 原始方法
console.log( Math.pow(2, 10) ) // 1024
// ** 运算符
console.log( 2 ** 10 ) //1024
ES2017 (ES8) 概述
Object.values
- 获取对象中的所有value
- 返回数组
const person = {
name: "Linda",
age: 12,
class: "class A",
grade: "2",
say: function () {
console.log(`hello, I am ${this.name}!`)
}
}
console.log(Object.keys(person)) // [ 'name', 'age', 'class', 'grade', 'say' ]
console.log(Object.values(person)) // [ 'Linda', 12, 'class A', '2', [Function: say] ]
Object.entries
- 将对象中的每对key value,以数组的形式返回
const person = {
name: "Linda",
age: 12,
class: "class A",
grade: "2",
say: function () {
console.log(`hello, I am ${this.name}!`)
}
}
console.log(Object.entries(person))
// [
// [ 'name', 'Linda' ],
// [ 'age', 12 ],
// [ 'class', 'class A' ],
// [ 'grade', '2' ],
// [ 'say', [Function: say] ]
// ]
// 可以使用 for...of来循环
for (const item of Object.entries(person)) {
console.log(item)
}
// [ 'name', 'Linda' ]
// [ 'age', 12 ]
// [ 'class', 'class A' ]
// [ 'grade', '2' ]
// [ 'say', [Function: say] ]
// 可以用于快速创建Map对象
const m = new Map( Object.entries(person) )
Object.getOwnPropertyDescriptors
- 获取对象中,属性的完整描述信息
- 配合着 Object.definedProperties() 来使用
const person = {
name: "Linda",
age: 12,
class: "class A",
grade: "2",
get sayClass() { // 自定义 get 方法
return `hello, I am ${this.name}, I am from ${this.class}`
}
}
console.log(person.sayClass)
// hello, I am Linda, I am from class A
/** 使用 assign() 方法复制对象,不会改变 */
const person2 = Object.assign({}, person)
person2.name = "Tom" // 改变对象内的属性值
// 得到的依旧是原来的数据,因为assign()方法将get方法当做了普通属性来复制
console.log(person2)
// {
// name: 'Tom',
// age: 12,
// class: 'class A',
// grade: '2',
// sayClass: 'hello, I am Linda, I am from class A'
// }
console.log(person2.sayClass)
// hello, I am Linda, I am from class A
/** 使用 getOwnPropertyDescriptors()获取对象属性完整信息,再用 definedProperties() 复制对象就会改变 */
const propDescrip = Object.getOwnPropertyDescriptors(person)
const person3 = Object.defineProperties({}, propDescrip)
person3.name = "Tom"
console.log(person3)
// {
// name: 'Tom',
// age: 12,
// class: 'class A',
// grade: '2',
// sayClass: [Getter]
// }
console.log(person3.sayClass)
// hello, I am Tom, I am from class A
String.prototype.padStart / String.prototype.padEnd
- 两个都是字符串填充方法
- 规定指定的字符长度和填充符
const person = {
name: "Linda",
age: 12,
class: "class A",
grade: "2",
}
for (const [key, value] of Object.entries(person)) {
console.log(`${key.padEnd(10, "-")} | ${value.toString().padStart(10, "*")}`)
}
// name------ | *****Linda
// age------- | ********12
// class----- | ***class A
// grade----- | *********2
在函数参数中添加尾逗号
- 无实际功能上的改变
const person = {
name: "Linda",
age: 12,
class: "class A",
grade: "2",
}