大綱
apply()
與call()
用途相同,差別在於,call()
必須列出每一個參數,而apply()
是利用陣列。
例如我有一個函數 myfunc(arg1, arg2, arg3)
。則
apply()
的用法是myfunc.apply(thisArg,[arg1,arg2,arg3])
,第一個傳入的參數(thisArg)在就是函數中的this,而第二個是參數陣列。call(thisArg,arg1,arg2,arg3)
- 兩者之間的關係應該是:
call(thisArg,arg1,arg2,arg3)
<==>apply(thisArg,[arg1,arg2,arg3])
- 兩個函數的差別:
- 參數
apply
的參數,最多兩個,第二個是陣列。apply(this, [...])
call
的參數,有多個。call(this, param1, param2, param3, param4...)
- 參數
看看甚麼是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
- x.helloX("你好")
- y.helloX("你好")
也就是說,可以通用於不同的物件,看起來就好像是某個物件的behavior。
this是動態綁定
function myfunc(name){
this.name="empty"; //🏷
}
arguments 的用法
function helloX(msg){
if (arguments.length) >1 {
console.log("hello ", +this.name + " " + msg )
}
}
⛳ 執行的結果是在window下會有一個欄位叫做<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="執行完以後,<code>window.name=&quot;lee4&quot;</code>">🏷</span><!--/html_preserve--> myfunc("chung3"); //<!--html_preserve--><span data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="執行完以後,<code>window.name=&quot;chung3&quot;</code>">🏷</span><!--/html_preserve--> console.log(window.name) //💡在主控台中,會顯示chung3 </script>
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>
另一個範例
如果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());
⛳
<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
😛參考操作
【測試】利用參數的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>
範例:陣列合併
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"]);