大綱

apply()call()用途相同,差別在於,call() 必須列出每一個參數,而apply() 是利用陣列。

例如我有一個函數 myfunc(arg1, arg2, arg3)。則

看看甚麼是apply


<pre id="log"></pre>
<script>
    var x="張三";
    var y="李四"
    function helloX(msg) {
        document.querySelector("#log").innerText = 
          document.querySelector("#log").innerText + "\r\n" +
             "hello"+ this + " " + msg;
    }
    helloX.apply(x, ["你好"]);// 傳到hellox裡的msg,必須用陣列,例如["你好"]
    helloX.apply(y, ["你好"]);// 傳到hellox裡的msg,必須用陣列,例如["你好"]
</script>

甚麼時候用? 上面的例子,看起來就好像x,y都有一個函數heloX

也就是說,可以通用於不同的物件,看起來就好像是某個物件的behavior。

this是動態綁定

function myfunc(name){
    this.name="empty"; //🏷
}

arguments 的用法

function helloX(msg){
    if (arguments.length) >1 {
        console.log("hello ", +this.name + "  " + msg )
    }
}


<script>
        function myfunc(name) {
            this.name = name; 
        }

        myfunc("lee4");//<!--html_preserve--><span  data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="執行完以後,&lt;code&gt;window.name=&amp;quot;lee4&amp;quot;&lt;/code&gt;">🏷</span><!--/html_preserve-->
        myfunc("chung3"); //<!--html_preserve--><span  data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="執行完以後,&lt;code&gt;window.name=&amp;quot;chung3&amp;quot;&lt;/code&gt;">🏷</span><!--/html_preserve-->
        console.log(window.name) //💡在主控台中,會顯示chung3
</script>
執行的結果是在window下會有一個欄位叫做name

看看甚麼是call


<pre id="log"></pre>
<script>
    var x="張三";
    var y="李四"
    function helloX(msg) {
        document.querySelector("#log").innerText = 
          document.querySelector("#log").innerText + "\r\n" +
             "hello"+ this + " " + msg;
    }
    helloX.call(x, "你好");// 傳到hellox裡的msg,不是用陣列例如❌["你好"],而是✔"你好"
    helloX.call(y, "你好");// 傳到hellox裡的msg,不是用陣列例如❌["你好"],而是✔"你好"
</script>

另一個範例

[JS] 06 prototype.pptx

如果Array 沒有提供求最大,最小的函數,則必須自己寫一個函數,但是我們知道Math library有提供函數:Math.max(),Math.min():

解釋下面的用法: 在Array的prototype上加入函數max(),min() 。 第一個參數不用,因為Math.max()不是我們寫的函數,是別人寫的,傳進去說不好會有問題。第2個才是我們要傳進的參數,因為是apply(),所以第2個參數也剛好是Array, 因此用this。

    var p = [35, 2, 65, 7, 8, 9, 12, 121, 33, 99];
    Array.prototype.max = function() {
        return Math.max.apply(null, this);// 🏷
    };

    Array.prototype.min = function() {
        return Math.min.apply(null, this);
    };

    var p1 = new Array(35, 2, 65, 7, 8, 9, 12, 121, 33, 99);

    //alert("Max value is: "+p.max()+"\nMin value is: "+ p.min());
    alert("p1's max is " + p1.max());
❓ 為甚麼不是寫成Math.min.apply(null, `[this]`);而是寫成Math.min.apply(null, `this`) ?
因為`p = [35, 2, 65, 7, 8, 9, 12, 121, 33, 99];`本身就是陣列。
上面程式碼的執行

<pre id="log"> </pre>
<script>
    var p = [35, 2, 65, 7, 8, 9, 12, 121, 33, 99];
    Array.prototype.max = function() {
        return Math.max.apply(null, this); 
    };

    Array.prototype.min = function() {
        return Math.min.apply(null, this);
    };

    var p1 = new Array(35, 2, 65, 7, 8, 9, 12, 121, 33, 99);

    document.querySelector("#log").innerText = "Max value is: "+p.max()+"\nMin value is: "+ p.min();
    
