js中的apply()和call()执行域转换详解

来源:互联网 发布:linux open函数头文件 编辑:程序博客网 时间:2024/06/05 20:33

js中函数其实是一个对象,这两个方法都是针对函数对象的,其目的是转换当前函数的执行环境,也就是函数中this所指的对象。

我们首先来看第一个实例:  

 function A(){                B.call(this);    }    function B(){        this.show = function(){            alert(this.param);        }    }    A.prototype = {        param : "A"    }    B.prototype = {        param : "B"    }    var a = new A();    a.show(); //输出A    var b = new B();<span id="transmark"></span>    b.show(); //输出B

    从以上实例可以看出B.call(this)这句使得函数A继承了B(B中的show()函数不在B的prototype中,但为什么b.show()可以访问不得而知,望高手赐教),而且a.show()输出A说明B.call(this)使得show函数执行时的作用域变成了对象a,所以此时访问的是对象a中prototype的param。

    下面我们看第二个实例:

function A(){  this.param = 'A';                B.call(this);    }    function B(){        this.show = function(){            alert(this.param);        }    }    B.prototype = {        param : "B"    }    var a = new A();    a.show(); //输出A    var b = new B();    b.show(); //输出B    alert(A.param); //输出undefined

    上述实例中我们不再在prototype对象中定义param变量,而在function A()中用this.param='A'代替,此时a.show()也能输出'A',而A.show()却输出了'undefined',这是为什么呢?首先通过之前的学习可以确定,JS中的函数是一个对象,函数名是一个函数对象的引用,而且JS中的对象和JAVA中的对象一样,同样有类和实例对象之说。于是笔者在此大胆猜测,函数里面定义的变量和prototype中定义的变量需要经过new出的对象才能直接引用,看之前我转载的一篇文章( JS中prototype详解 )中有介绍,称为“对象变量\方法”和“原型变量\方法”,与之相似的还有一个“类变量\方法”。我们先掌握这个,对后面理解有好处。

    下面我们看第三个实例:

function A(){            B.call(this);    }    function B(){        this.newParam = 'newB';        this.show = function(){            alert(this.param);        }    }    B.prototype = {        param : "B"    }    var a = new A();    a.show(); //输出undefined    alert(a.newParam); //输出newB    var b = new B();     b.show(); //输出B    alert(A.param); //输出undefined

    上述例子中A()中去掉了this.param='A',此时a.show()输出undefined,于是可以推测出B.call(this)不会将prototype中定义的原型变量“复制”到实例变量a,如果变量不存在则输出undefined,如果方法不存在则报错,但是B()中定义的对象变量\方法则可以“复制”到a变量中。注意,此处的“复制”还真是把b中的变量和方法复制到了a变量中,具体读者可用console.log()在浏览器控制台中看看。

    下面我们看第四个实例:

function A(){           this.param = 'newA';    }    function B(){    this.newParam = 'newB';        this.show = function(){            alert(this.param);        }    }    B.staticParam = 'staticB';     B.prototype = {        param : "B"    }    A.param = 'staticA';    var a = new A();    B.call(A);     A.show(); //输出staticA    alert(A.newParam); //输出newB    alert(A.staticParam); //输出undefined
    上述例子中我们可以看到B.call(A),此时因为A相当于类,所以将B中的对象方法\变量复制到了类A中,成为了A的类变量\方法,而alert(A.staticParam)输出undefined说明B的类变量不会复制到A中。

    下面我们看第五个实例:

function A(){           this.param = 'newA';    }    function B(){    this.newParam = 'newB';        this.show = function(){            alert(this.param);        }    }    B.staticParam = 'staticB';     B.prototype = {        param : "B"    }    A.param = 'staticA';    var a = new A();    b.call(A); 
    上述例子报"Uncaught TypeError: b.call is not a function",可推测call()方法是类方法,实例对象无法调用,而apply()也是类方法,读者可自己测之。

    好了,现在咱们来总结一下,JS中的call()和apply()方法是函数对象的类方法,方法的第一个参数表示当前需转换的域对象,可以为对象实例,也可以为类。而只有函数的对象变量\方法才能复制到新的执行域中,当执行域为类对象,则需用类对象来引用,否则需用实例对象引用。笔者在本篇文章中都是用的call()函数来举例,apply()其实和call()用法基本一样,后面笔者将会写一篇专门比较apply()和call()的文章。

0 0
原创粉丝点击