【问题标题】:How to make a property/method invokable or not?如何使属性/方法可调用或不可调用?
【发布时间】:2017-05-11 18:26:39
【问题描述】:

我想实现这个功能:

  1. 我有一个对象var obj = {};
  2. 我在那个 obj 上有三个属性,obj.zero & obj.one& obj.binaryString

    • obj.zero & obj.one 是方法,而 obj.binaryString 是字符串

当我链接属性时,我希望它们将各自的数字添加到binaryString。比如:

obj.one.zero.zero.one => 使obj.binaryString = 1001

obj.one.zero.one.one.zero => 使obj.binaryString = 10110

我已经通过这个实现了上述功能:

function Binary () {
    var obj = { binaryString: '' };

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one  // => obj.binaryString becomes '1001'

现在我想注销已完成的binaryString、plus 和additionalString,我已使用以下代码完成:

// placed inside Binary constructor function
Object.defineProperty(obj, 'log', {
    get: function() {
        return function(additionalString) {
            console.log(obj.binaryString + additionalString);
        };
    }
});

所以用这个当前的代码我可以做到这一点:

binary.one.zero.one.zero.one.log(' is the answer');
// logs out `10101 is the answer`

我想要做的是摆脱 log 并使 onezero 方法可调用或不可调用,以便我可以实现此功能:

binary.one.one.zero.one(' is the result')
// => logs out `1101 is the result`

我该怎么做?

我相信它的功能类似于Chalk 的工作方式:

chalk.blue.bold('Hello world!');
// `blue` is not invoked here but it adds the color blue to the style

chalk.blue('Hello world!');
// `blue` IS invoked here.  It adds blue to the style and returns the stylized string

【问题讨论】:

标签: javascript defineproperty


【解决方案1】:

只需将 obj 设为函数,然后打印您想要的任何内容。

function Binary () {
    var obj = function(msg){ console.log(msg+this.binaryString ) };
    obj.binaryString = ''

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one.zero(" is the result ")

【讨论】:

    【解决方案2】:

    我想指出,您正在做的是一个非常糟糕/危险的想法:滥用读取属性来改变对象本身是自找麻烦。您现在可能看不到它,但它会以难以发现的错误和复杂模式的形式导致痛苦和心痛。

    可以做的是,不是那么危险,而是在每次调用#one#zero 时返回Binary 的新实例,而不是改变对象本身。例如:

    function Binary(s) {
      this.binaryString = s || ''
    }
    Object.defineProperty(Binary.prototype, 'zero', {
      get: function() {
        return new Binary(this.binaryString + '0')
    }})
    Object.defineProperty(Binary.prototype, 'one', {
      get: function() {
        return new Binary(this.binaryString + '1')
    }})
    

    这是 Chalk 采用的方法,并且会更安全且不易出错。

    更新

    在考虑了您的问题并看到您的问题之后,我认为最好的方法是根本不使用类。您可以使用纯基于函数的方法来解决此问题。它是不可变的,它是安全的,而且我相信它不那么令人困惑。这是在 ES5 中:

    function bin(str) {
      if(!str) str = ''
      function f(msg) { return str + ' ' + msg }
      return Object.defineProperties(f, {
        zero: {
          get: function() {
            return bin(str + '0')
          },
        },
        one: {
          get: function() {
            return bin(str + '1')
          },
        },
      })
    }
    

    如果你可以使用 ES6(又名 ES2015),你可以让它更紧凑:

    function bin(str = '') {
      return Object.defineProperties(msg => `${str} ${msg}`, {
        zero: { get() { return bin(str + '0') } },
        one: { get() { return bin(str + '1') } },
      })
    }
    

    你会这样使用它:

    bin().one.zero.one.zero('is the answer') // '1010 is the answer'
    

    【讨论】:

    • 感谢您的建议。你介意告诉我我的代码会如何导致难以发现的错误和复杂的模式吗?对我来说,现在理解和调试似乎很简单。这样做只是一种不好的做法吗?这个功能真的会导致更多的错误吗?谢谢。另外,为什么要将属性放在prototype 而不是对象本身上?
    • Read 属性——顾名思义——用于读取内容,至少按照惯例(这是一个良好且合理的惯例)。很容易忘记看起来像读取属性的东西实际上正在改变对象。此外,JavaScript 代码充斥着自动内省。例如,说for(p in someBinaryNumber) console.log(someBinaryNumber[p]) 会为您的号码添加 1 和 0!更糟糕的是,您无法预测订单!越来越多的人觉得可变性总体上来说很糟糕。
    • 至于将属性放在prototype 上,这是一种更“OOP”的方式,尽管这是一个非常奇怪的混合示例,它是其他六个中的六个。 OOP 在 JS 中通常很奇怪,很多人认为无论如何你都不应该这样做(耸耸肩)。当然,这些天我不会写很多被认为是 OOP 的东西。
    • 非常感谢您的反馈!谢谢!
    • 使用您列出的格式,我将如何实现能够像上面答案中概述的 Dzair 那样调用属性 (binary.one.zero.one(" is the result") // => 10 is the result) 的功能?
    猜你喜欢
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 2012-01-27
    相关资源
    最近更新 更多