返回顶部
首页 > 资讯 > 精选 >如何进行JavaScript中getter/setter的实现
  • 807
分享到

如何进行JavaScript中getter/setter的实现

2023-06-17 07:06:49 807人浏览 八月长安
摘要

如何进行javascript中getter/setter的实现,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。虽然ES5中为我们提供了Object.defineProperty方

如何进行javascript中getter/setter的实现,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

虽然ES5中为我们提供了Object.defineProperty方法来设置getter与setter,但此原生方法使用起来并不方便,我们何不自己来实现一个类,只要继承该类并遵循一定的规范就可以拥有媲美原生的getter与setter。

现在我们定义以下规范:

取值器跟设值器遵循格式:_xxxGetter/_xxxSetter,xxx代表需要被控制的属性。例如,如果要控制foo属性,则对象需要提供 _fooGetter/_fooSetter方法来作为实际的取值器与控制器,这样我们可以带代码中调用obj.get(‘foo’)和 obj.set(‘foo’, value)来进行取值与设值;否则调用get与set方法相当于代码:obj.foo和obj.foo = value;

提供watch函数:obj.watch(attr, function(name, oldValue, newValue){});每次调用set方法时,便会触发fucntion参数。 function中name代表被改变的属性,oldValue是上一次该属性的值,newValue代表该属性的***值。该方法返回一个handle对 象,拥有remove方法,调用remove将function参数从函数链中移除。

首先使用闭包模式,使用attributes变量作为私有属性存放所有属性的getter与setter:

var Stateful = (function(){    'use strict';    var attributes = {        Name: {            s: '_NameSetter',            g: '_NameGetter',            wcbs: []        }    };    var ST = function(){};    return ST;})()

其中wcbs用来存储调用watch(name, callback)时所有的callback。

***版实现代码如下:

