ES8中禁止对象元素枚举

2019-11-11 张宇童 学习日志

let obj = {
    name: '小明',
    age: 18
}
Object.defineProperty(obj, 'age', {
    enumerable: false
})
 for (let i in obj) {
    console.log(i)
 }

console.log(Reflect.ownKeys(obj))
console.log(Object.keys(obj))
console.log(Object.getOwnPropertyDescriptors(obj))

标签: javascript ES6

评论(0) 浏览(452)

ES7中新增的语法指数运算以及includes

2019-11-10 张宇童 学习日志

第一个是includes判断数组中的元素是否存在

let arr = ['hello', 'world']
console.log(arr.includes('hello')) // true
console.log(arr.includes('helle')) // false 
第二个是指数运算。ES7进行了简写

ES5中的做法

Math.pow(2, 2) // 4
ES7中的做法

2 ** 2 // 4

标签: javascript ES6

评论(0) 浏览(455)

使用Generator定义Symbol.iterator可迭代对象

2019-11-10 张宇童 学习日志

let booksInfo = {
    authDescipt: {
        a: ['hello','book', 'san'],
        b: ['nihao', 'henhao', 'three'],
        c: ['aaa', 'bbb', 'ccc']
    }
}

booksInfo[Symbol.iterator] = function *() {
    let AllAuthDescipt = this.authDescipt;
    let keys = Reflect.ownKeys(AllAuthDescipt)
    let values = []
    while(1) {
        if (!values.length) {
            if (keys.length) {
                values = AllAuthDescipt[keys[0]]
                keys.shift()
                yield values.shift()
            } else {
                return false
            }
        }else {
            yield values.shift()
        }
    }
}
o = []
for (let v of booksInfo) {
    o.push(v)
}

console.log(o)

标签: javascript ES6

评论(0) 浏览(436)

使用Symbol.iterator定义可迭代对象

2019-11-10 张宇童 学习日志

let booksInfo = {
    authDescipt: {
        a: ['hello','book', 'san'],
        b: ['nihao', 'henhao', 'three'],
        c: ['aaa', 'bbb', 'ccc']
    }
}


booksInfo[Symbol.iterator] = function () {
    let AllAuthDescipt = this.authDescipt;
    let keys = Reflect.ownKeys(AllAuthDescipt)
    let values = []
    return {
        next() {
            if (!values.length) {
                if (keys.length) {
                    values = AllAuthDescipt[keys[0]]
                    keys.shift()
                }
            }
            return {
                done: !values.length,
                value: values.shift(),
            }
        }
    }
}

for (let v of booksInfo) {
    console.log(v)
// hello
// index.js:31 book
// index.js:31 san
// index.js:31 nihao
// index.js:31 henhao
// index.js:31 three
// index.js:31 aaa
// index.js:31 bbb
// index.js:31 ccc
}

标签: javascript ES6

评论(0) 浏览(484)

Generator抽奖的实现

2019-11-10 张宇童 学习日志

function *draw(first = 1, two = 2, three = 3) {
    let one_arr = ['a1', 'a2', 'a3', 'a4']
    let two_arr = ['b1', 'b2', 'b3', 'b4']
    let three_arr = ['c1', 'c2', 'c3', 'c4']
    let judge = []
    for (let i = 0; i< first; i++) {
        let random = Math.floor(Math.random() * one_arr.length)
        judge = judge.concat(one_arr.splice(random, 1))
    }
    for (let i = 0; i< two; i++) {
        let random = Math.floor(Math.random() * two_arr.length)
        judge = judge.concat(two_arr.splice(random, 1))
    }
    for (let i = 0; i< three; i++) {
        let random = Math.floor(Math.random() * three.lenght)
        judge = judge.concat(three_arr.splice(random, 1))
    }
    for (let i of judge) {
        yield console.log(i)
    }
}

let d = draw()
d.next()

标签: javascript ES6

评论(0) 浏览(381)

proxy详解

2019-11-9 张宇童 学习日志

Proxy

在 ES6 标准中新增的一个非常强大的功能是 Proxy,它可以自定义一些常用行为如查找、赋值、枚举、函数调用等。通过 Proxy 这个名称也可以看出来它包含了“代理”的含义,只要有“代理”的诉求都可以考虑使用 Proxy 来实现。

