ES6
class
吾注:
构造函数的 prototype 属性对象会被每个实例继承 构造函数中的 this 指向实例。用 this 在构造函数中创建的属性是实例的属性 构造函数的出现主要是用来“复用代码逻辑”。用 prototype 继承,用 this 多态。 类是构造函数,构造函数是个函数
实例:会有一个 constructor 属性,指向构造函数。实例.constructor === 构造函数 // true
- instanceof 运算符: 验证原型对象与实例对象之间的关系。 用法:实例 instanceof 构造函数 // true
- isPrototypeOf()方法:判断某个 proptotype 对象和某个实例之间关系。 用法:构造函数.prototype.isPrototypeOf(实例) // true
- hasOwnProperty()方法:判断是本地属性还是 prototype 对象属性。用法:实例对象.hasOwnProperty('name') // true
- in 运算符:判断某个实例是否有某个属性,不管是不是本地属性。用法:属性名 in 实例对象 // true
function Animal(name) {
this.name = name
}
Animal.proptotype.type = 'abcd'
const a = new Animal('a')
a.name // a,多态
a.type // 'abcd',继承
// 简单继承和多态
class Animal {
name() {
return 'Animal'
}
say() {
return this.name()
}
}
class Dog extends Animal {
food = "bone"
name() {
return 'Dog'
}
}
const dog = New Dog()
dog.say() // Dog
// 在类中操作实例里的属性。
class Dog extends Animal {
constructor(name) {
// 子类必须调用super方法,否则创建实例就报错。
super('xyz') // 调用父类的constructor().
// 只有调用super之后,才可以使用this关键字,否则会报错
this.name = name
}
toString() {
return this.name + '' + super.toString() // 调用父类的toString()
}
}
吾注
每一个对象都有proto属性,指向对应的构造函数的 prototype 属性
class
子类的__proto__属性,表示构造函数的继承,总是指向父类子类.__proto__ === 父类
子类 prototype 属性的__proto__属性,表示方法的继承,总是指向父类的 prototype 属性。子类.prototype.__proto__ === 父类.prototype
decorator 修饰器(一个特殊的函数)
在声明阶段实现类和类成员(属性和方法)注解的一种语法。
// 类的修饰符有一个参数,类本身
function log(target) {
// target被修饰的类 如Numberic
const desc = Object.getOwnPropertyDescriptors(target.prototype)
for (const key of Object.keys(desc)) {
// 忽略构造函数constructor
if (key === 'constructor') {
continue
}
const func = desc[key].value
if ('function' === typeof func) {
Object.defineProperty(target.prototype, key, {
value(...args) {
console.log('before' + key)
const ret = func.apply(this, args)
console.log('after' + key)
return ret
},
})
}
}
}
// 类属性的修饰符有三个参数
function readonly(target, key, descriptor) {
descriptor.writable = false
}
// 类方法修饰器,同属性
function validate(target, key, descriptor) {
const func = descriptor.value
descriptor.value = function(...args) {
for (let num of args) {
if ('number' !== typeof num) {
throw new Error(`${num} is not a number`)
}
}
return func.apply(this, arrgs)
}
}
@log
class Numberic {
@readonly PI = 3.14
@validate
add(...nums) {
return nums.reduce((p, n) => p + n, 0)
}
}
new Numberic().add(1, 2) // 调用函数时会打印日志
数组
{
let arr = Array.of(3, 4, 5, 6)
console.log(arr) // [3, 4, 5, 6]
}
{
const a = 3,
b = 4,
c = 'sss'
let arr = Array.of(a, b, c)
console.log(arr) // [3, 4, "sss"]
}
{
// 如果这俩写法没区别,那么这个API的作用是什么
const a = 3,
b = 4,
c = 'sss'
let arr = [a, b, c]
console.log(arr) // [3, 4, "sss"]
}
{
let arr = Array.of()
console.log(arr) // []
}
{
// 把类数组变成数组
let a = document.querySelectorAll('a')
let aArr = Array.from(a)
aArr.forEach(item => {
console.log(item.textContent)
})
console.log(
Array.from([1, 2, 3], item => {
return item + 2
})
) // [3, 4, 5]
}
{
console.log([1, 2, undefined].fill(7)) // [7, 7, 7]
console.log([1, 2, 3].fill(7, 1, 3)) // [1, 7, 7](从1开始替到位置3,不包括3)
}
{
for (let index of [1, 2, 3].keys()) {
console.log(index) // 0 1 2
}
// 报错原因未知
for (let value of [1, 2, 3]) {
console.log(value) // 1 2 3
}
for (let [index, value] of [1, 2, 3].entries()) {
console.log([index, value])
} //[0, 1]
// [1, 2]
// [2, 3]
}
{
console.log([1, 2, 3, 4].copyWithin(0, 3, 4)) // [4, 2, 3, 4] 用从3开始到4结束的位置处的数,替换位置从0开始处的数
}
{
const a = [1, 2, 3, 4]
console.log(
a.find(item => {
return item > 2
})
) // 3 (只返回第一个)
}
{
const a = [1, 2, 3, 4]
console.log(
a.findIndex(item => {
return item > 2
})
) // 2 (只返回第一个的下标)
}
{
console.log([1, 2, NaN].includes(1)) //true(是否包含这个值)
console.log([1, 2, NaN].includes(NaN)) //true(是否包含这个值)
}
对象
{
let o = 1;
let k = 2;
let es6 = {
o,
k
}
let es6_method = {
hello() {
console.log('hello')
}
}
console.log(es6, es6_method.hello()) // hello Object {o: 1, k: 2}
}
{
// 属性表达式:对象属性的key值可以用一个表达式去写
let a = 'b';
let es6 = {
[a]: 'c'
}
console.log(es6) // Object {b: "c"}
}
{
// 判断两个字符串的值是否相等
console.log(Object.is('aaa','aaa')) // true
console.log(Object.is([],[])) // false(因为数组是个引用类型)
console.log(Object.assign({a: 'a'}, {b: 'b'})) // 浅拷贝,不拷贝继承属性(只拷贝自身属性),和不可枚举属性且只拷贝地址,不拷贝地址中对应内容
let test = {
o: 'a',
k: 'b'
}
// Object.entries(test)时,只能用for-of
for(let [key,value] of Object.entries(test)) {
console.log([key, value])
}
}
{
// 报错,对象暂时不能用扩展运算符
let {a, b, ...c} = {
a: 'a',
b: 'b',
c: 'c',
d: 'd'
}
console.log(a, b, c)
}
// 类与对象
// 有些东西只有在实例中才能用
{
class Parent {
// 构造函数
constructor(name="mukewang") {
// 给对象的实例增加一个属性name
// 通过构造函数传入参数
this.name = name;
}
}
// 生成实例(在实例中传参)
let v_parent = new Parent('v');//'v'就是name属性的值
console.log(v_parent) // Parent {name: "v"}
}
{
// 继承
class Parent {
// 构造函数
constructor(name="mukewang") {
// 给对象的实例增加一个属性name
// 通过构造函数传入参数
this.name = name;
}
}
class Child extends Parent {
}
console.log(new Child) // 打印子对象的实例
// Child {name: "mukewang"}
}
{
// 子类的实例如何传参
// 在子类的构造函数中用super方法
class Parent {
constructor(name="mukewang") {
this.name = name;
}
}
class Child extends Parent {
constructor(name="child") {
super(name);// super的参数列表就是父类的参数列表,否则就用父类默认的参数列表
// 如果子类还要用自己的属性,只能写在super后面
this.type = 'child'
}
}
console.log(new Child('这个地方的参数会覆盖child')) // Child {name: "child"}
}
{
// getter,setter(这是属性,不是方法)
class Parent {
constructor(name="mukewang") {
this.name = name;
}
// 这是属性,不是方法
get longName() {
return 'mk' + this.name;
}
set longName(value) {
this.name = value;
}
}
// 我估计,这个地方只能在实例中运行
let v = new Parent();
console.log(v.longName) // mkmukewang
v.longName = 'dddddddddd' // 这是属性,不是方法
console.log(v.longName) // mkdddddddddd
}
{
// static,静态方法就是通过类调用,而不是通过实例调用
class Parent {
constructor(name="mukewang") {
this.name = name;
}
static tell() {
console.log('tell')
}
}
Parent.tell() // tell
}
{
// 静态属性没有console直接就返回了,?
// 静态属性
// 类定义完之后直接在类上定义的就是静态属性
// 没有使用new
class Parent {
constructor(name="mukewang") {
this.name = name;
}
static tell() {
console.log('tell')
}
}
Parent.type = 'test' // test
console.log(Parent.type) //用的时候直接调用
}
// decorators(不能用)
// 类修饰符
// 是个函数;修改行为;修改类的行为,即拓展类的功能
// core-decorators;类的修饰器库
{
let readonly = function(target, name, descriptor) {
descriptor.writable = false
return descriptor
}
class Test {
@readonly
time() {
return '2017'
}
}
let test = new Test();
test.time = function() {
console.log('time')
}
console.log(test.time())
}
{
// 类的静态属性,在类本身上调用
let typename = function(target, name, descriptor) {
target.myname = 'aaa'
}
@typename
class Test {
}
console.log(Test.myname)
}
{
// 埋点
let log=(type) => {
return function(target, name, descriptor) {
let src_method = descriptor.value
descriptor.value = (...arg) => {
src_method.apply(target, arg) {
// 埋点的接口
console.log(`log${type}`)
}
}
}
}
class AD {
@log('show')
show() {
console.log('show')
}
@log('click')
click() {
console.log('click')
}
}
let ad = new AD()
ad.show()
ad.click()
}
函数
{
function test(x = 'aa', y = 'bb', c = '默认值的后面不能带没有默认值的变量') {
console.log(x, y)
}
test('dded') // dded bb
}
{
let x = 'test'
function test(x, y = x) {
console.log(x, y)
}
test('till') // till till
}
{
let x = 'test'
function test(c, y = x) {
console.log(y)
}
test('till') // test
}
{
function test(...arg) {
// 是个数组
for (let v of arg) {
console.log(v)
}
}
test(1, 2, 3, 5) //1,2,3,5(执行4次)
}
{
console.log(...[1, 3, 4]) // 1 3 4(把数组的值解出来)
console.log('a', ...[1, 3, 4]) // a 1 3 4
}
{
let arrow = v => v * 2
// let arrow = () => v*2
// 函数返回值
arrow(4)
}
{
// 尾调用:函数的最后是不是函数(提升性能)
function tail(x) {
console.log(x)
}
function fx(x) {
return tail(x)
}
fx(111111) // 111111
}
// 模块化
// 导出模块
export let A = 123
export function test() {
console.log('test')
}
export class Hello {
test() {
console.log('class')
}
}
// 引入模块
import { A, test, Hello } from ''
import { A } from '' //需要哪个拿那个
import * as lesson from ''
lesson.A
//
export default {
A,
test,
Hello,
}
import test from ''
// test 就代表default里的东西
generator
{
// 数组的内置
const arr = ['aa', 'bb']
const map = arr[Symbol.iterator]()
console.info(map.next()) // Object {value: "aa", done: false}
console.log(map.next()) // Object {value: "bb", done: false}
console.log(map.next()) // Object {value: undefined, done: true}
}
{
const obj = {
start: [1, 2, 3],
end: [7, 8, 9],
[Symbol.iterator]() {
const self = this
let index = 0
const arr = self.start.concat(self.end)
const len = arr.length
return {
next() {
if (index < len) {
return {
value: arr[index++],
done: false,
}
}
return {
value: arr[index++],
done: true,
}
},
}
},
}
for (const key of obj) {
console.log(key) // 1,2,3,7,8,9
}
}
// generator
// 异步编程的解决方案
// next
// yield*
{
const tell = function*() {
yield 'a'
yield 'b'
return 'c'
}
const k = tell()
console.log(k.next()) // Object {value: "a", done: false}
console.log(k.next()) // Object {value: "b", done: false}
console.log(k.next()) // Object {value: "c", done: true}
console.log(k.next()) // Object {value: undefined, done: true}
}
{
const obj = {}
obj[Symbol.iterator] = function*() {
yield 1
yield 2
yield 3
}
for (const value of obj) {
console.log(value) // 1, 2, 3
}
}
{
// 状态机
const state = function*() {
while (1) {
yield 'A'
yield 'B'
yield 'C'
}
}
const status = state()
console.log(status.next()) // Object {value: "A", done: false}
console.log(status.next()) // Object {value: "B", done: false}
console.log(status.next()) // Object {value: "C", done: false}
console.log(status.next()) // Object {value: "A", done: false}
console.log(status.next()) // Object {value: "B", done: false}
console.log(status.next()) // Object {value: "C", done: false}
}
{
// (装插件才能用)
const state = async function() {
while (1) {
await 'A'
await 'B'
await 'C'
}
}
const status = state()
console.log(status.next()) // Object {value: "A", done: false}
console.log(status.next()) // Object {value: "B", done: false}
console.log(status.next()) // Object {value: "C", done: false}
console.log(status.next()) // Object {value: "A", done: false}
console.log(status.next()) // Object {value: "B", done: false}
console.log(status.next()) // Object {value: "C", done: false}
}
{
const draw = function(count) {
// 抽奖逻辑
console.log(`剩余${count}次`)
}
const residue = function*(count) {
while (count > 0) {
count--
yield draw(count)
}
}
const star = residue(5)
const btn = document.createElement('button')
btn.id = 'start'
btn.textContent = '抽奖'
document.body.appendChild(btn)
document.getElementById('start').addEventListener(
'click',
() => {
star.next()
},
false
)
}
{
// 长轮询
const ajax = function*() {
// 对服务端的查询(真实的接口)
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ code: 0 }) // 如果为1,则不断轮询
}, 200)
})
}
const pull = function() {
const generator = ajax()
const step = generator.next()
step.value.then(d => {
if (d.code != 0) {
setTimeout(() => {
console.log('wait')
pull()
}, 1000)
} else {
console.log(d) // Object {code: 0}
}
})
}
pull()
}
解构赋值
{
let a, b
;[a, b] = [1, 2]
console.log(a, b) // 1, 2
}
{
let a, b, rest
;[a, b, ...rest] = [1, 2, 3, 4, 5]
console.info(a, b, rest) // 1, 2, [3, 4, 5]
}
{
// 加一个小括号,貌似不用声明变量
let a, b
;({ a, b } = { a: 1, b: 2 }) // 没有括号报错
console.log(a, b) //1, 2
}
{
let a, b
;[a, b, c = 3] = [1, 2]
console.log(a, b, c) //1, 2, 3
}
{
let a, b
;[a, b, c] = [1, 2]
console.log(a, b, c) //1, 2, undefind(用默认值解决)
}
{
// 两个变量交换
let a = 1
let b = ((2)[(a, b)] = [b, a]) // 我的有报错,说b is not defined(因为在控制台中没有写分号)
console.log(a, b) // 2, 1
}
{
// 接收函数结果
function f() {
return [1, 2]
}
let a, b
;[a, b] = f()
console.log(a, b) // 1, 2
}
{
// 选择接收函数结果(扔掉某个结果)
function f() {
return [1, 2, 3, 4]
}
let a, b
;[a, , , b] = f()
console.log(a, b) //1, 4(中间的被省略了)
}
{
// 接收函数结果
function f() {
return [1, 2, 3, 4]
}
let a, b
;[a, ...b] = f()
console.log(a, b) //1, [2, 3, 4]
}
// 一个是给对象赋值,一个是给变量赋值
{
let a, b
;({ a, b } = { a: 1, b: 2 }) // 没有括号报错
console.log(a, b) //1, 2
}
{
let o = {
p: 44,
q: true,
}
let { p, q } = o
console.log(p, q) // 44, true
}
{
let { a = 10, b = 5 } = { a: 3 }
console.log(a, b) // 3, 5
}
{
// 防止命名冲突
let data = {
title: 'abc',
test: [
{
title: 'test',
desc: 'dddddddddddddddd',
},
],
}
let {
title: esTitle,
test: [{ title: cnTitle }],
} = data
console.log(esTitle, cnTitle) // abc, test
}
set、map、object
// set里的元素必须是唯一的
{
let list = new Set()
list.add(5)
list.add(54)
console.log(list.size) // 2
}
{
let arr = [1, 2, 3, 4, 5]
let list = new Set(arr)
console.log(list) // Set(5) {1, 2, 3, 4, 5}(下标是0-4)
}
{
let list = new Set()
list.add(1)
list.add(1)
console.log(list) // Set(1) {1},重复的将不生效
}
{
let arr = [1, 2, 3, 4, 5, 3, 4, 5]
let list = new Set(arr)
console.log(list) // Set(5) {1, 2, 3, 4, 5}
}
{
let arr = ['add', 'delete', 'clear', 'has']
let list = new Set(arr)
console.log(list.has('add')) // true
console.log(list.delete('add'), list) // true Set(3) {"delete", "clear", "has"}
list.clear()
console.log(list) // Set(0) {}
}
{
// 遍历
let arr = ['add', 'delete', 'clear', 'has']
let list = new Set(arr)
for (let key of list.keys()) {
console.log(key)
}
for (let value of list.values()) {
console.log(value)
}
for (let value of list) {
console.log(value)
}
for (let [key, value] of list.entries()) {
console.log([key, value])
}
list.forEach(item => {
console.log(item)
})
// add ["add", "add"]
// delete ["delete", "delete"]
// clear ["clear", "clear"]
// has ["has", "has"]
}
// weakset
// 与set的区别
// 1、支持的元素不同,只支持Object
// 2、地址的引用,也不会检测是否被垃圾回收掉了
// 没有size属性,没有clear方法,不能遍历
// 有has、delete、add方法,同set
{
let weakset = new WeakSet()
let arg = {}
weakset.add(arg)
// weakset.add(2)
console.log(weakset) // WeakSet {Object {}}
}
map
// 数组类型的key值
{
let map = new Map()
let arr = ['aaa']
map.set(arr)
console.log(map) // Map(1) {["aaa"] => undefined}
map.set(arr, 456)
console.log(map) // Map(1) {["aaa"] => 456}
console.log(map.get(arr)) // 456
}
{
let map = new Map([['a', 123], ['b', 456]])
console.log(map) // Map(2) {"a" => 123, "b" => 456}
console.log(map.size) // 2
console.log(map.delete('a'), map) // true Map(1) {"b" => 456}
console.log(map.clear(), map) // undefined Map(0) {}
}
{
let weakmap = new WeakMap()
let o = {}
weakmap.set(o, 123)
console.log(weakmap.get(o)) // 123
}
// map set 与数组对象的比较
// 增删改查
{
// 增
let map = new Map()
let array = []
let set = new Set()
map.set('t', 1)
array.push({ t: 1 })
set.add({ t: 1 })
console.log(map, array, set) // Map(1) {"t" => 1} [{t: 1}] Set(1) {Object {t: 1}}
// 查
let map_exist = map.has('t')
let array_exist = array.find(item => item.t)
let set_exist = set.has({ t: 1 }) // false,因为不是一个,要存成一个变量
console.log(map_exist, array_exist, set_exist) // true Object {t: 1} false
// 改
map.set('t', 2)
array.forEach(item => {
item.t ? (item.t = 2) : ''
})
set.forEach(item => (item.t ? (item.t = 2) : ''))
console.log(map, array, set) // Map(1) {"t" => 2} [t: 2] Set(1) {Object {t: 2}}
// 删除
// 如果一块儿console,则打印不出,因为delete会影响前者(对于array)
map.delete('t')
let index = array.findIndex(item => item.t)
array.splice(index, 1)
set.forEach(item => (item.t ? set.delete(item) : ''))
console.log(map, array, set) // Map(0) {} [] Set(0) {}
}
{
// set、map和Object
let item = { t: 1 }
let map = new Map()
let set = new Set()
let obj = {}
// 增
set.add(item)
obj['t'] = 1
map.set('t', 1)
console.log(map, set, obj) // Map(1) {"t" => 1} Set(1) {Object {t: 1}} Object {t: 1}
// 查
console.log({
map: map.has('t'),
set: set.has(item),
obj: 't' in obj,
}) // Object {map: true, set: true, obj: true}
// 改
map.set('t', 2)
item.t = 2
obj['t'] = 2
console.log(map, set, obj) // Map(1) {"t" => 2} Set(1) {Object {t: 2}} Object {t: 2}
// 删:set删除时要删item,而不是key
map.delete('t')
set.delete('t')
delete obj['t']
console.log(map, set, obj) // Map(0) {} Set(1) {Object {t: 2}} Object {}
set.delete(item)
console.log(map, set, obj) // Map(0) {} Set(0) {} Object {}
}
数值扩展
{
// 二进制,八进制,大小写无碍
console.log(0b11111000) // 248
console.log(0o707) // 455
}
{
// Number.isFinite(15)一个数是不是有尽
console.log(Number.isFinite(15)) // true
console.log(Number.isFinite(NaN)) // false
console.log(Number.isFinite('true' / 0)) // false
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN(0)) // false
}
{
// Number.inInteger(25)一个数是不是整数
console.log(Number.isInteger(25)) // true
console.log(Number.isInteger(25.0)) // true
console.log(Number.isInteger(25.1)) // false
console.log(Number.isInteger('25')) // false
}
{
// 有效数的上下限,是否是有效数
console.log(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER) // 9007199254740991 -9007199254740991
console.log(Number.isSafeInteger(10)) // ture
console.log(Number.isSafeInteger('a')) // false
}
{
// 取一个小数的整数部分
console.log(Math.trunc(4.1)) // 4
console.log(Math.trunc(4.9)) // 4
}
{
// 判断一个数是正,负,0,还是NaN
console.log(Math.sign(-3)) // -1
console.log(Math.sign(0)) // 0
console.log(Math.sign(3)) // 1
console.log(Math.sign('-3')) // -1
console.log(Math.sign('3')) // 1
console.log(Math.sign('a')) // NaN
}
{
// 一个数的立方根
console.log(Math.cbrt(-1)) // -1
console.log(Math.cbrt(8)) // 2
}
promise
{
const ajax = function() {
console.log('执行')
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
}
ajax().then(() => {
console.log('timeout')
})
// 执行
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// timeout
}
{
const ajax = function() {
console.log('执行')
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
}
ajax()
.then(
() =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 2000)
})
)
.then(() => {
console.log('timeout2')
})
}
{
const ajax = function(num) {
console.log('执行')
return new Promise((resolve, reject) => {
if (num > 5) {
resolve()
} else {
throw new Error('出错了')
}
})
}
ajax(6)
.then(() => {
console.log(6)
})
.catch(err => {
console.log(err)
})
ajax(3)
.then(() => {
console.log(3)
})
.catch(err => {
console.log(err)
})
}
{
// 所有图片加载完再添加到页面
function loadImg(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img')
img.src = src
img.onload = function() {
resolve(img)
}
img.onerror = function(err) {
reject(err)
}
})
}
function showImgs(imgs) {
imgs.forEach(img => {
document.body.appendChild(img)
})
}
Promise.all([
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
]).then(showImgs)
}
{
// 有一个图片加载完就添加到页面
function loadImg(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img')
img.src = src
img.onload = function() {
resolve(img)
}
img.onerror = function(err) {
reject(err)
}
})
}
function showImgs(img) {
const p = document.createElement('p')
p.appendChild(img)
document.body.appendChild(p)
}
Promise.race([
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/dflef0720bea6832.png'),
]).then(showImgs)
}
proxy 和 reflect
// 映射对象
{
let obj = {
time: '2017-05-02',
a: '2017-2',
b: '2017-05',
name: 'net',
_r: 123,
}
let monitor = new Proxy(obj, {
// 拦截对象属性的读取
get(target, key) {
// 不管你读取什么属性,都将属性值的2017替换成2018
return target[key].replace('2017', '2018')
},
set(target, key, value) {
// 只允许修改name属性
if (key === 'name') {
return (target[key] = value)
} else {
return target[key]
}
},
// 拦截key in object操作
has(target, key) {
if (key === 'name') {
return target[key]
} else {
return false
}
},
// 拦截delete
deleteProperty(target, key) {
if (key.indexOf('_' > -1)) {
delete target[key]
return true
} else {
return target[key]
}
},
// 拦截Object.keys,Object.getOwnPropertySymbols,Objet.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter(item => item != 'time')
},
})
// 用户访问的是monitor
console.log(monitor.time, monitor.a, monitor.b) // 2018-05-02 2018-2 2018-05
monitor.time = '2018'
console.log(monitor.time) // 2018-05-02
monitor.name = '2018'
console.log(monitor.name) // 2018
console.log('name' in monitor, 'time' in monitor) // true false
delete monitor.time
console.log(monitor) // Proxy {a: "2017-2", b: "2017-05", name: "2018", _r: 123}
delete monitor._r
console.log(monitor) // Proxy {a: "2017-2", b: "2017-05", name: "2018"}
console.log(Object.keys(monitor)) // ["a", "b", "name", "_r"]
}
// proxy有的方法reflect都有,且用法一致
{
let obj = {
time: '2017-05-02',
a: '2017-2',
b: '2017-05',
name: 'net',
_r: 123,
}
console.log(Reflect.get(obj, 'time')) // 2017-05-02
Reflect.set(obj, 'name', 'aaa')
console.log(obj.name) // aaa
console.log(Reflect.has(obj, 'name')) // true
}
// 用在校验里
{
// 和业务解耦的校验模块
function validator(target, validator) {
return new Proxy(target, {
_validator: validator,
set(target, key, value, proxy) {
// 判断当前的对象有无key值,有就可以赋值
if (target.hasOwnProperty(key)) {
let va = this._validator[key]
// 如果存在则正确映射
if (!!va(value)) {
return Reflect.set(target, key, value, proxy)
} else {
throw Error(`不能设置${key}到${value}`)
}
} else {
throw Error(`${key}不存在`)
}
},
})
}
// 过滤选项,校验条件
const personValidators = {
name(val) {
return typeof val === 'String'
},
age(val) {
return typeof val === 'number' && val > 18
},
}
class Person {
constructor(name, age) {
;(this.age = age), (this.name = name)
// 返回一个拦截对象,即操作的不是Person实例,而是proxy对象
return validator(this, personValidators)
}
}
const person = new Person('lilei', 30)
console.info(person) // Proxy {age: 30, name: "lilei"}
person.name = 48 // Uncaught Error: 不能设置name到48
}
正则与字符串
正则
// u修饰符:i,g;y修饰符;s修饰符(没有实现)
{
// es5
const regex = new RegExp('xyz', 'i')
const regex2 = new RegExp(/xyz/i)
console.log(regex.test('xyz123'), regex2.test('xyz123')) // true true
// es6
const regex3 = new RegExp(/xyz/gi, 'i') // 后面的会把前面的覆盖
console.log(regex3.flags) // i
}
{
// g,y都是全局匹配,g是从上一次匹配的位置继续匹配,y是必须是紧跟着的下一个位置上是才能匹配成功
const s = 'bbb_bb_b'
const a1 = /b+/g
const a2 = /b+/y
console.log(1, a1.exec(s), a2.exec(s))
// 1 ["bbb", index: 0, input: "bbb_bb_b"] ["bbb", index: 0, input: "bbb_bb_b"]
console.log(2, a1.exec(s), a2.exec(s))
// 2 ["bb", index: 4, input: "bbb_bb_b"] null
// 是否开启了y这种匹配模式
console.log(a1.sticky, a2.sticky) // false true
}
{
// u修饰符
// 字符串中有的字符是大于两个字节的要加u修饰符,否则错误
console.log(1, /^\uD83D/.test('\uD83D\uDC2A')) // true(把'\uD83D\uDC2A'当做是两个字符)
console.log(1, /^\uD83D/u.test('\uD83D\uDC2A')) // false(把'\uD83D\uDC2A'当做是一个字符)
console.log(/\u{61}/.test('a')) // false
console.log(/\u{61}/u.test('a')) // true(大括号包括的是一个字符,但是要加u字符才能识别)
console.log(`\u{20BB7}`) // 𠮷
// let s='𠮷'
console.log('u', /^.$/.test(s)) // u false
console.log('u', /^.$/u.test(s)) // u true
console.log(/𠮷{2}/.test('𠮷𠮷')) // false
console.log(/𠮷{2}/u.test('𠮷𠮷')) // true
}
字符串
{
console.log('a', '\u0061') // a a
console.log('s', '\u20db7') // s ⃛7
console.log('s', `\u{20db7}`) // s 𠶷
console.log('s', `\u{20bb7}`) // s 𠮷
}
{
const s = '𠮷'
// es5
console.log(s.length) // 2(因为每两个字节是一个长度)
console.log(s.charAt(0)) // �
console.log(s.charAt(1)) // �
console.log(s.charCodeAt(0)) // 55362
console.log(s.charCodeAt(1)) // 57271
// es6
const s1 = '𠮷a'
console.log(s1.length) // 3
console.log(s1.codePointAt(0)) // 134071(十进制码值)
console.log(s1.codePointAt(0).toString(16)) // 20bb7
console.log(s1.codePointAt(1)) // 57271
console.log(s1.codePointAt(2)) // 97
}
{
// es5(有码值取字符)
console.log(String.fromCharCode('0x20bb7'))
// es6(可能存在兼容问题,报错)
console.log(String.formCodePoint('0x20bb7'))
}
{
const str = '\u{20bb7}acb'
for (let i = 0; i < str.length; i++) {
console.log(str[i]) // 报错
}
for (const code of str) {
console.log(code) // 𠮷, a, c, b,
}
}
{
let str = 'string'
console.log(str.includes('c')) // false
console.log(str.includes('str')) // true
console.log(str.startsWith('str')) // true
console.log(str.endsWith('ng')) // true
}
{
let str = 'abc'
console.log(str.repeat(4)) // abcabcabcabc
}
{
let str = 'abc'
console.log(`sss${str}`) // sssabc
}
{
console.log('1'.padStart(2, '0')) // 01
console.log('1'.padEnd(2, '0')) // 10
}
// 标签模板
{
// 处理多语言转换,处理xss攻击
// abc`i am ${user.name},${user.info}`就是abc函数的返回值
let user = {
name: 'list',
info: 'hello world',
}
console.log(1, abc`i am ${user.name},${user.info}`)
// 1 "i am ,,,listhello world"
function abc(s, v1, v2) {
console.log(2, s, v1, v2)
return s + v1 + v2
}
// 2 ["i am ", ",", "", raw: Array(3)] "list" "hello world"
// function abc(s, v1, v2) {
// console.log(2, s, v1, v2)
// return s+v1+v2
// }
}
{
// raw把斜杠转义,使斜杠不生效
console.log(String.raw`hi\n${1 + 2}`) // hi\n3
console.log(`hi\n${1 + 2}`) // hi, 3(分两次打印)
}
Symbol
// 提供一个独一无二的值
{
const a = Symbol()
const b = Symbol()
console.log(a === b) // false
const c = Symbol.for('c') // c为key值,
const d = Symbol.for('c') // c为key值,
console.log(c === d) // true
}
{
// 通过symbol做key值for in 拿不到这个值
const a1 = Symbol.for('abc')
const obj = {
[a1]: '123',
abc: 222,
c: 'ddd',
}
console.log(obj) // Object {abc: 222, c: "ddd", Symbol(abc): "123"}
for (const [key, value] of Object.entries(obj)) {
console.log(key, value) // abc 222, c ddd
}
Object.getOwnPropertySymbols(obj).forEach(item => {
console.log(obj[item]) // 123
})
Reflect.ownKeys(obj).forEach(item => {
console.log(item) // abc, c, Symbol(abc)
console.log('v', obj[item]) // 222, ddd, 123
})
}