前端路
作用域
ES6 在全局作用域、局部作用域外,新增了一个块级作用域。在 { } 中使用 let / const 则会形成块级作用域,在 “块” 外层不能获取到 “块” 中的变量。在 for 循环中,for 的条件语句中声明的参数与其执行语句中声明的参数之间互相不影响,互相独立。可视为 for 循环中嵌套了两层作用域。
for (let i = 0; i < 3; i++) {let i = 'Azer';console.log(i);
}
// Azer Azer Azer
解构赋值
数组的解构
const arr = [100, 200, 300]// 命名并获取对应位置的元素
const [foo, bar, baz] = arr;// 获取某个特定位置的元素,空缺该元素前方的参数位
const [, , baz] = arr;// 获取包含某个特定位置之后的所有元素的数组
const [foo, ...rest] = arr
// rest => [200, 300]// 当解构长度大于原数组长度是,超出部分则会返回 undefined
// 可以通过设置默认值,让超出部分返回默认值
const [foo, bar, baz = 123, more = 'default value'] = arr
对象的解构
const obj = {name: 'Azer', age: 25}
// 解构
const {name, age} = obj
// 重命名
const {name: na} = obj
// 默认值
const {age = 20} = obj
模板字符串
语法
`This is a ${string}`
带标签的模板字符串
- 在模板字符串前添加标签(一个特殊的函数)
- 此时,模板字符传向函数中传入的第一个参数是一个数组,数组中包含的是字符串中按表达式 ${} 分割后的各个部分的字符串
- 标签函数还可以通过键名获取到字符串中对应的参数、表达式的值
- 标签函数的使用,可以对模板字符串进行自定义设置,如对字符串进行校验、替换等。
function log(strings) {console.log(strings)
}
const name = 'Azer'
const result = log`Hi, my name is ${name}.`
// result => [ 'Hi, my name is ', '.' ]
字符串扩展方法
includes()
- 字符串中是否包含指定的字符或字符串
- 接收两个参数
-
第一个参数,
在此字符串内搜索的目标字符串 -
第二个参数为可选参数,表示在字符串中开始搜索的位置(默认为0)
-
starsWith()
- 字符串中是否以指定内容开头
- 接收两个参数
-
第一个参数,
在此字符串内搜索的目标字符串 -
第二个参数为可选参数,表示在字符串中开始搜索的位置(默认为0)
-
endsWith()
字符串中是否以指定内容结尾
rest 操作符
语法
...rest
接收剩余参数
function(arg1, ...rest)
- 通过 ...rest 来获取指定位置往后的所有参数
- rest 为一个数组
- ...rest 必须在参数末尾,其后不能再有其他参数
- ...rest 仅能使用一次
- rest 参数可以替换 'arguments' 类数组的使用
展开数组
const arr = ['foo', 'bar', 'baz']
// 手动 ==> 无法应对不定项
console.log(arr[0], arr[1], arr[2])
// ==>
console.log.apply(console, arr)
// ==>
console.log(...arr)
拷贝对象
- 用于拷贝对象时,拷贝后的对象与源对象不是同一个对象,即执行的是“深”拷贝
- 拷贝的对象,其属性值如果也是一个对象,则此时,两个对象的对应的属性值是同一个对象
- rest 操作符用于拷贝对象时,对于第一层,执行的是值引用,如果存在属性值为对象时,不用对子层级进行“深拷贝”
const cls = {student1: {name: 'Azer',age: 25}
}let obj1 = { ...obj }console.log(obj === obj1) // false
console.log(obj.student1=== obj1.student1) // true
箭头函数
语法
() => {}
const add = (m, n) => m + n;
const add1 = (m, n) => { return m + n };
注意事项
若使用 { } ,则需要通过 return 来返回值
关于 this
箭头函数中是不存在 this 机制的。因此,箭头函数不会改变 this 的指向。
const person = {name: 'Azer',sayHi: name => {console.log(`Hi, my name is ${ this.name }`)}
}
// Hi, my name is undefined
// 此时,this 依旧指向全局,而不是 person 实例
对象
字面量的增强
- 当设置的变量名跟对象的属性值一致时,可以直接写变量名
- 计算属性名,可以通过 [ ] ,使用表达式作为对象的属性名
const bar = '233'
const obj = {foo: 423,bar,[Math.random()]: 'a xi ba'
}
Object.assign()
- 将多个源对象中的属性复制到一个目标对象中
- 若源对象和目标对象中存在同名属性,源对象中的值会覆盖目标对象中对应的值
- 当存在多个源对象时,源对象会逐个覆盖到目标对象中
const src1 = { a: 'src1', b: 'src1' }
const src2 = { a: 'src2', d: 'src2' }
const target = { a: 'target', c: 'target'}const result = Object.assign(target, src1, src2)
console.log(target) // { a: 'src2', c: 'target', b: 'src1', d: 'src2' }
console.log(result === target) // true
Object.is()
- 用于判断两个值是否为同一个值
- 满足的条件
- 都是 undefined
- 都是 null
- 都是 true 或 false
- 都是相同长度的字符串且相同字符按相同顺序排列
- 都是相同对象(意味着每个对象有同一个引用)
- 都是数字且
- 都是 +0
- 都是 -0
- 都是 NaN
- 都是非零而且非 NaN 且为同一个值
console.log(NaN === NaN)
// false
console.log(Object.is(NaN, NaN))
// trueconsole.log(+0 === -0)
// true
console.log(Object.is(+0, -0))
// false
Proxy
对比 Object.defineProperty()
- defineProperty 只能监视对象属性的读写
- Proxy 能够监听更多的对象操作(如删除)
- Proxy 更好的支持数组对象的监视
- Proxy 是以非侵入的方式监管了对象的读写
- 即,Proxy 不需要通过直接操作创建的对象去监听对象
对象的代理
const person = {name: 'cyz',age: 25
}const personProxy = new Proxy(person, {get(target, property) {return property in target ? target[property] : 'default'},set(target, property, value) {if (property === 'age' &&!Number.isInteger(+value)) {throw new TypeError(`${ value } is not an int`)}target[property] = value},deleteProperty (target, property) {delete target[prpperty]}
})
console.log(personProxy.name) // cyz
console.log(personProxy.a) // default
personProxy.age = '23'
console.log(personProxy.age) // 23
delete personProxy.age
console.log(person)
handler
方法 | 触发方式 |
---|---|
get | 读取某个属性 |
set | 写入某个属性 |
has | in 操作符 |
deleteProperty | delete 操作符 |
getPrototypeOf | Object.getPrototypeOf() |
setPrototypeOf | Object.setPrototypeOf() |
isExtensible | Object.isExtensible() |
preventExtensions | Object.preventExtensions() |
getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor() |
defineProperty | Object.defineProperty() |
ownKeys | Object.getOwnPropertyNames() Object.getOwnPropertySymbols() |
apply | 调用一个函数 |
construct | 用 new 调用一个函数 |
对数组对象的监听
const list = []
const listProxy = new Proxy(list, {set (target, property, value) {console.log('set', property, value)target[property] = valuereturn true // 表示设置成功}
})
listProxy.push(100)
// set 0 100
// Proxy 会自动查询数组内元素的下标作为 property
Reflect 对象
Reflect 对象统一提供一套用于操作对象的API(静态函数)
const obj = { name: 'Azer', age: 18 }console.log('name' in obj)
console.log(delete obj['age'])
console.log(Object.keys(obj))
// ===>
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))
API
方法 | 描述 | 对应 |
---|---|---|
apply() | 对一个函数进行调用操作,同时传入一个数组作为调用参数 | function.prototype.apply() |
construct() | 对构造函数进行 new 操作 | new target(...args) |
defineProperty() | Object.defineProperty() | |
deleteProperty() | 作为函数的 delete 操作符 | delete target[key] |
get() | 获取对象身上的某个属性的值 | target[name] |
getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor() | |
getPrototypeOf() | Object.getPrototypeOf() | |
has() | 判断一个对象是否存在某个属性 | in 运算符 |
isExtensible() | Object.isExtensible() | |
ownKeys() | 返回一个包含所有自身属性(不包含继承属性)的数组 | Object.keys() |
preventExtensions() | Object.preventExtensions() | |
set() | 将值分配给属性的函数 | |
setPrototypeOf() | Object.setPrototypeOf() |
类(class)
案例
class Person {constructor (name) {this.name = name}say() {console.log(`My name is ${this.name}`)}static create (name) {return new Person(name)}
}let person = new Person()
方法
- 实例方法:通过这个构造函数所构造的对象去调用
- 静态方法:直接通过类型本身去调用,通过 static 关键字声明
// 承上
const tom = Person.create('tom')
tom.say()
类的继承
class Student extends Person {constructor(name, number) {super(name) // 始终指向父类,即调用父类中对应的方法(函数)this.number = number}hello() {super.say()console.log(`My number is ${this.number}`)}
}
const s = new Student('Azer', '55')
s.hello()
Set
Set 是一个数据集合,是 ES6 中新定义的数据结构,类似于数组,但是 Set 结构对象中不允许存在重复项。添加的项若存在重复,则会被忽略掉。
Set 原型方法
方法(Set.prototype) | 描述 |
---|---|
add(value) | 在对象尾部添加一个元素,返回该对象 |
clear() | 移除对象内所有对象 |
delete(value) | 如果元素存在,则移除该元素 |
entries() | 返回一个新的迭代器对象,该对象包含原对象中的按插入顺序排列的所有元素的值的 [value, value] 数组。即,与 Map 对象类似,以每个元素的值作为键名,生成键值对数组 |
forEach(callback()) | 按照插入顺序,为每一个值调用一次 callback |
has(value) | 判断对象中是否存在某一个值 |
values() | 返回一个新的迭代器对象,该对象包含对象中的按插入顺序排列的所有元素的值 |
keys() | 与 values() 相同 |
常用用途
// 去重
const arr = [4,3,7,6,4,3,7,2,9]
const result = Array.from(new Set(arr))
// ===> const rusult = [...new Set(arr)]
console.log(result) // [4,3,7,6,2,9]
Map
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值
与 Object 的区别
- 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
- Map 中的键值是有序的(FIFO 原则,即先进先出),而添加到对象中的键则不是。
- Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
案例
// key 是字符串
var myMap = new Map();
var keyString = "a string";
myMap.set(keyString, "和键'a string'关联的值");
myMap.get(keyString); // "和键'a string'关联的值"
myMap.get("a string"); // "和键'a string'关联的值"// 因为 keyString === 'a string'// key 是对象
var myMap = new Map();
var keyObj = {},
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.get(keyObj); // "和键 keyObj 关联的值"
myMap.get({}); // undefined, 因为 keyObj !== {}// key 是函数
var myMap = new Map();
var keyFunc = function () {}, // 函数
myMap.set(keyFunc, "和键 keyFunc 关联的值");
myMap.get(keyFunc); // "和键 keyFunc 关联的值"
myMap.get(function() {}) // undefined, 因为 keyFunc !== function () {}// key 是 NaN
var myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"
var otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"
Symbol
- Symbol 存在唯一性
Symbol() === Symbol() // false
Symbol('foo') === Symbol('foo') // false
- Symbol 的对应性是依据传入的字符串
const s1 = Symbol.for('boo')
const s2 = Symbol.for('boo')
console.log(s1 === s2) // true
- Symbol.for() 参数的值为字符串,若传入的值不是字符串,则会默认被转化为字符串
console.log(Symbol.for(true) === console.log('true')) // true
- 使用 Symbol 作为属性名,该属性无法被 for..in..,Object.keys(),JSON.stringify() 获取到
const obj = {[Symbol()]: 'symbol value',foo: 'normal value'
}
for (var key in obj) {console.log(key)
} // foo
console.log(Object.keys) // ['foo']
console.log(JSON.stringify(obj)) // {"foo":"normal value"}
// 获取方法
console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol() ]
-
目前,Symbol 最主要的作用,是为对象添加一个独一无二的属性名
for...of...
概述
- 将作为遍历所有数组结构的统一方式
- 可以通过 break 直接终止循环
- 无法遍历 Object 对象
迭代器(Iterator)
- 可以被 for...of... 遍历的对象,内部必须有一个返回迭代器的 iterator 方法
- 迭代器内部必须有一个 next 方法,作为返回一个迭代结果对象的接口
- 迭代结果对象中,需要有一个 value 作为当前迭代到的数据,以及一个值为布尔值的属性 done 来表示当前迭代是否结束
- 当迭代结束时,返回的迭代结果对象为:
{ value: undefined, done: true }
案例
const obj = {store: ['foo', 'bar', 'baz'],[Symbol.iterator]: function () {let index = 0const self = thisreturn {next: function () {return {value: self.store[index],done: index++ >= self.store.length}}}}
}for (const item of obj) {console.log('循环体', item)
}
// 循环体 foo 循环体 bar 循环体 baz
生成器(Generator)
概念
- 通过在声明函数时添加 * 作为标识
- 可以使用 yield 替代 return 的使用
- 通过调用函数的 next 方法来触发 yield(也由此可见,Generator 支持 Iterator 接口)
- 当函数体中存在多个 yield 时,可以通过调用 next 方法,按顺序触发函数的执行
案例
function* foo() {console.log('111')yield 100console.log('222')yield 200console.log('333')yield 300
}
const generator = foo()
console.log(generator.next()) // 111 { value: 100, done: false}
console.log(generator.next()) // 200 { value: 200, done: false}
console.log(generator.next()) // 300 { value: 300, done: false}
console.log(generator.next()) // { value: undefined, done: true}
应用
// 案例一:发号器
function* createIdMaker() {let id = 1while (true) {yield id++}
}
const idMaker = createIdMaker()
console.log(idMaker.next()) // { value: 1, done: false }
console.log(idMaker.next()) // { value: 2, done: false }
console.log(idMaker.next()) // { value: 3, done: false }// 案例二:使用 Generator 函数实现 iterator 方法
const todos = {life: ['吃饭', '睡觉', '打豆豆'],learn: ['语', '数', '英'],work: ['A', 'B'],[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)
}
// 吃饭 睡觉 打豆豆 语 数 英 A B
以上,为 ES 2015 内容
ES 2016 新增特性
- 判断少数组中是否存在某一个元素
// Array.prototype.includes
let arr = ['a','v','b','d']
arr.includes('a') // true
arr.includes('c') // false
- 指数运算符
console.log(Math.pow(2, 10)) // 1024
// ===>
console.log(2 ** 10) // 1024
ES2017 新增特性
- Object.values
- 返回对象中所有的值所组成的数组
- Object.entries
- 以数组的形式返回对象中的键值对
- 使得对象可以通过 for...of... 来遍历
- 可以借助这个方法,将 Object 对象转化为 Map 对象
const obj = {value1: 'foo',value2: 'bar'
}console.log(Object.values(obj)) // ['foo', 'bar']console.log(Object.entries(obj)) // [['value1', 'foo'], ['value2', 'bar']]
for (const [key, value] of Object.entries(obj)) {console.log(key, value)
} // value1 foo // value2 bar
console.log(new Map(Object.entries(obj))) // Map { 'value1' => 'foo', 'value2' => 'bar' }
- Object.getOwnPropertyDescriptors
- String.prototype.padStart / String.prototype.padEnd
- 用给定的字符串去填充目标字符串知道长度达到指定长度
const books = { html: 4, css: 3, javascript: 10 }
for (const [name, count] of Object.entries(books)) {console.log(`${name.padEnd(18, '=')}|${count.toString().padStart(3, '0')}`)
}
// html==============|004
// css===============|003
// javascript========|010
更多推荐
前端路
发布评论