在类中,什么时候应使用属性,什么时候应使用方法?

在类的构建过程中,对于一个特定值的访问既可以使用属性也可以使用方法

例子:

//实现

//Point类,表示平面上的一个点
function Point(x,y){
    this.x = x;
    this.y = y;
    
    //距原点的距离,使用属性来实现
    Object.defineProperty(this,"distance",{
        get: function(){
            return Math.sqrt(this.x*this.x + this.y*this.y);
        }
    });
}

//距原点的距离,使用方法来实现
Point.prototype.getDistance = function(){
    return Math.sqrt(this.x*this.x + this.y*this.y);
}

//访问
var a = new Point(3,5);

//使用属性访问
Console.log(a.distance);

//使用方法访问
Console.log(a.getDistance());

问题:

  • 在哪些情况下应使用属性,在哪些情况下应使用方法?

  • 使用属性和使用方法各有哪些优缺点

  • 有哪些介绍相关内容的文章或书籍?

阅读 3.1k
2 个回答

你这个问题其中在 Javaer 中已经讨论了很久了。Java Bean 为什么一定要用 getter 和 setter,讨论的就是这个问题。

我这里只是简单的说一下,你可以自己去百度相关的资料。

对于 Java 来说,就是属性和方法,通过 getXxxx() 和 setXxxx() 这两种方法来获取或设置属性的值。

不过对于 js 来说,可以通过 Object.defineProperty 来定义属性,这个属性和原来直接 this.xxxx 的这个属性应该有所区别,所以通常会把 this.xxxxx 这个称为字段 (Field),而把 Object.defineProperty 定义的那个称为属性。由于 JS 有属性,所以不需要(但可以)申明 getter 和 setter 方法,反正作用是一样的。

现在从 JS 的角度来说,所有会提到“字段”和“属性”。

相比字段,属性有几个作用,其一就是保护字段。比如我定义了一个字段,这个字段的值只能在内部修改,而不能被外部调用者修改,那只需要定义对应的只读属性,也就是只有 getter 没有 setter 的属性即可。当然这在 JS 里还有点困难,因为 JS 没有实现私有成员,关于 JS 成员私有化的问题,可以参考 ES5 中模拟 ES6 的 Symbol 实现私有成员。由于字段被私有化,对应的属性又只提供了 getter,所以外部调用只能通过属性的 getter 获取字段值,而不能修改它,达到保护的目的。

第二个作用是重载处理,这在 JS 里体现也不明显,因为 ES5 的继承实现确实有点麻烦。不过 ES6 在语法上已经支持了。具体点说,就是父类定义了一个属性,子类重载这个属性,改变了父类存取属性默认行为。比如说,父类的 name 属性对值没有限制,但是由于某种原因,需要父类类似的功能,但 name 不能为空,那可以从该父类继承,重载其 name 属性,在赋空值的自动修正,或报错。

class A {
    get name() {
        return this._name;
    }

    set name(name) {
        this._name = name;
    }
}

class B extends A {
    get name() {
        return super.name;
    }

    set name(name) {
        super.name = name || "Anonymous";
    }
}

const b = new B();
b.name = "";
console.log(b.name);

总的来说,字段一般作为内部保存数据用,不对外。如果需要对外,则通过属性来实现。这种设计模式对扩展很有好处。JavaScript 在这方面应用不是很多,如果你想参考,可以看看 C# 的属性和 Java 的 getter/setter 方法。

所谓的属性和方法只是叫法上的不同。方法可以是属性,属性也可以是方法。如下:

function Point(x,y){
    this.x = x;
    this.y = y;
    this.z = function(){console.log(this.x);};
    
    //距原点的距离,使用属性来实现
    Object.defineProperty(this,"distance",{
        get: function(){
            return Math.sqrt(this.x*this.x + this.y*this.y);
        }
    });
}

//距原点的距离,使用方法来实现
Point.prototype.getDistance = function(){
    return Math.sqrt(this.x*this.x + this.y*this.y);
}

//访问
var p = new Point(3,5);
'x' in p //true
'getDistance' in p //true
p.hasOwnProperty('getDistance'); //false这是这个方法的特性,不遍历原型链
p.hasOwnProperty('distance'); //true
p.hasOwnProperty('y');  //true
p.hasOwnProperty('z');  //true

只不过按前辈的经验来分,属性一般是一个值,可以获取,可以改变。而方法一般是一段可以执行的代码,可以操作属性值。外部调用时属性直接使用,方法需要(),予以执行。

推荐问题
宣传栏