js中函数执行的两种方式:一是通过调用运算符’()’,二是通过调用call或apply来动态执行。
一、动态方法调用中指定this对象
开发中我们往往需要在对象B中调用对象A的方法,这个时候就用到了apply()和call(),它们的第一个参数就是用于指定this对象,如果为null,则表明传入默认的宿主对象。
function foo(){ alert(this.name); } function MyObject(){ this.name = 'MyObject'; } MyObject.prototype.do = function(){ foo.apply(this); } var obj = new MyObject(); //弹出'MyObject',这里的this就是obj obj.do();
二、栈的可见与修改
function fun1(v1){ var v1 = 100; } function fun2(name){ fun1.apply(this,arguments); alert(name); } //传入参数未被修改,仍然弹出'myName' fun2('myName');
这是因为,fun1.apply()被调用时,arguments被做了一次复制:值数据被复制,引用数据被创建引用。因此fun1与fun2中的arguments虽然看起来是相同的,其实是被隔离的两套数据。但是,如果把fun1改成下面这样:
function fun1(){ //显示true alert(arguments.callee.caller === fun2); }
所以外层的函数对于内部被调用的函数依然是可见的,尽管arguments在call() || apply()时是通过复制加以隔离的,但是调用栈对于被调用函数仍然可见,被调用函数仍然可以访问栈上的arguments,如:
function fun1(name){ arguments.callee.caller.arguments[0] = 100; //alert(arguments.callee.caller === fun2) } function fun2(name){ fun1.apply(this,arguments); alert(name); } //显示传入的参数被改为 100 fun2('myName');
在fun1中,我们通过callee与caller访问到栈上的函数的参数,并修改了fun2中的形式参数name,然而fun2并不知道形参已经被修改,因此这是极其危险的! 小盆友们都知道,类Arguments和Array通常是共享一个父类的——这是因为它们都有一个需要自维护的length属性。因此,我们也可以把Array原型中的方法apply到arguments实例上,例如:
[].slice.call(arguments,1);
但这也增加了调用栈上的风险:我们不但可以修改arguments中某些参数的值,也可修改arguments传入值的个数。例如:
function fun3(name){ [].push.call(arguments.callee.caller.arguments,100); } function fun4(name){ fun3(); //显示 2 console.dir(arguments.length); } fun4('myName');
作者:狂流
出处:http://www.cnblogs.com/kuangliu/
欢迎转载,分享快乐! 如果觉得这篇文章对你有用,请抖抖小手,推荐一下!