Basic Syntax

语法

let p = new Proxy(target, handler)

解释

参数 含义 必选
target 用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理) Y
handler 一个对象,其属性是当执行一个操作时定义代理的行为的函数 Y

MDN 给出的解释偏官方,通俗的讲第一个参数 target 就是用来代理的“对象”,被代理之后它是不能直接被访问的,而 handler 就是实现代理的过程。

场景

我们经常读取一个对象的 key-value:

let o = {
  name: 'xiaoming',
  age: 20
}

console.log(o.name) // xiaoming
console.log(o.age) // 20
console.log(o.from) // undefined

当我们读取 from 的时候返回的是 undefined,因为 o 这个对象中没有这个 key-value。想想看我们在读取数据的时候,这个数据经常是聚合的,当大家没有按照规范来的时候或者数据缺失的情况下,经常会出现这种“乌龙”现象。

如果我们不想在调用 key 的时候返回 undefined,之前的做法是这样的:

console.log(o.from || '')

如果我们对所有代码都是这种写法,那阅读性和观赏性就不得而知了。值得庆幸的是,ES6 的 Proxy 可以让我们轻松的解决这一问题:

let o = {
  name: 'xiaoming',
  age: 20
}

let handler = {
  get(obj, key) {
    return Reflect.has(obj, key) ? obj[key] : ''
  }
}

let p = new Proxy(o, handler)

console.log(p.from)

这个代码是想表达如果 o 对象有这个 key-value 则直接返回,如果没有一律返回 '',当然这里是自定义,大家可以根据自己的需要来写适合自己业务的规则。

Schema Validation

刚才对数据的“读操作”进行了拦截,接下来我们描述下“写操作”进行拦截。

场景 1

从服务端获取的数据希望是只读,不允许在任何一个环节被修改。

// response.data 是 JSON 格式的数据,来自服务端的响应
// 在 ES5 中只能通过遍历把所有的属性设置为只读
for (let [key] of Object.entries(response.data)) {
  Object.defineProperty(response.data, key, {
    writable: false
  })
}

如果我们使用 Proxy 就简单很多了:

let data = new Proxy(response.data, {
  set(obj, key, value) {
    return false
  }
})

场景 2

对于数据交互而言,校验是不可或缺的一个环境,传统的做法是将校验写在了业务逻辑里,导致代码耦合度较高。如果大家使用 Proxy 就可以将代码设计的非常灵活。

// Validator.js
export default (obj, key, value) => {
  if (Reflect.has(key) && value > 20) {
    obj[key] = value
  }
}

import Validator from './Validator'
let data = new Proxy(response.data, {
  set: Validator
})

场景 3

如果对读写进行监控,可以这样写:

let validator = {
  set(target, key, value) {
    if (key === 'age') {
      if (typeof value !== 'number' || Number.isNaN(value)) {
        throw new TypeError('Age must be a number')
      }
      if (value <= 0) {
        throw new TypeError('Age must be a positive number')
      }
    }
    return true
  }
}
const person = { age: 27 }
const proxy = new Proxy(person, validator)
proxy.age = 'foo'
// <- TypeError: Age must be a number
proxy.age = NaN
// <- TypeError: Age must be a number
proxy.age = 0
// <- TypeError: Age must be a positive number
proxy.age = 28
console.log(person.age)
// <- 28

// 添加监控
window.addEventListener(
  'error',
  e => {
    console.log(e.message) // Uncaught TypeError: Age must be a number
  },
  true
)

场景 4

什么实例一个对象,每个对象都有一个自己的 id 而且只读。

class Component {
  constructor () {
    this.proxy = new Proxy({
      id: Math.random().toString(36).slice(-8)
    })
  }
  get id () {
    return this.proxy.id
  }
}

练习

  1. 封装 ajax,让返回的数据是只读的

Revocable Proxies

除了使用常规的代理,还可以创建临时的代理,这个临时可以理解为:代理可以取消。

const dinosaur = {
  name: 'Fred',
  isDangerous: true
}