var Stateful = (function(){    'use strict';    var attributes = {};    function _getNameAttrs(name){        return attributes[name] || {};    }    function _setNameAttrs(name) {        if (!attributes[name]) {            attributes[name] = {                s: '_' + name + 'Setter',                g: '_' + name + 'Getter',                wcbs: []             }        }    }    function _setNameValue(name, value){        _setNameAttrs(name);        var attrs = _getNameAttrs(name);        var oldValue = _getNameValue.call(this, name);        //如果对象拥有_nameSetter方法则调用该方法,否则直接在对象上赋值。        if (this[attrs.s]){            this[attrs.s].call(this, value);        } else {            this[name] = value;        }        if (attrs.wcbs && attrs.wcbs.length > 0){            var wcbs = attrs.wcbs;            for (var i = 0, len = wcbs.length; i < len; i++) {                wcbs[i](name, oldValue, value);            }        }    };    function _getNameValue(name) {        _setNameAttrs(name);        var attrs = _getNameAttrs(name);        var oldValue = null;        // 如果拥有_nameGetter方法则调用该方法,否则直接从对象中获取。        if (this[attrs.g]) {            oldValue = this[attrs.g].call(this, name);        } else {            oldValue = this[name];        }        return oldValue;    };    function ST(){};    ST.prototype.set = function(name, value){        //每次调用set方法时都将name存储到attributes中        if (typeof name === 'string'){            _setNameValue.call(this, name, value);        } else if (typeof name === object) {            for (var p in name) {                _setNameValue.call(this, p, name[p]);            }        }        return this;    };    ST.prototype.get = function(name) {        if (typeof name === 'string') {            return _getNameValue.call(this, name);        }    };    ST.prototype.watch = function(name, wcb) {        var attrs = null;        if (typeof name === 'string') {            _setNameAttrs(name);            attrs = _getNameAttrs(name);            attrs.wcbs.push(wcb);            return {                remove: function(){                    for (var i = 0, len = attrs.wcbs.length; i < len; i++) {                        if (attrs.wcbs[i] === wcb) {                            break;                        }                    }                    attrs.wcbs.splice(i, 1);                }            }        } else if (typeof name === 'function'){            for (var p in attributes) {                attrs = attributes[p];                attrs.wcbs.splice(0,0, wcb); //将所有的callback添加到wcbs数组中            }            return {                remove: function() {                    for (var p in attributes) {                        var attrs = attributes[p];                        for (var i = 0, len = attrs.wcbs.length; i < len; i++) {                            if (attrs.wcbs[i] === wcb) {                                break;                            }                        }                        attrs.wcbs.splice(i, 1);                    }                }            }        }    };    return ST;})()

测试工作:

console.log(Stateful);    var stateful = new Stateful();    function A(name){        this.name = name;    };    A.prototype = stateful;    A.prototype._NameSetter = function(n) {        this.name = n;    };    A.prototype._NameGetter = function() {        return this.name;    }    function B(name) {        this.name = name;    };    B.prototype = stateful;    B.prototype._NameSetter = function(n) {        this.name = n;    };    B.prototype._NameGetter = function() {        return this.name;    };    var a = new A();    var handle = a.watch('Name', function(name, oldValue, newValue){        console.log(name + 'be changed from ' + oldValue + ' to ' + newValue);    });    a.set('Name', 'AAA');    console.log(a.name);    var b = new B();    b.set('Name', 'BBB');    console.log(b.get('Name'));    handle.remove();    a.set('Name', 'new AAA');    console.log(a.get('Name'), b.get('Name'))

输出:

function ST(){}Namebe changed from undefined to AAAAAANamebe changed from undefined to BBBBBBnew AAA BBB

可以看到将所有watch函数存放于wcbs数组中,所有子类重名的属性访问的都是同一个wcbs数组。有什么方法可以既保证每个实例拥有自己的 watch函数链又不发生污染?可以考虑这种方法:为每个实例添加一个_watchCallbacks属性,该属性是一个函数,将所有的watch函数链 都存放到该函数上,主要代码如下:

ST.prototype.watch = function(name, wcb) {        var attrs = null;        var callbacks = this._watchCallbacks;        if (!callbacks) {            callbacks = this._watchCallbacks = function(n, ov, nv) {                var execute = function(cbs){                    if (cbs && cbs.length > 0) {                        for (var i = 0, len = cbs.length; i < len; i++) {                            cbs[i](n, ov, nv);                        }                    }                }                //在函数作用域链中可以访问到callbacks变量                execute(callbacks['_' + n]);                execute(callbacks['*']);// 通配符            }        }        var _name = '';        if (typeof name === 'string') {            var _name = '_' + name;        } else if (typeof name === 'function') {//如果name是函数,则所有属性改变时都会调用该函数            _name = '*';            wcb = name;        }        callbacks[_name] = callbacks[_name] ? callbacks[_name] : [];        callbacks[_name].push(wcb);        return {            remove: function(){                var idx = callbacks[_name].indexOf(wcb);                if (idx > -1) {                    callbacks[_name].splice(idx, 1);                }            }        };    };

经过改变后整体代码如下:

var Stateful = (function(){    'use strict';    var attributes = {};    function _getNameAttrs(name){        return attributes[name] || {};    }    function _setNameAttrs(name) {        if (!attributes[name]) {            attributes[name] = {                s: '_' + name + 'Setter',                g: '_' + name + 'Getter'            }        }    }    function _setNameValue(name, value){        if (name === '_watchCallbacks') {            return;        }        _setNameAttrs(name);        var attrs = _getNameAttrs(name);        var oldValue = _getNameValue.call(this, name);        if (this[attrs.s]){            this[attrs.s].call(this, value);        } else {            this[name] = value;        }        if (this._watchCallbacks){            this._watchCallbacks(name, oldValue, value);        }    };    function _getNameValue(name) {        _setNameAttrs(name);        var attrs = _getNameAttrs(name);        var oldValue = null;        if (this[attrs.g]) {            oldValue = this[attrs.g].call(this, name);        } else {            oldValue = this[name];        }        return oldValue;    };    function ST(obj){        for (var p in obj) {            _setNameValue.call(this, p, obj[p]);        }    };    ST.prototype.set = function(name, value){        if (typeof name === 'string'){            _setNameValue.call(this, name, value);        } else if (typeof name === 'object') {            for (var p in name) {                _setNameValue.call(this, p, name[p]);            }        }        return this;    };    ST.prototype.get = function(name) {        if (typeof name === 'string') {            return _getNameValue.call(this, name);        }    };    ST.prototype.watch = function(name, wcb) {        var attrs = null;        var callbacks = this._watchCallbacks;        if (!callbacks) {            callbacks = this._watchCallbacks = function(n, ov, nv) {                var execute = function(cbs){                    if (cbs && cbs.length > 0) {                        for (var i = 0, len = cbs.length; i < len; i++) {                            cbs[i](n, ov, nv);                        }                    }                }                //在函数作用域链中可以访问到callbacks变量                execute(callbacks['_' + n]);                execute(callbacks['*']);// 通配符            }        }        var _name = '';        if (typeof name === 'string') {            var _name = '_' + name;        } else if (typeof name === 'function') {//如果name是函数,则所有属性改变时都会调用该函数            _name = '*';            wcb = name;        }        callbacks[_name] = callbacks[_name] ? callbacks[_name] : [];        callbacks[_name].push(wcb);        return {            remove: function(){                var idx = callbacks[_name].indexOf(wcb);                if (idx > -1) {                    callbacks[_name].splice(idx, 1);                }            }        };    };    return ST;})()

测试:

console.log(Stateful);    var stateful = new Stateful();    function A(name){        this.name = name;    };    A.prototype = stateful;    A.prototype._NameSetter = function(n) {        this.name = n;    };    A.prototype._NameGetter = function() {        return this.name;    }    function B(name) {        this.name = name;    };    B.prototype = stateful;    B.prototype._NameSetter = function(n) {        this.name = n;    };    B.prototype._NameGetter = function() {        return this.name;    };    var a = new A();    var handle = a.watch('Name', function(name, oldValue, newValue){        console.log(name + 'be changed from ' + oldValue + ' to ' + newValue);    });    a.set('Name', 'AAA');    console.log(a.name);    var b = new B();    b.set('Name', 'BBB');    console.log(b.get('Name'));    a.watch(function(name, ov, nv) {        console.log('* ' + name + ' ' + ov + ' ' + nv);    });    a.set({        foo: 'FOO',        Goo: 'GOO'    });    console.log(a.get('goo'));    a.set('Name', 'AAA+');    handle.remove();    a.set('Name', 'new AAA');    console.log(a.get('Name'), b.get('Name'))

输出:

function ST(obj){        for (var p in obj) {            _setNameValue.call(this, p, obj[p]);        }    }Namebe changed from undefined to AAAAAABBB* foo undefined FOO* goo undefined GOOGOONamebe changed from AAA to AAA+* Name AAA AAA+* Name AAA+ new AAAnew AAA BBB

以上代码就是dojo/Stateful的原理。

看完上述内容,你们掌握如何进行JavaScript中getter/setter的实现的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网精选频道,感谢各位的阅读!

--结束END--

本文标题: 如何进行JavaScript中getter/setter的实现

本文链接: https://lsjlt.com/news/287555.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何进行JavaScript中getter/setter的实现
    如何进行JavaScript中getter/setter的实现,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。虽然ES5中为我们提供了Object.defineProperty方...
    99+
    2023-06-17
  • JavaScript的setter与getter方法的实例应用
    这篇文章主要讲解了“JavaScript的setter与getter方法的实例应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript的set...
    99+
    2024-04-02
  • Vuex如何获取getter对象中的值(包括module中的getter)
    目录Vuex获取getter对象中的值1.直接从根实例获取2.使用mapGetters取值3.使用module中的getter计算属性获取的getter值需要刷新才能更新描述解决Vu...
    99+
    2024-04-02
  • JavaScript中的预编译如何进行
    本篇内容介绍了“JavaScript中的预编译如何进行”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!&nb...
    99+
    2024-04-02
  • 如何进行TCP Socket中的linux实现
    这篇文章给大家介绍如何进行TCP Socket中的linux实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。TCP Server端:#include <iostream>#include <cstr...
    99+
    2023-06-16
  • JavaScript中如何进行变量提升
    JavaScript中如何进行变量提升,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。变量提升就好比JavaScript引擎用一个很小的代码起重...
    99+
    2024-04-02
  • javascript如何进行累加
    这篇文章将为大家详细讲解有关javascript如何进行累加,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。javascript实现累加的方法:首先创建相应的js示例文件;然后通过“for(var i = ...
    99+
    2023-06-15
  • JavaScript如何实现进制转换
    这篇文章主要讲解了“JavaScript如何实现进制转换”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript如何实现进制转换”吧! ...
    99+
    2024-04-02
  • 如何进行JavaScript设计模型Iterator的实践
    今天就跟大家聊聊有关如何进行JavaScript设计模型Iterator的实践,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所...
    99+
    2024-04-02
  • javascript如何实现36进制的转换
    这篇“javascript如何实现36进制的转换”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这...
    99+
    2024-04-02
  • 如何进行实现Python的配置
    今天就跟大家聊聊有关如何进行实现Python的配置,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Python配置中的一个文本区域,其中某个名字空间可以直接访问,“直接访问” 这里指...
    99+
    2023-06-17
  • 如何进行Hybris UI的Route实现
    如何进行Hybris UI的Route实现,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。登录Hybris前台,在product catalog里选择Digita...
    99+
    2023-06-04
  • JavaScript中函数进阶是怎样现进行的
    JavaScript中函数进阶是怎样现进行的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。全局作用域· 全局作用域是最大的作用域·&...
    99+
    2024-04-02
  • JavaScript如何实现10进制转8进制
    本篇内容介绍了“JavaScript如何实现10进制转8进制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • JavaScript如何实现8进制转10进制
    这篇文章主要介绍JavaScript如何实现8进制转10进制,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 在JavaScript中,可以利用parseI...
    99+
    2024-04-02
  • css如何实现进行中打点效果
    这篇文章主要为大家展示了“css如何实现进行中打点效果”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“css如何实现进行中打点效果”这篇文章吧。代码如下:<...
    99+
    2024-04-02
  • PHP中如何实现对象进行遍历
    小编给大家分享一下PHP中如何实现对象进行遍历,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先我们来了解下一种什么是对象遍历:它主要就是指遍历对象中的,对外部可...
    99+
    2023-06-20
  • 如何进行C#中Dictionary的内部实现分析
    本篇文章为大家展示了如何进行C#中Dictionary的内部实现分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。了解Dictionary的开发人员都了解,和List相比,字典添加会慢,但是查找会比...
    99+
    2023-06-17
  • 如何进行Redlock中Redis分布式锁的实现
    这篇文章将为大家详细讲解有关如何进行Redlock中Redis分布式锁的实现,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。普通实现说道Redis分布式锁大部分人都会想到:setnx+lua,...
    99+
    2023-06-02
  • 如何进行JavaScript重构的分析
    本篇文章为大家展示了如何进行JavaScript重构的分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。通常我们的团队中,开发人员在Java语言层面具备相当的技术素...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作