javascript之function的apply(), call()

接上文:
[url=http://lixh1986.iteye.com/blog/1960343][b]javascript之function的this[/b][/url]

____________________________________________________________________


[size=medium][b]一、关于apply 和 call 是什么[/b][/size]

[url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply]Function.prototype.apply()[/url]:

- The apply() method calls a function with a given this value and arguments provided as an array.
- 指定函数执行时的上下文对象 this,和执行参数,并执行函数。


call() 方法与 apply() 方法相同,不同的只是参数的格式。


[size=medium][b]二、用例剖析[/b][/size]

[url=http://www.cnblogs.com/PengNian/articles/838215.html]考虑以下这段代码:[/url]

<input type="button" id="btnSubmit" value="Click me!" />

<script language="javascript" type="text/javascript">

function ButtonMessager(buttonId, msg){

this.message = msg;

//在面向对象编程的函数体内,可以有面向过程的语句。
document.getElementById(buttonId).onclick = this.showMessage;

}

ButtonMessager.prototype.showMessage=function(){
alert(this.message);
}

var btnMessager = new ButtonMessager("btnSubmit", "Hello!");

</script>


按预想的意图,当点击按钮时,应当会弹出 [color=gray][i]"Hello!"[/i][/color],但上面的代码运行,却弹出 [color=gray][i]"undefined"[/i][/color] 。问题出在哪里呢?在12行设个断点,对它进行调试,发现 [color=gray][i]this[/i][/color] 竟然是指向 [color=gray][i]btnSubmit[/i][/color],如果是这样的话,那就难怪会弹出 [color=gray][i]"undefined"[/i][/color],因为 [color=gray][i]btnSubmit[/i][/color] 本身并没有定义 [color=gray][i]message[/i][/color]。

事实上,这是与Javascript的语法和运行机制有关的,当 [color=gray][i]showMessage[/i][/color] 真正调用前,[color=gray][i]this[/i][/color] 的指向是不明确,而只有在运行里,[color=gray][i]this[/i][/color] 的指向会由运行时来决定。


那么有没有什么方法来正确实现上述意图呢?答案是肯定的。

首先看下面的代码:

var x=10;
var o ={ x: 15 };
function foo(){
alert(this.x);
}

foo(); // 10
foo.call(o); // 15


function.call()方法的意义在于,当调用它时,函数使用给定的this作为上下文对象运行。
当调用 foo() 时,this是指向window的(所有的全局变量就是window的属性)。
当调用 foo.call(o) 时,this指向给定的 o 。


理解了function.call的作用,当解决上面的问题就不难了:

<input type="button" id="btnSubmit" value="Click me!" />

<script language="javascript" type="text/javascript">
function ButtonMessager(buttonId, msg){
this.message = msg;

// 当 click 事件触发时,this 不再指向 btnSubmit
// 而是指定的 ButtonMessager 生成的 对象:btn
document.getElementById(buttonId).onclick = createDelegate(this,this.showMessage);
}

ButtonMessager.prototype.showMessage=function(){
alert(this.message);
}

function createDelegate(object, method){
return function(){
method.apply(object);
}
}

var btn = new ButtonMessager("btnSubmit", "Hello!");

</script>
</script>



[size=medium][b]四、apply() 与 call() 辩析[/b][/size]

What is the difference between using call and apply to invoke a function?[1]

var func = function(){
alert('hello!');
};

func.apply();
//vs
func.call();


Are there performance differences between the two methods? When is it best to use call over apply and vice versa?


[url=http://stackoverflow.com/a/1986909/2893073][b]Anwser:[/b][/url]

The difference is that:
- apply lets you invoke the function with arguments as an array;
- call requires the parameters be listed explicitly.

A useful mnemonic is [color=darkblue]"A for array and C for comma."[/color]

See MDN's documentation on [url=https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply]apply[/url] and [url=https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call]call[/url].

Pseudo syntax:

//
theFunction.apply(valOfThis, arrayOfArgs)
//
//
theFunction.call(valOfThis, arg1, arg2, ...)
//


Sample code:


function theFunction(name, profession) {
console.log("My name is " + name + " and I am a " + profession + ".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");

// My name is John and I am a fireman.
// My name is Susan and I am a school teacher.
// My name is Claude and I am a mathematician.



[size=medium][b]五、补充说明:[/b][/size]

相同点:
都是指定函数运行时的上下文对象:this, 并执行函数。
不同点:
apply 可以将参数作为数组的形式传递
call 传递参数,必须一个个明确列出来

fun.apply(thisArg[, argsArray])
Calls a function with a given this value and arguments provided as an array (or an array like object).
[color=darkblue]Description:[/color]
You can assign a different this object when calling an existing function. this refers to the current object, the calling object.
apply is very similar to call, except for the type of arguments it supports.[2]

fun.call(thisArg[, arg1[, arg2[, ...]]])
Calls a function with a given this value and arguments provided individually.
[color=darkblue]Description:[/color]
You can assign a different this object when calling an existing function. this refers to the current object, the calling object.[3]


[size=medium][b]六、参数个数过长的处理[/b][/size]

例子(可以直接运行):

function minOfArray(arr) {
var min = Infinity;
var QUANTUM = 32768;

for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
min = Math.min(submin, min);
}

return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

alert(min);


说明:
But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.) If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:[4]


[size=medium][b]七、用法之一: 对匿名函数使用 call() 方法[/b][/size]


var animals = [
{species: 'Lion', name: 'King'},
{species: 'Whale', name: 'Fail'}
];

for (var i = 0; i < animals.length; i++) {
(function (i) {
this.print = function () { //add print method for arguments.
console.log('#' + i + ' ' + this.species + ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}

In this purely constructed example, we create anonymous function and use call to invoke it on every object in an array. The main purpose of the anonymous function here is to add a print function to every object, which is able to print the right index of the object in the array. Passing the object as [color=green]this[/color] value was not strictly necessary, but is done for explanatory purpose.


[size=medium][b]八、用法之二: Ext中的模板写法[/b][/size]
var fn = function(){
fn.superclass.constructor.apply(this,arguments);
}

Ext.extend(fn, Ext.util.Observable,{

});

superclass 是一个代指(变量),指向fn继承的父类。fn继承了谁,superclass就是谁。
constrctor 是也是变量,代指superclass的构造方法。

fn.superclass.constructor.apply(this,arguments);
指在创建 superclass 时,使用其构造方法,加入 arguments 作为参数,一起创建。


问题:superclass不是javaScript关键字,又怎么可以直接用呢?它是怎么产生的?
解释:
The Ext.extend method create a "superclass" property that point to the prototype of the Superclass, this allow you to execute or read any method or property in the superclass (that is defined in it's prototype).[5]


引用:
[1].[url]http://stackoverflow.com/questions/1986896/what-is-the-difference-between-call-and-apply[/url]
[2].[4].[url]https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply[/url]
[3].[url]https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call[/url]
[5].[url]http://www.sencha.com/forum/showthread.php?128276-Extend-how-to-call-parent-s-superclass[/url]


—————————————

javascript 函数基础系列文章

[url=http://lixh1986.iteye.com/blog/1955314]1、JavaScript之变量的作用域[/url]
[url=http://lixh1986.iteye.com/blog/2028899]2、javascript之变量类型与变量声明及函数变量的运行机制[/url]
[url=http://lixh1986.iteye.com/blog/1947017]3、javaScript之function定义[/url]
[url=http://lixh1986.iteye.com/blog/1896682]4、javascript之function的prototype对象[/url]
[url=http://lixh1986.iteye.com/blog/1891833]5、javascript之function的(closure)闭包特性[/url]
[url=http://lixh1986.iteye.com/blog/1960343]6、javascript之function的this[/url]
[url=http://lixh1986.iteye.com/blog/1943409]7、javascript之function的apply(), call()[/url]


___________


javascript 面向对象编程系列文章:

[url=http://lixh1986.iteye.com/blog/1958956]1、javaScript之面向对象编程[/url]
[url=http://lixh1986.iteye.com/blog/2332467]2、javascript之面向对象编程之属性继承[/url]
[url=http://lixh1986.iteye.com/blog/2348442]3、javascript之面向对象编程之原型继承[/url]


-


-
转载请注明
原文出处: http://lixh1986.iteye.com/blog/1943409


-
2016-07-12
-
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值