关于GetterSetter大家一定不会陌生,下面简单介绍几种我所知道的在JavaScript中实现G/S的方法.

 

 

  第一种算是比较常见了,通过闭包Store Value从而实现accessor,适用于所有浏览器.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Sandy(val){
    var value = val;
     
    this.getValue = function(){
        return value;
    };
     
    this.setValue = function(val){
        value = val;
    };
}
 
//usage
 
var sandy = new Sandy("test");
sandy.value
// => undefined
sandy.setValue("test2")
sandy.getValue

 

  下面是JavaScript权威指南(中文第五版)中P152页使用闭包的一个例子.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function makeProperty(o, name, predicate) {
    var value; //This is property value;
 
    //The setter method simply returns the value
    o['get' + name] = function() { return value;};
 
    //The getter method stores the value or throws an exception if
    //the predicate rejects the value
    o['set' + name] = function(v) {
        if (predicate && !predicate(v) {
            throw 'set' + name + ': invalid value ' + v;
        } else {
            value = y;
        }
    }
}
 
//The following code demenstrates the makeProperty() method
var o = {}; // Here is an empty object
 
//Add property accessor methods getName and setName
//Ensure that only string values are allowed
makeProperty(o, 'Name', function(x) { return typeof x == 'string'; });
 
o.setName('Frank');   //Set the property value;
print(o.getName());   //Get the property value
o.setName(0);       //Try to set a value of the wrong type

 

  第二种方法是使用__defineSetter__与__defineGetter__来实现accessor,看下划线就知道它们并非标准,适用于Firefox 2.0+, Safari 3.0+, Google Chrome 1.0+ 和 Opera 9.5+ ,方法使用见MDN.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Sandy(val){
    var value = val,
    _watch = function(newVal) {
        console.log('val is Changed to : ' + newVal);
    }
 
    this.__defineGetter__("value", function(){
        return value;
    });
     
    this.__defineSetter__("value", function(val){
        value = val;
    _watch(val);
    });
}
 
var sandy = new Sandy("test");
sandy.value
// => test
sandy.value = "test2";
// => 'val is Changed to : test2'
sandy.value
// => "test2"

 

  除了__defineG/Setter__外, 你还可以使用'set'、'get'关键字在在原型对象上定义accessor,对于单个对象同样适用, 适用于Firefox 2.0+, Safari 3.0+, Google Chrome 1.0+ 和 Opera 9.5+.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function Sandy(val){
    this.value = val;
}
 
Sandy.prototype = {
    get value(){
        return this._value;
    },
    set value(val){
        this._value = val;
    }
};
 
//Or
 
var sandy = {
    '_value' : 'sandy',
    get value() {
      return this._value;
    },
    set value(val) {
      this._value = val;
    }
}

 

 

  最后一种方法,用到了Object的静态方法defineProperty,作用于单个对象,该方法应该属于ES5的范畴了,目前似乎只有Chrome 支持这种方法,其实Ie8也支持,但操作对象仅限于Dom节点(Dom node),见IEBlog,该方法的使用见MDN.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var sandy = {}, rValue;
 
Object.defineProperty(sandy, 'value' ,
    {
        'set' : function(val) {
            rValue = val;
        },
        'get' : function() {
            return rValue;
        },
        'enumerable' : true
        'configurable' : true
    }
)
 
//Ie8+
 
Object.defineProperty(document.body, "description", {
    get : function () {
        return this.desc;
    },
    set : function (val) {
        this.desc = val;
    }
});
 
document.body.description = "Content container";
 
// document.body.description will now return "Content container"

 

 

‘enumerable','configuralbe' 属于ES5规范中的Property Attributes(属性特性),在这里就不做讨论了,有兴趣的Google或者直接去看ES5的文档. ^ ^