【问题标题】:JavaScript Prototype Functions Using Privileged Getter/Setter Functions?使用特权 Getter/Setter 函数的 JavaScript 原型函数?
【发布时间】:2014-01-04 10:16:35
【问题描述】:

三部分问题:

  1. 添加第二层抽象并使用原型 getter/setter 函数调用特权构造函数 getter/setter 函数有什么价值?请参阅下面的ns.Wheel.prototype.getWeight2()ns.Wheel.prototype.setWeight2()

  2. swiss.getWeight() 的调用会调用构造函数中的this.getWeight() 方法。有什么方法可以将原型链上移一级以调用ns.Wheel.prototype.getWeight()

  3. 将原型 getter/setter 函数“隐藏”在构造函数 getter/setter 之后的任何值?例如,ns.Wheel.prototype.getWeight() 在构造函数中“隐藏”在 this.getWeight() 方法后面。

还要注意原型 getter/setter 如何为克添加单位;即“g”单位。例如,this.getWeight 返回 1000,而 ns.Wheel.prototype.getWeight 返回 1000g。

本例中使用了瑞士奶酪轮。

(function(ns) {
    ns.Wheel = function() {
        var _weight = 1000; // weight of cheese wheel. Private variable.
        this.getWeight = function() { return _weight } // privileged weight getter
        this.setWeight = function(weight) { return _weight = weight } // privileged weight setter
    }
    ns.Wheel.prototype.getWeight = function() { return this.getWeight()+'g' }
    ns.Wheel.prototype.setWeight = function(weight) { return this.setWeight(weight)+'g' }
    ns.Wheel.prototype.getWeight2 = function() { return this.getWeight()+'g' }
    ns.Wheel.prototype.setWeight2 = function(weight) { return this.setWeight(weight)+'g' }
})(window.cheese = window.cheese || {});  // immediate function namespacing technique

var swiss = new cheese.Wheel();
console.log(swiss.getWeight()); //-> 1000. Invokes constructor method
console.log(swiss.setWeight(2000)); //-> 2000. Invokes constructor method
console.log(swiss._weight); //-> undefined. Private variable!!!
console.log(swiss.getWeight2()); //-> 2000g. Invokes prototype method.
console.log(swiss.setWeight2(9000)); //->9000g. Invokes prototype method.

【问题讨论】:

  • 我建议您使用 Class.create$super() 看看 prototype.js 及其非常好的 inheritance behavour。朋友们,现在因为我复活了这样一个邪恶的老图书馆而将我用石头打死! ;)
  • 我建议不要担心在 JS 中将变量设为“私有”。为了拥有“私有”变量,您必须将使用它们的方法移动到构造函数中,这意味着您在构造函数中拥有每个非“静态”方法的副本。这是对内存的浪费。一个常见的约定是用下划线命名“私有”变量,然后永远不要在创建它们的上下文之外使用带有下划线前缀的变量。如果您真的想要私有,请考虑使用 TypeScript,它可以执行我的建议,但会在编译时为您检查。
  • 我同意 cmets 不使用闭包来拥有“私有”成员和特权方法,但如果你真的必须这样做,那么这种模式可能有用:stackoverflow.com/a/19879651/1641941 它不会阻止您无法完全访问私有值,但如果您有很多“私有”值,它将减少名为 _somePrivate 的对象上的成员数量

标签: javascript constructor prototype getter-setter


【解决方案1】:
  1. 添加第二层抽象并使用原型 getter/setter 函数调用特权构造函数 getter/setter 函数有什么价值?

    一般来说,我会说不。尽可能在原型上存在方法会更节省内存,因为在实例构造期间设置的方法将存在于每个实例上,而原型方法只需要定义一次。

  2. 将原型链向上移动一级以调用 ns.Wheel.prototype.getWeight() 的任何方式

    如果您希望某些方法能够“私有”访问在构造函数内部定义的变量,那么这些函数也必须在构造函数内部定义。函数范围在声明时设置。因此,在构造函数之外定义的函数(例如原型方法)无法访问构造函数范围的变量。

    由于 JavaScript 函数是一等对象,您可以使用 callapply 调用原型方法:ns.Wheel.prototype.setWeight.call(this, 1000)(其中第一个参数设置被调用函数的 this 值,以及其他参数是实际的函数参数)。

  3. “隐藏”原型 getter/setter 函数“隐藏”在构造函数 getter/setter 之后的任何价值?

    在您的情况下,永远不会使用 ns.Wheel.prototype.getWeight (及其相应的设置器)。当getWeight2调用this.getWeight()时,即解析为实例级函数,无需查找原型方法的原型链。

    我能看到的唯一值可能是您有条件地用实例方法遮蔽了一些原型方法,而在其他情况下让原型方法显示出来。但是,如果您希望该原型方法能够访问构造函数范围的变量,那么您很不走运,如第 2 点所述。例如:

    function Egg(color) {
        if(color == "invisible") {
            this.examine = function() { return "You can't see the egg at all! }
        } 
    }
    
    Egg.prototype.examine = function() { return "The egg is painted " + color; }
    

    这不是一个很好的例子(它更适用于像数字这样的简单值,而不是函数),但它是我能想到的唯一“有用”的原型阴影示例。

我强烈支持上面的第二条评论,它建议不要使用私有变量。正如我在第一点中所述,它们通过要求在每个实例上定义使用它们的方法来浪费内存。通过尝试模拟私有变量,您浪费了原型继承的力量。相反(如 cmets 中所述),将所有变量设为公开并使用前导下划线指定“私有”变量。

【讨论】:

  • 1.同意... 2. 这就是 this.getWeight()this.setWeight 是... 3. 这是我的问题 #2:我怎样才能“让原型方法显示通过?”谢谢回复:^)
  • @kmiklas 我误解了你的第 2 点;我进行了广泛的编辑。
【解决方案2】:

添加第二层抽象并使用原型 getter/setter 函数调用特权构造函数的任何值 getter/setter 函数?参见 ns.Wheel.prototype.getWeight2() 和 ns.Wheel.prototype.setWeight2() 下面。

为什么不呢?好吧,请记住调用函数很昂贵,所以如果只是在末尾添加'g',如果你想获得一些微秒,你可以考虑手动进行。

对 swiss.getWeight() 的调用会调用构造函数中的 this.getWeight() 方法。任何将原型链上移一级的方法 改为调用 ns.Wheel.prototype.getWeight()?

是的,您可以:

  • 使用不同的名称
  • 使用cheese.Wheel.prototype.getWeight.call(swiss)

“隐藏”原型 getter/setter 函数“隐藏”的任何值 构造函数获取器/设置器?例如,ns.Wheel.prototype.getWeight() 被“隐藏”在构造函数中 this.getWeight() 方法的后面。

视情况而定。在您的情况下,我会使用不同的名称来避免“隐藏”。

【讨论】:

  • 命名空间是“奶酪”,所以上面的第二个项目实际上是 cheese.Wheel.prototype.getWeight.call(swiss),但是很好!!! tyvm!
  • @kmiklas 正确,已修复。
猜你喜欢
  • 1970-01-01
  • 2020-08-16
  • 2018-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 2020-10-01
相关资源
最近更新 更多