30686


JavaScriptではオブジェクトにsetterを用意すれば代入の操作で複雑な処理が行えますが、

[code]

    var o = {
        set current(a) {
            console.log(a)
        },
    };
    o.current = 1; //console => 1
    
[/code]

同じように代入で処理をしたいのですが、プロパティに変数をつけたようにはできないでしょうか。厳密にsyntaxが以下のようである必要はありませんが、`...=...`の形にはしたいです。

[code]

    o.current(2) = 1; //2*1, console => 2
    o.current(4) = 1; //4*1, console => 4
    o.current(4) = 2; //4*2, console => 8
    
[/code]

変数は文字列ではない予定なので`Proxy`の`handler.get(target, propertyName,
receiver)`では少し試したのではできなさそうでしたが、よくはわかってないです。


CC BY-SA 3.0
2016-11-26T08:25:42.743
30684
2016-11-27T14:51:37.333
3974
question
javascript
JavaScriptで変数付きsetterのようなことはできますか？


`()`を付けると関数の呼び出し形式になり、左辺値には使えなくなります。  
`[]`で代用するとして、`Proxy` を使うのであれば、`get` ではなく `set` になると思います。

[code]

    const current_hdl = {
     set: (_, name, val) => {
      console.log(Number(name) * val);
      return true;
     }
    };
    const current = new Proxy({}, current_hdl);
    
    let o = { current: current }
    o.current[2] = 1; //2*1, console => 2
    o.current[4] = 1; //4*1, console => 4
    o.current[4] = 2; //4*2, console => 8
[/code]

追記: 「変数は文字列ではない」というのが、文字列（プロパティ名）として表現不可能、という意味であれば上記は使えないかもしれませんね。

* * *

数字を複数渡すとのことなので、やはり packet0 さんの回答のように関数にするしかないですね。  
少し一般化し、

[code]

    o.method(right, ...lefts);
    
[/code]

への構文糖として

[code]

    o.param(...lefts).method = right;
    // あるいは
    o.method = right;
    
[/code]

を用意する例です。

[code]

    let o = {
     param: (...lefts) => {
      function setter(target, name, val){
       target[name](val, ...lefts);
       return true;
      }
      return new Proxy(o, {set: setter});
     },
     get current(){
      return (right, ...lefts) => {
       lefts.push(right);
       console.log(lefts);
      }
     },
     set current(right){
      o.current(right);
     },
    };
    
    o.param(1, 2).current = 10; // console => [ 1, 2, 10 ]
    o.current(10, 1, 2); // 上と同じ
    
    o.param().current = 10; // console => [ 10 ]
    o.current = 10; // 上と同じ
    o.current(10); // 上と同じ
[/code]


CC BY-SA 3.0
2016-11-26T09:41:26.280
30686
2016-11-27T10:00:03.933
2016-11-27T10:00:03.933
3054
3054
30684
answer


なんか思いついたので

`()`がそのままだと関数になり[左辺値には使えない](https://ja.stackoverflow.com/a/30686/3974)ので、1度オブジェクトを返し、そのsetterで元のオブジェクトを変えればいいかなと。関数の他にsetterがあるので`.v`のような余分な文がつきますが...

[code]

    var o = {
      test: 0,
      current: function(a) {
        return {
          set v(x) {
            test = a * x;
            console.log(test);
          }
        };
      },
      current2: function() {
        var _sum = Array.from(arguments).reduce(
          (prev, curr) => {
            return prev + curr
          }, 0);
        return {
          set v(x) {
            test = _sum * x;
            console.log(test);
          }
        };
      },
    };
    
    o.current(2).v = 1; //2*1, console => 2
    o.current(4).v = 1; //4*1, console => 4
    o.current(4).v = 2; //4*2, console => 8
    o.current2(1, 1).v = 1; //(1+1)*1, console => 2
    o.current2(1, 3).v = 1; //(1+3)*1, console => 4
    o.current2(1, 3).v = 2; //(1+3)*2, console => 8
    o.current2(...Array(11).keys()).v = 2; //(0+1+2+..+10)*2, console => 110
[/code]


CC BY-SA 3.0
2016-11-27T08:14:40.203
30718
2016-11-27T08:14:40.203
2017-04-13T12:52:38.920
-1
3974
30684
answer


再帰的にProxyを返して、ジャグ配列みたいな感じにすることはできますね。まあメソッドの引数として渡した方が文字列に変換されることもなくて、実用的な気はしますが。

[code]

    function create_indexer(callback) {
      const handler = {
        get: (target, name) =>
          new Proxy([...target, name], handler),
        set: (target, name, val) =>
          callback.call(null, [...target, name], val)
      };
      return new Proxy([], handler);
    }
    
    let o = {
      test: 0,
      current: create_indexer((args, val) => {
        test = args.reduce((prev, cur) => prev + Number(cur), 0) * val;
        console.log(test);
      })
    };
    
    o.current[2] = 1; //2*1, console => 2
    o.current[4] = 1; //4*1, console => 4
    o.current[4] = 2; //4*2, console => 8
    o.current[1][1] = 1; //(1+1)*1, console => 2
    o.current[1][3] = 1; //(1+3)*1, console => 4
    o.current[1][3] = 2; //(1+3)*2, console => 8
[/code]


CC BY-SA 3.0
2016-11-27T10:12:45.817
30722
2016-11-27T14:51:37.333
2016-11-27T14:51:37.333
3974
8000
30684
answer