iT邦幫忙

5

以陣列為參數傳入來產生物件

對JS不求甚解下,平常把function當class用,
但要用陣列當參數產生物件使用時,
才知道 function 本身可以用 apply 把陣列傳入當參數,
但要 new 出新的實體無法直接傳入陣列,
而需要間接的方式才實現。
function 的參數傳入陣列,用apply的方法可解決:

function call_me(x,y) {
  console.log(x);
  console.log(y);
};

call_me(1,2);
var arrary = [1,2];
call_me(array); // --> call_me(array,undefined)

call_me.apply(null,array);
call_me.apply(this,array);

但要產生物件,用apply來代入陣列的參數卻因型態不合而無法作用:

var create_me = function(x,y) {
  this.x = x;
  this.y = y;
}
  
var one = new create_me(1,2) // -> Object { x=1, y=2 }
var two = new.create_me.apply(array) // SyntaxError: syntax error

根據:
Use of .apply() with 'new' operator. Is this possible?
提供的解法,這樣就可以解決:

var build_me = function() {
  function F(args) {
    return create_me.apply(this, args);
  }
  F.prototype = create_me.prototype;
  
  return function(args) {
    return new F(args);
  }
}();

build_me(array) // -> Object { x=1, y=2 }

先搞清楚 function 與 new 出一個物件有何不同,
這篇文章:
JavaScript 函式與 new 運算子
區別了什麼是 function 與 new 的不同,
可以有簡單的概念。

解法裡有用到 prototype,
但一直搞不清楚什麼是 prototype?
參考了這篇 JavaScript 中的 prototype 物件是什麼?
是翻譯這篇 The prototype object of JavaScript
才搞清楚 JS 裡的 prototype 的用法,
有點像是 ruby 裡,把 class 加上新的 method,
然後產生的各 instance 也帶有新的 method;
但不同的是,ruby 產生的 instance,與之後再 class 再新增methods後,是沒關係的;
而 JS 產生新的 Function 的 instance後,若又再改其 Function 的 prototype,之前的instance也隨之變動。
(這地方有誤解嗎?)
add method to class

再看一下 JavaScript 的 prototype(上) 的例子說明,

var foo = {};
var bar = function() {};
typeof(foo); // -> "object"
typeof(bar); // -> "function"
new foo; // -> TypeError: foo is not a constructor
new bar; // -> Object { }
typeof(new bar); // -> "object"

回到原問題,要傳陣列為參數到function可用 apply,
但想要傳到所產生的 object 卻不能。

如果把解法裡的 F.prototype = create_me.prototype; 拿掉,
build_me(array) // -> F { x=1, y=2 }
結果不是 Object 而是 F。

測試一下 F.prototype // -> F { }
create_me.prototype // -> Object { }
當 F.prototype = create_me.prototype 之後
F.prototype // -> Object { }

觀念上有不對或不清楚的地方,
也請指點補充一下。


0
dojo3000
iT邦新手 4 級 ‧ 2012-12-03 12:15:58

有點不太懂大大的意思,如果要把一個陣列給一個建構函式當成參數,不是像下面這樣做就好了嗎?

<pre class="c" name="code">
var arr = [1,2,3];

var Sum = function(numbers){
   var _size = numbers.length;
   var _total = 0;

   for(var i=0;i<_size;i++){
       _total += numbers[i]   
   }

   this.total = _total;
}

var s = new Sum(arr);

s.total // 等於6
0
逮丸逮丸
iT邦大師 1 級 ‧ 2012-12-03 15:49:06

最簡單的方式解決一語道破,
我再仔細想一下,自己幹嘛繞那麼大一圈。

一定是哪裡有誤會,才會越想越複雜吧。

會不會是ruby和js的差異呢?(不熟ruby,所以也不清楚)

不過大大上面介紹那些資源都蠻好的。

0
fillano
iT邦超人 1 級 ‧ 2012-12-07 11:32:01

基本上new會把函數從他的context抽離,所以你用apply時,他其實是把apply當做constructor。

<pre class="c" name="code">
var a = {
  base: 1,
  init: function() {
    this.add = function(c) {
      return this.base+c;
    }
  }
};
var b = new a.init();
alert(b.add(3));//結果是NaN

改成這樣的話:

<pre class="c" name="code">
var a = {
  base: 1,
  init: function() {
    this.base = 2;
    this.add = function(c) {
      return this.base+c;
    }
  }
};
var b = new a.init();
alert(b.add(3));//結果是5...
fillano iT邦超人 1 級‧ 2012-12-07 11:35:49 檢舉

補充一下:

<pre class="c" name="code">
var a = {
  base: 1,
  init: function() {
    this.add = function(c) {
      return this.base+c;
    }
  }
};
a.init.prototype = a;
var b = new a.init();
alert(b.add(3));//結果是4...
0
gituest
iT邦新手 5 級 ‧ 2013-01-01 13:48:38

這個題目 跟我問的差不多吧

就是得不到你要的回傳結果
a=b ,b=c,a=c.
用數字跟字串來驗證 都很合乎道理
到了物件 這樣寫就不行

你找到的解決方法
是把指令參數 再變成 數據參數
把new 跟apply再變成 1,2 這樣來套到你要的物件
透過 擴充繼承的prototype方法改變 apply陣列變成數據參數

其實就我上次問到答案 對物件的了解
物件之間所有資訊的溝通 都是透過return

你這個 apply跟func 跟 [] 少了一個東西叫做return.
我寫了一個有return的
不知是不是也一樣呢?

0
gituest
iT邦新手 5 級 ‧ 2013-01-01 13:48:50

我的想法是 apply是用陣列資料去呼叫func處理出
你要的結果 在傳回來
所有處理好的東西 放在return後面就對了

哈哈 其實我也不是很清楚啦
<script>
var create_me = function(x,y) {
this.x = x;
this.y = y;
return({m:x,n:y});
// return {this.x:x,this.y:y} ;
return z ;
}
<script>
var create_me = function(x,y) {
this.x = x;
this.y = y;
return({m:x,n:y});

}
var arr = [1,2];
var one = new create_me(1,2); // -> Object { x=1, y=2 }
two=create_me.apply(arr);
alert(one);
alert(two);

for (x in one) document.write(x);
document.write("<p>one.m::>"+one.m);
document.write("<p>one.n::>"+one.n);
for (y in two) {
document.write("<br>"+y)};
document.write("<p>two.m::>"+two.m);
document.write("<p>two.n::>"+two.n);
</script>

0
gituest
iT邦新手 5 級 ‧ 2013-01-01 13:52:25

上面前面的<script>有重複部分珊掉就可以了

我要留言

立即登入留言