const dinoProxy = Proxy.revocable(dinosaur, {
  get: (target, property) => {
    return 'RAWRRRRRRRR'
  }
})
// We need this assignment because the `revocable` method returns an object with the proxified object and the revoke method
const proxifiedDinosaur = dinoProxy.proxy

// Now everytime we access a property in our `proxifiedDinosaur` it gets intercepted by the `get` trap in our handler
console.log(proxifiedDinosaur.name) // "RAWRRRRRRRR"
console.log(proxifiedDinosaur.isDangerous) // "RAWRRRRRRRR"

// Now, if we call `revoke` on our `dinoProxy` we get a TypeError when accessing properties on `proxifiedDinosaur`
dinoProxy.revoke()
console.log(proxifiedDinosaur.name) // TypeError: Cannot perform 'get' on a proxy that has been revoked
console.log(proxifiedDinosaur.isDangerous) // TypeError: Cannot perform 'get' on a proxy that has been revoked

[!TIP]
一旦 revoke 被调用,proxy 就失效了,这也就起到了“临时”代理的作用

练习

  1. 希望在各个组件初始化的时候都赋值一个随机的 ID,但是这个组件调用这个 ID 是固定的,该怎么做?
  2. 临时代理有哪些应用场景呢?
  3. 如何把接口的数据用代理进行包装?

阅读

标签: javascript ES6

评论(0) 浏览(756)

JavaScript中的Proxy可撤销

2019-11-9 张宇童 学习日志

let obj = {
    name: '小明',
    age: 18
}


let proxy = Proxy.revocable(obj, {
    get (target, key) {
        if (key == 'age') {
            return target[key] + 3
        }
        return target[key] || ''
    }
})

console.log(proxy.proxy.age, proxy)

setTimeout(function () {
    proxy.revoke()
    setTimeout(function () {
        console.log(proxy.proxy.age)
    }, 1000)
}, 1000)

标签: javascript ES6

评论(0) 浏览(450)

JavaScript中的Proxy模块化过滤

2019-11-9 张宇童 学习日志

let source = {
    name: '小李',
    price: 100,
}

function validate(target, key, value) {
    if (Reflect.has(target, key)) {
        if (key == 'price') {
            if (value < 300) {
                return target[key] = value
            }
        }
    }
    return false
    
}

let p = new Proxy(source, {
    get (target, key) {
        if (key == 'price')
        return target[key] || '';
        return '您没有权限'
    },
    set: validate
})
p.price = 200
console.log(p.price, p.name)

标签: javascript ES6

评论(0) 浏览(397)

JavaScript简单使用

2019-11-9 张宇童 学习日志

let a = {
    x: '小花',
    price: 190
}

let p = new Proxy(a, {
    get(target, key) {
        if (key == 'price') {
            return target[key] + 20
        }else {
            return target[key]
        }
    }
})
console.log(a.price)

标签: javascript ES6

评论(0) 浏览(416)

JavaScript中的Reflect

2019-11-9 张宇童 学习日志

let obj = {x: '312', y: '666'}
let arr = ['1','2','3']

// Object.freeze(obj)
let d = new Date()
console.log(Reflect.apply(Math.floor, null, [3.99])) // 3 Reflect.apply 反射
console.log(Reflect.construct(Date, []).getTime()) // 1573292254566 实例化
console.log(Reflect.getPrototypeOf(d))// 打印原型方法 1
console.log(Reflect.has(d, 'constructdor')) // 判断原型链上有没有属性或元素 2
console.log(Reflect.isExtensible(d)) // 判断对象是否可以扩展3
Object.freeze(d) // 冻结对象 使对象不可扩展
console.log(Reflect.isExtensible(d)) // 变成了false
console.log(Reflect.ownKeys(d)) // 查看对象自己的属性 不包含原型链上的属性4
console.log(Reflect.isExtensible(obj)) // true
Reflect.preventExtensions(obj) // 冻结对象5
console.log(Reflect.isExtensible(obj)) // 变成了false
console.log(Reflect.getPrototypeOf(arr))
Reflect.setPrototypeOf(arr, String.prototype) // 修改arr的原型对象

标签: javascript ES6

评论(0) 浏览(416)

Powered by emlog