【问题标题】:Shortest way to set value to variable in Knockout在 Knockout 中为变量设置值的最短方法
【发布时间】:2017-07-17 23:13:31
【问题描述】:

在淘汰赛中,我有可观察的变量location。它的类型为LocationEdit。这个 viewModel 有 observable 而不是 fields。

我收集了字段名称:fields。对于每个字段我想重置location的值

fields.forEach(field => {
       if (this.uniqueField(locs, field)) {
           if (ko.isObservable(this.location()[field])) {
               this.location()[field](locs[0][field]);
           } else {
               this.location()[field] = locs[0][field];
           }
       }
});

为了使这段代码更简单(删除 if 子句),我可以在一行中以某种方式将值设置为 this.location()[field] 吗?

【问题讨论】:

    标签: javascript knockout.js observable


    【解决方案1】:

    您可以使用条件运算符 (... ? ... : ... ;),尽管它没有太大变化:

    fields.forEach(field => {
           if (this.uniqueField(locs, field)) {
               ko.isObservable(this.location()[field]) ? this.location()[field](locs[0][field]) : this.location()[field] = locs[0][field];
           }
    });
    

    或者你可以写一个函数:

    function upd(arr, index, val) {
        ko.isObservable(arr[index]) ? arr[index](val) : arr[index] = val;
    }
    

    用法:

    fields.forEach(field => {
           if (this.uniqueField(locs, field)) {
               upd(this.location(), field, locs[0][field]);
           }
    });
    

    demo

    您甚至可以将此函数添加到ko

    if(typeof ko.updatePotentialObservable == 'undefined')
        ko.updatePotentialObservable = function (arr[index], val) {
            ko.isObservable(obj) ? arr[index](val) : arr[index]= val;
        }
    

    用法:

    fields.forEach(field => {
           if (this.uniqueField(locs, field)) {
               ko.updatePotentialObservable(this.location(), field, locs[0][field]);
           }
    });
    

    查看其他demo

    【讨论】:

    • 是的,当然,但也想找到其他解决方案
    • @demo 你可以创建你的函数,否则在其他情况下可能会派上用场(见答案更新)
    • 快速说明:您的 upd 方法不起作用,因为它无法访问原始对象。必须是function upd(obj, key, val) { ko.isObservable(obj[key]) ? obj[key](val) : obj[key] = val; }
    【解决方案2】:

    说实话,我认为Gôtô 的回答绝对是你最好的选择。基本上,您会想要创建一个类似于ko.unwrap 的实用函数,但要设置一个值。

    但既然你说“也想找到另一个解决方案”,那么这里有一个不同的效用函数。我认为您的代码中最令人困惑的部分是对locs[0][field]this.location()[field] 的返回调用。我想要带有这个签名的东西:

    reset(source, target, keys);
    

    因此,在您的代码中,您可以这样做:

    reset(
      this.location(), 
      locs[0], 
      fields.filter(f => this.uniqueField(locs, f))
    );
    

    现在,写这个方法,我得到了这个:

    const mergePropsObs = (function() {
      // Return a method for setting a specific property in object
      const getSetter = obj => prop => ko.isObservable(obj[prop])
        ? obj[prop]
        : val => obj[prop] = val;
        
      // Return unique keys for two objects
      // (I went with a quick oneliner; there are many ways to do this)
      const allKeys = (obj1, obj2) => 
        Object.keys(Object.assign({}, obj1, obj2));
    
      return (base, ext, onlyProps) => {
        const props = onlyProps || allKeys(base, ext);
        const values = props.map(p => ko.unwrap(ext[p]));
        
        props
          .map(getSetter(base))
          .forEach((setter, i) => setter(values[i]));
      };
    }());
    
    var base = { a: 1, b: ko.observable(2), c: 5 };
    
    mergePropsObs(
      base, 
      { a: 2, b: 3 },
      ["a", "b"]);
      
    console.log(base.a);
    console.log(base.b());
    console.log(base.c);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

    此实用方法可以与上述签名一起使用。当您不提供字段名称数组时,它还具有备用功能。

    【讨论】:

      猜你喜欢
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-06
      • 1970-01-01
      相关资源
      最近更新 更多