JavaScript对象是否像Ruby一样“开放”?

3
在Ruby中,我可以使用相同的语法来添加和修改任何类、对象或方法的功能,因为Ruby具有“开放的类”。JavaScript是否也是这样呢?
例如...
在我的例子中,我想改变Google Apps Script处理URL对象的方式,这样每次我评估一个URL对象时,URL对象本身都会确保它以协议://(默认为http://)开头。

在现代JavaScript运行时中,可以保护对象属性不被修改。 - Pointy
一个例子是 Object.defineProperty - simonzack
4个回答

3

是的,您可以自由修改对象。您可以修改特定对象 Object.overridenProperty = ...,或通过其 prototype 属性修改从给定 class 派生的所有对象 Object.prototype.inheritedMethod = ...

请注意,重新定义方法可能很棘手,因为新定义不会与原始定义共享相同的作用域:

var BaseClass;

(function(){
    var defaults = { ... };

    BaseClass = function(){
        this.someValue = defaults.someValue;
    };
}());

有时候,类定义可能会存在于闭包内部,你无法实际地覆盖一个方法或属性,因为它是即时生成的。在这种情况下,您需要单独在每个您感兴趣的对象上覆盖该属性:

(function(){
    var defaults = { ... },
    BaseObject = (function(){
        var obj = function(){
            this.someValue = defaults.someValue;
        };

        return obj;
    }());
}());

2

可以。

需要注意的是,在Ruby中,“类”的定义方式与其他语言有很大不同。但你可以实现相同的效果。

以下是Ruby代码示例:

#ruby
class Foo
  # no methods yet
end

foo = Foo.new

class Foo
  def bar
    'bar'
  end
end

foo.bar #=> 'bar'

这个JavaScript实现等价于:

// js
var Foo = function() {};

var foo = new Foo();

Foo.prototype.bar = function() {
  return 'bar';
};

foo.bar(); // 'bar'

你甚至可以轻松地覆盖所有内容,如下所示:

你甚至可以轻松地覆盖所有内容:

var oldBar = Foo.prototype.bar;
Foo.prototype.bar = function() {
  return "Called oldBar and got: "+ oldBar.call(this);
};

foo.bar(); // "Called oldBar and got: bar"

1
请看具有getter和setter的这个类:
function User(){
this._name = "";
}
User.prototype.setName = function(name){this._name = name;}
User.prototype.getName = function(){return this._name;}
user = new User();
user.setName("somename");
alert(user.getName(););

{{链接1:JSfiddle示例}}


1

您在问题中特别提到了Google Apps Script。由于GAS是JavaScript的变体,因此对象定义和扩展的“常规方法”适用于其他答案中所述。

然而,有一个非常恼人的例外:您无法扩展Google类的原型。您可以在问题跟踪器上找到有关此问题的评论,问题708。它被标记为“不会修复”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接