• JavaScript控制对象


    使用getter与setter控制属性访问

    function Ninja() {
        let skillLevel;
        this.getSkillLevel = () => {
            console.log('get')
            return skillLevel;
        }
        this.setSkillLevel = value => {
            console.log('set');
            skillLevel = value;
        }
    }
    const nijia = new Ninja();
    nijia.setSkillLevel(100)
    console.log(nijia, nijia.getSkillLevel() == 100);
    

    定义getter与setter

    在JavaScript中,可以通过两种方式定义getter和setter:

    • 通过对象字面量定义,或在ES6的class中定义。
    • 通过使用内置的Object.defineProperty方法。
    const ninjaCollection = {
        ninjas: ['a','b','c'],
        get firstNinja(){
            console.log('get');
            return this.ninjas[0];
        },
        set firstNinja(value){
            console.log('set');
            this.ninjas[0] = value;
        }
    }
    console.log(ninjaCollection);
    

    在ES6的class中使用getter和setter

    class NinjoCollection {
        constructor(){
            this.ninjas = ['a','b','c'];
        }
        get firstNinja() {
            console.log('get');
            return this.ninjas[0];
        }
        set firstNinja(value) {
            console.log('set');
            this.ninjas[0] = value;
        }
    }
    const ninjiaoCollectionClass = new NinjoCollection();
    console.log(ninjiaoCollectionClass.firstNinja === 'a');
    ninjiaoCollectionClass.firstNinja = 'hello';
    console.log(ninjiaoCollectionClass.firstNinja);
    

    Object.defineProperty

    控制私有变量,下例中_skillLevel是私有的,skillLevel是公有的。

    function Ninja() {
        let _skillLevel = 0;
        Object.defineProperty(this, 'skillLevel', {
            get: () => {
                console.log('get');
                return _skillLevel;
            },
            set: value => {
                console.log('set');
                _skillLevel = value;
            }
        })
    }
    const ninja = new Ninja();
    
    console.log(typeof ninja._skillLevel);
    

    使用getter与setter检验属性

    function Ninja() {
        let _skillLevel = 0;
        Object.defineProperty(this, 'skillLevel', {
            get: () => {
                console.log('get');
                return _skillLevel;
            },
            set: value => {
                console.log('set');
                if(!Number.isInteger(value)){
                    throw new TypeError('必须为整数!')
                }
                _skillLevel = value;
            }
        })
    }
    
    try {
        const ninja = new Ninja();
        ninja.skillLevel = 23.3;
    } catch (error) {
        console.log(error)
    }
    

    使用getter与setter定义如何计算属性值

    const nameObj = {
        name: 'a',
        clan: 'b',
        get fullTitle(){
            return this.name + '-' + this.clan;
        },
        set fullTitle(value){
            const segments = value.split(" ");
            this.name = segments[0];
            this.clan = segments[1];
        }
    };
    console.log(nameObj.name == 'a');
    

    使用代理控制访问

    通过Proxy构造器创建代理

    const emperor = {name: 'pdd'};
    const representative = new Proxy(emperor, {
        get : (target, key) => {
            console.log('get:' + key);
            return key in target ? target[key] : 'error!';
        },
        set: (target, key, value) => {
            console.log('set:' + key);
            target[key] = value;
        }
    });
    console.log(emperor.name === 'pdd',representative.name === 'pdd'); // true true
    console.log(emperor.name1,representative.name1); // undefined "error!"
    

    使用代理记录日志

    上同

    使用代理检测性能-apply

    代理的作用有利于原函数的复用

    假设不用代理:

    判断一个数是否大于2

    function isPrime(number){
        if(number < 2) {
            return false;
        } else {
            return true;
        }
    }
    

    写完后如果要检测该函数的性能,执行了多久,这时就要修改代码,加上console.timeconsole.timeEnd不利于代码的复用,如下:

    function isPrime(number){
        console.time('isPrime');
        if(number < 2) {
            console.timeEnd('isPrime');
            return false;
        } else {
            console.timeEnd('isPrime');
            return true;
        }
    }
    

    function isPrime(number){
        if(number < 2) {
            return false;
        } else {
            return true;
        }
    }
    // 正常打印
    function test1(num){
        console.time('test')
        const result = isPrime(num);
        console.timeEnd('test');
        return result;
    }
    // 隔2秒后再获取时间
    function test2(num){
        console.time('test')
        setTimeout(() => {
            const result = isPrime(num);
            console.timeEnd('test');
            return result;
        }, 2000);
    }
    test1(23); // test: 0.00390625 ms
    test2(23); // test: 2001.0390625 ms
    

    用代理解决

    function isPrime(number){
        if(number < 2) {
            return false;
        } else {
            return true;
        }
    }
    // 正常打印
    isPrime1 = new Proxy(isPrime, {
        apply: (target, thisArg, args) => {
            console.time('isPrime');
            const result = target.apply(thisArg, args);
            console.timeEnd('isPrime');
            return result;
        }
    })
    // 隔2秒后再获取时间
    isPrime2 = new Proxy(isPrime, {
        apply: (target, thisArg, args) => {
            console.time('isPrime');
            setTimeout(() => {
                const result = target.apply(thisArg, args);
                console.timeEnd('isPrime');
                return result;
            }, 2000); 
        }
    })
    isPrime1(23); // isPrime: 0.00390625 ms
    isPrime2(23); // isPrime: 2001.0390625 ms
    

    使用代理计算值-apply

    apply方法拦截函数的调用、call和apply操作

    function sum (a,b) { return a+b };
    var proxy = new Proxy(sum, {
        apply(target, thisArg, args) {
            // return Reflect.apply(...arguments) * 2;
            // 或
            return target.apply(thisArg, args) * 2;
        }
    })
    // 以下调用全都是*2后的结果
    proxy(1,2); // 6
    proxy.call(null, 4,5); // 18
    proxy.apply(null, [29,239]); // 536
    Reflect.apply(proxy, null, [32,10]); // 84
    

    apply实现负数组

    function createNegativeArrayProxy(array) {
        return new Proxy(array, {
            get: (target, index) => {
                index = index < 0 ? target.length + Number(index) : index;
                return target[index];
            }
        })
    }
    var arr = createNegativeArrayProxy(['a', 'b', 'c', 'd']);
    console.log(arr[1],arr[-2]); // b c
    

    普通方法实现暂时想不到,下标也无法获取。

    proxy总结

    • 代理可以代理对象函数数组

    • 代理的过程中,可以在getset中进行拦截和设置新的参数方法;

    • 代理的过程中,可以通过apply绑定拦截原来的函数。

    总结

    1. 使用访问器方法(getter和setter)可以控制对象
    • 通过内容的Object.definedProperty方法访问属性
    • 通过对象字面量中使用get和set语法
    • 通过ES6的class语法

    • 读取对象时会隐式调用get,写入对象时会隐式调用set
    • get可以定义计算属性,set可以实现数据验证与日志记录
    1. 使用代理(proxy)可以控制对象
    • 代理可以定义对象交互时的行为
    • 所有的交互行为必须通过代理
    1. 使用代理(proxy)可以实现以下内容
    • 日志记录
    • 性能测量
    • 数据校验
    • 数组负索引
    1. 使用代理(proxy)效率不高,需进行性能测验
  • 相关阅读:
    C#中的int、long、float、double等类型都占多少个字节的内存
    Bit 存储操作代码碎片
    unity文件写入与读取
    unity调用系统剪切板功能
    LayerMask小结
    NGUI中获取鼠标在控件内部坐标
    【Unity技巧】Unity中的优化技术
    工程源码目录
    Unity3D_NGUI_性能优化实践_CPU卡顿
    Unity3d:UI面板管理整合进ToLua
  • 原文地址:https://www.cnblogs.com/firefly-pengdan/p/13711522.html
Copyright © 2020-2023  润新知