Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to implement getter/setter in JavaScript

2025-03-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

It is believed that many inexperienced people have no idea about how to implement getter/setter in JavaScript. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

Although ES5 provides us with the Object.defineProperty method to set up getter and setter, this native method is not convenient to use, so why not implement a class ourselves, as long as we inherit it and follow certain specifications, we can have comparable native getter and setter.

Now let's define the following specifications:

The selector and setter follow the format: _ xxxGetter/_xxxSetter,xxx represents the attribute that needs to be controlled. For example, if you want to control the foo property, the object needs to provide the _ fooGetter/_fooSetter method as the actual selector and controller, so that we can take and set the value with calls to obj.get ('foo') and obj.set (' foo', value) in the code; otherwise, calling the get and set methods is equivalent to code: obj.foo and obj.foo = value

Provide the watch function: obj.watch (attr, function (name, oldValue, newValue) {}); the fucntion parameter is triggered each time the set method is called. In function, name represents the changed attribute, oldValue is the value of the last attribute, and newValue represents the * * value of the attribute. This method returns an handle object, has the remove method, and calls remove to remove the function parameter from the function chain.

First, using the closure pattern, use the attributes variable as a private attribute to store the getter and setter of all attributes:

Var Stateful = (function () {'use strict'; var attributes = {Name: {s:' _ NameSetter', g:'_ NameGetter', wcbs: []}}; var ST = function () {}; return ST;}) ()

Wcbs is used to store all callback when calling watch (name, callback).

The implementation code of * version is as follows:

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); / / call the _ nameSetter method if the object has it, otherwise assign a value directly on the object. 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);};}

The overall code after the change is as follows:

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) {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;}) ()

Test:

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'))

Output:

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 AAAAAA + * Name AAA+ new AAAnew AAABBB

The above code is the principle of dojo/Stateful.

After reading the above, have you mastered how to implement getter/setter in JavaScript? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 258

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report