</script>    
那為甚麼不寫成

    var p = [35, 2, 65, 7, 8, 9, 12, 121, 33, 99];
    Array.prototype.max = function() {
        return Math.max( this);
    };
Array.prototype.min = function() {
    return Math.min( this);
};

var p1 = new Array(35, 2, 65, 7, 8, 9, 12, 121, 33, 99);

//alert("Max value is: "+p.max()+"\nMin value is: "+ p.min());
alert("p1's max is " + p1.max());

Math.max([2,3,4])
NaN
Math.max(2,3,4)
4

😛參考操作

[js]06 prototype)

【測試】利用參數的stack,允許thisp的傳入(不是關鍵字this)

this的傳入,除了利用call,apply之外,還可以利用javascript對參數處理的彈性:

    <script>
        function showArg(arg1) {
            console.log(this);
            console.log(arg1);
            console.log(arguments[0]);
            console.log(arguments[1]);
            thisp=arguments[1]; 
        }
        showArg("me", "pine");
        showArg.call("apple", "me", "pine");
    </script>

也就是說,雖然showArg的參數只有1個,但是仍然可以再呼叫的時候傳入多於一個的參數,此時,showArg的body可以利用argument[1]來存取。

【例】上述測試的應用

every 是一個Array內建方法,調用使用者提供的函數(這裡isBigEnough),依照說明書,isBigEnough應該有3個參數:元素值,元素索引,整個陣列。

<html>
   <head>
      <title>JavaScript Array every Method</title>
   </head>
   
   <body>
   
      <script type="text/javascript">
 
            Array.prototype.every = function(fun /*, thisp*/)
            {
               var len = this.length;
               if (typeof fun != "function")
               throw new TypeError();
               
               var thisp = arguments[1];
               for (var i = 0; i < len; i++)
               {
                  if (i in this && !fun.call(thisp, this[i], i, this)) //<1>
                  return false;
               }
               return true;
            };
  
         function isBigEnough(element, index, array) {
		    console.log(this);
            return (element >= 10);
         }
         
         var passed = [12, 5, 8, 130, 44].every(isBigEnough,"arg2"); //<2>
         document.write("First Test Value : " + passed ); 
         
         passed = [12, 54, 18, 130, 44].every(isBigEnough,"arg2");
         document.write("Second Test Value : " + passed ); 
      </script>
      
   </body>
</html>

註解

  1. thisp 會指向[arg2]{.underline}

arg2 被當成this 傳入;[isBitEnough]{.underline}(只有三個參數,不包括arg2)

範例:陣列合併

var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
var b = [ "foo", "bar", "baz", "bam", "bun", "fun" ];
// `b` onto `a`:
a.push.apply( a, b );
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

// or `a` into `b`:
b.unshift.apply( b, a );
b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]


jquery 跳過😛

【範例】apply

<script type='text/javascript'>
$(function() {
function btnClick() {
    alert("Button[" + this.value + "] clicked!");
}
$("#a").click(btnClick);
var virtualButton = { value: "V" };
btnClick.apply(virtualButton);
});
</script>
</head><body>
<input type="button" value="A" id="a" />
</body>

btnClick 是一個沒有參數的函數(function)。一般的函數呼叫方法是 btnClick() 就可以了。但是,範例中的btnClick() 的設計目的是配合其他物件,(因為函數有"this" ),因此可以配合call或apply 方法。以apply 方法來說,btnClick.apply(virtualButton) 也是呼叫btnClick (),但是透過apply機制,這裡的virtualButton 被當成this的參數,傳入btnClick() ,被認為是"this"。因此,this.value 指的是 變數virtualButton 欄位value 的值 "V"。

不用new

   function myObject(name) {
            this.name = name;
            return this; //沒有這行會出錯
        }

        function helloX(msg) {
            console.log(arguments.length);
            console.log("hello " + this.name + "  " + msg)

        }
        var x1= myObject("lee4"); 
        var x2=  myObject("chung3");
        helloX.apply(x1,["ko"]);