您的位置:首页 > Web前端 > JavaScript

《前端之路》之 JavaScript 进阶技巧之高阶函数(下)

2018-09-10 17:44 417 查看

目录

  • 二、自定义事件
  • 第二章 - 03: 前端 进阶技巧之高阶函数

    一、防篡改对象

    JavaScript共享的本质一直是开发人员心头的痛,因为任何对象都可以被在同一个环境中运行的代码修改。

    ECMAScript5致力于解决这个问题,可以让开发人员定义

    防篡改对象
    (tamper-proof object)。它的原理就是

    通过设置每个对象的属性的一下的默认属性:

    • [[Configurable]] --- 是否可配置
    • [[Writable]] --- 是否可以重新赋值
    • [[Enumerable]] --- 是否可列举的
    • [[Value]] --- 默认值
    • [[Get]]
    • [[Set]]

    1-1:Configurable 和 Writable

    下面我们就针对以上每一个属性进行 解析一下:

    // Demo one
    var o = {}
    Object.defineProperty(o, 'name', {
    value: 'zhang',
    configurable: false
    })
    console.log(o)
    
    Object.defineProperty(o, 'name', {
    writable: false
    })
    
    o.name = 'Li'
    
    console.log(o)  // {name: 'zhange'}  属性未被改变

    上面的 Demo 中 我们将 configurable 属性设置成为 false, 再对比下面的 Demo 来看 configurable 属性作用

    // Demo two
    var o = {}
    Object.defineProperty(o, 'name', {
    value: 'zhang',
    configurable: false
    })
    console.log(o)
    
    Object.defineProperty(o, 'name', {
    writable: true
    })
    
    o.name = 'Li'
    
    // Uncaught TypeError: Cannot redefine property: name 报错

    总结: 当 [[Configurable]] 为 fasle 的时候 [[Writable]] 默认已经被设置 false, 如果去修改 [[Writable]] 的时候
    则会报错。 那么我们就可以理解为 当 [[Configurable]] 为 false 的时候, [[Writable]] 是只能为 false的。

    1-2:Enumerable

    我们还是用 Demo 来进行对比解释:

    var o = {}
    Object.defineProperty(o, 'age', {
    enumerable: true,
    value: 18
    })
    
    for(item in o) {
    console.log(item, o[item])   // age 18
    }

    把 enumerable 设置成 false

    var o = {}
    Object.defineProperty(o, 'age', {
    enumerable: false,
    value: 19
    })
    
    for(item in o) {
    console.log(item, o[item])   // undefined
    }

    1-3:get 、set

    get 和 set 这对双胞胎我们已经说过多次了。这次我们仔细来看下这个~

    var o = {}
    var v = 'coder'
    Object.defineProperty(o, 'job', {
    get: function() {
    console.log('get:', v)
    return v
    },
    set: function(newV) {
    console.log('set:', newV)
    v = newV
    }
    })
    o.job = 'xxx'   // set: xxx
    
    // 很奇怪的一点就是 当我们在 浏览器控制台点开 o 对象的时候,再次去点击 job 属性,就会触发 get 方法。

    2-1:不可扩展对象

    Object.preventExtensions(o)
    可以使得 不能再给对象添加属性和方法

    var o = {name: 'zhang'}
    Object.preventExtensions(o)
    
    o.age = '12'
    console.log(o)      // {name: 'zhang'}
    
    // 已经阻止了给对象添加属性和方法了。再去添加 也未能添加上

    Object.isExtensible(o)
    确定对象是否可以扩展

    var o = {name: 'zhang'}
    var res1 = Object.isExtensible(o)
    Object.preventExtensions(o)
    var res2 = Object.isExtensible(o)
    console.log(res1, res2)     // true false

    2-2:密封的对象

    Object.seal(o)
    密封对象不可扩展,而且已有成员的[[Configurable]]特性被设置为false,意味着不能删除属性和方法。不可增加,不能删除。

    var o = {name: 'Li'}
    Object.isSealed(o)  // false
    Object.seal(o)
    Object.isSealed(o)  // true

    Object.isSealed(o)
    检测时候被密封了(🐝 )

    2-3:冻结的对象

    Object.freeze(o)

    最严格的防篡改级别就是冻结对象(frozen object)。冻结的对象不能扩展,又是密封的,而且对象属性的[[Writable]]特性会被设置为false。

    如果定义了[[Set]]函数,访问器属性仍然是可写的。

    var obj = {age: 123}
    Object.freeze(obj)
    Object.isFrozen(obj)            // true
    Object.isSealed(obj)            // true
    Object.isExtensible(obj)        // false

    Object.isFrozen(o)

    检查是否被冻结

    二、自定义事件

    基于

    观察者模式
    的一种创建松散耦合代码的技术。使用自定义事件有助于解耦相关对象,保持功能的隔绝。

    function EventTarget(){
    this.handlers = {};
    }
    
    EventTarget.prototype = {
    constructor : EventTraget,
    addHandler : function(type,handler){
    if(typeof this.handlers[type] === 'undefined'){
    this.handlers[type] = [];
    }
    this.handlers[type].push(handler);
    },
    fire : function(event){
    if(!event.target){
    event.target = this;
    }
    if(this.handlers[type] instanceof Array){
    var handlers = this.handlers[event.type];
    for(var i = 0,len = handlers.length; i < len; i++){
    handlers[i](event);//执行回调函数
    }
    }
    },
    removeHandler : function(type,handler){
    if(this.handlers[type] instanceof Array){
    var handlers = this.handlers[type];
    for(var i = 0,len = handlers.length; i < len; i++){
    if(handlers[i] === handler){
    break;
    }
    }
    handlers.splice(i,1);//删除
    }
    }
    }

    总结: 以上则为高阶函数中的相关的一些场景的应用,但是这也仅仅是属于基础部分,实际的使用场景还需要大家自己灵活处理。
    好了,本期这篇 blog 就先写到这里。

    GitHub 地址:(欢迎 star 、欢迎推荐 : )

    前端 进阶技巧之高阶函数(下)

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: