apply call this arguments caller callee

JavaScript为函数对象定义了两个方法:apply和call,它们的作用都是将函数绑定到另
外一个对象上去运行,两者仅在定义参数的方式有所区别:

Function.prototype.apply(thisArg,argArray);
Function.prototype.call(thisArg[,arg1[,arg2…]]);

从函数原型可以看到,第一个参数都被取名为thisArg,也就是说,所有函数内部的this
指针都会被赋值为thisArg,这就达到了将函数作为另外一个对象的方法运行的目的。两个
方法除了thisArg 参数,都是为Function 对象传递的参数。

 <script type="text/javascript">
        //定义一个函数func1,具有属性p和方法A
        function func1() {
            this.p = "func1-";
            this.A = function (arg) {
                alert(this.p + arg);
            }
        }
        //定义一个函数func2,具有属性p和方法B
        function func2() {
            this.p = "func2-";
            this.B = function (arg) {
                alert(this.p + arg);
            }
        }
        var obj1 = new func1();
        var obj2 = new func2();
        obj1.A("byA"); //显示func1-byA
        obj2.B("byB"); //显示func2-byB
        obj1.A.apply(obj2, ["byA"]); //显示func2-byA,其中[“byA”]是仅有一个元素的数组,下同
        obj2.B.apply(obj1, ["byB"]); //显示func1-byB
        obj1.A.call(obj2, "byA"); //显示func2-byA
        obj2.B.call(obj1, "byB"); //显示func1-byB
    </script>

可以看出,obj1的方法A被绑定到obj2运行后,整个函数A的运行环境就转移到了obj2,
即this指针指向了obj2。同样obj2 的函数B也可以绑定到obj1 对象去运行。代码的最后4
行显示了apply和call函数参数形式的区别。
与 arguments 的length属性不同,函数对象的还有一个参数相关的属性length,它表示
函数定义时所指定参数的个数,而非调用时实际传递的参数个数。例如下面的代码将显示2:

function sum(a,b){
return a+b;
}
alert(sum.length);

 

call,apply都是Function的原型的方法,其他function继承

this

和传统意义的面向对象的语言不同,JavaScript 中的this 指针是一个动态的变量,一个
方法内的this指针并不是始终指向定义该方法的对象的,在上一节讲函数的apply和call方
法时已经有过这样的例子。

 <script type="text/javascript">
       <!--
        //创建两个空对象
        var obj1 = new Object();
        var obj2 = new Object();
        //给两个对象都添加属性p,并分别等于1和2
        obj1.p = 1;
        obj2.p = 2;
        //给obj1添加方法,用于显示p的值
        obj1.getP = function () {
            alert(this.p); //表面上this指针指向的是obj1
        }
        //调用obj1的getP方法
        obj1.getP();
        //使obj2的getP方法等于obj1的getP方法
        obj2.getP = obj1.getP;
        //调用obj2的getP方法
        obj2.getP();
//-->
    </script>

从代码的执行结果看,分别弹出对话框1 和2。由此可见,getP函数仅定义了一次,在
不同的场合运行,显示了不同的运行结果,这是有this指针的变化所决定的。在obj1 的getP
方法中,this就指向了obj1 对象,而在obj2 的getP 方法中,this就指向了obj2 对象,并通
过this指针引用到了两个对象都具有的属性p。
由此可见,JavaScript 中的this 指针是一个动态变化的变量,它表明了当前运行该函数
的对象。由this指针的性质,也可以更好的理解JavaScript中对象的本质:一个对象就是由
一个或多个属性(方法)组成的集合。每个集合元素不是仅能属于一个集合,而是可以动态
的属于多个集合。这样,一个方法(集合元素)由谁调用,this指针就指向谁。实际上,前
面介绍的apply方法和call方法都是通过强制改变this指针的值来实现的,使this指针指向
参数所指定的对象,从而达到将一个对象的方法作为另一个对象的方法运行的效果。

this的范围

var user={
name:"jack", //定义了name属性,初始化为jack
favoriteColor:["red","green","black","white"],//定义了颜色喜好数组
hello:function(){ //定义了方法hello
alert("hello,"+this.name);
},
sex:"male" //定义了性别属性sex,初始化为sex
}
user.hello();       //"hello,jack"
var user={
name:"jack", //定义了name属性,初始化为jack
favoriteColor:["red","green","black","white"],//定义了颜色喜好数组
hello:function(){ //定义了方法hello
alert("hello,"+name);
},
sex:"male" //定义了性别属性sex,初始化为sex
}
user.hello();      //"hello,"
name="hongda";
var user={
name:"jack", //定义了name属性,初始化为jack
favoriteColor:["red","green","black","white"],//定义了颜色喜好数组
hello:function(){ //定义了方法hello
alert("hello,"+name);
},
sex:"male" //定义了性别属性sex,初始化为sex
}
user.hello();          //"hello,hongda"
  name = "hongda";
        var user = {
            name: "jack", //定义了name属性,初始化为jack
            favoriteColor: ["red", "green", "black", "white"], //定义了颜色喜好数组
            hello: function () { //定义了方法hello
                name = "hongdadada";
                alert("hello," + name);
            },
            sex: "male" //定义了性别属性sex,初始化为sex
        }
        user.hello();     //"hello,hongdadada"

一个对象内部的方法调用该对象的属性时要指明this,该属性不是某个范围内的变量。

 function fun() {
            name = "hongdada";
            function show() {  //没有意义
                alert(name);
            }
        }
        var f = new fun();
        console.dir(f);

 function fun() {
            this.name = "hongdada";
            this.show=function show() {
                alert(name);
            }
        }
        var f = new fun();
        console.dir(f);

function中没有this时,它就是个方法,只有有this时它才类似一个类

传递给函数的隐含参数:arguments

当进行函数调用时,除了指定的参数外,还创建一个隐含的对象——arguments。
arguments是一个类似数组但不是数组的对象,说它类似是因为它具有数组一样的访问性质,
可以用arguments[index]这样的语法取值,拥有数组长度属性length。arguments 对象存储的
是实际传递给函数的参数,而不只局限于函数声明所定义的参数列表,

function func(a,b){
alert(a);
alert(b);
for(var i=0;i<arguments.length;i++){
alert(arguments[i]);
}
}
func(1,2,3);   //1,2,1,2,3

  代码:

 <script type="text/javascript">
        function dwn(s) {
            document.write(s + "<br/>");
        }
        //定义一个多边形(Polygon)类型
        function Polygon() {
            //存放多边形的顶点
            var m_points = [];
            m_points = Array.apply(m_points, arguments);
            //用上面介绍的那种方式定义getter
            function GETTER() { };
            GETTER.prototype = m_points[0];
            this.firstPoint = new GETTER();
            //公有属性
            this.length = {
                valueOf: function () { return m_points.length },
                toString: function () { return m_points.length }
            }
            //添加一个或多个顶点
            this.add = function () {
                m_points.push.apply(m_points, arguments);
            }
            //取得序号为idx 的顶点
            this.getPoint = function (idx) {
                return m_points[idx];
            }
            //设置特定需要的顶点
            this.setPoint = function (idx, point) {
                if (m_points[idx] == null) {
                    m_points[idx] = point;
                }
                else {
                    m_points[idx].x = point.x;
                    m_points[idx].y = point.y;
                }
            }
        }
        //构造一个三角形p
        var p = new Polygon({ x: 1, y: 2 }, { x: 2, y: 4 }, { x: 2, y: 6 });
        dwn(p.length);           //3
        dwn(p.firstPoint.x);     //1
        dwn(p.firstPoint.y);     //2
        p.firstPoint.x = 100; //不小心写了它的值
        dwn(p.getPoint(0).x); //1 不会影响到实际的私有成员
        delete p.firstPoint.x; //恢复
        dwn(p.firstPoint.x);    //1
        p.setPoint(0, { x: 3, y: 4 }); //通过setter 改写了实际的私有成员
        dwn(p.firstPoint.x); //3 getter 的值发生了改变
        dwn(p.getPoint(0).x);  //3
 
    </script>

 

应用例子:

 function dwn(s) {
            document.write(s + "<br/>");
        }
        function App() {
        var fun={};
            var arr = Array.apply(null, arguments);
            var arr2 = Array.apply(arr2, arguments);
            var arr3 = Array.apply(fun, arguments);
            var arr4 = Array.apply(window, arguments);
            dwn(arr);
            dwn(arr2);
            dwn(arr3);
            dwn(arr4);
        }
        App(1, 2, 3, 4, 5, 6, 7, 8);

Array这个function方法对象初始化中没有使用this,所有thisArg不管填什么都没影响。

   function Class1() {
            this.name = "class1";
            this.showNam = function () {
                alert(this.name);
            }
        }
        function Class2() {
            this.name = "class2";
        }
        var c1 = new Class1();
        var c2 = new Class2();
        c1.showNam.call(c2);    //class2

call也可以形成继承

   function Class1() {
            this.showTxt = function (txt) {
                alert(txt);
            }
        }
        function Class2() {
            Class1.call(this);
        }
        var c2 = new Class2();
        c2.showTxt("cc");     //cc

class2继承class1

多继承

function Class1() {
            this.showTxt1 = function (txt) {
                alert("Class1:"+txt);
            }
        }
        function Class0() {
            this.showTxt0 = function (txt) {
                alert("Class0:"+txt);
            }
        }
        function Class2() {
            Class0.call(this);
            Class1.call(this);
        }
        var c2 = new Class2();
        c2.showTxt0("cc");
        c2.showTxt1("cccc");

在javascript框架prototype里就使用apply来创建一个定义类的模式

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

解析:从代码看,该对象仅包含一个方法:Create,其返回一个函数,即类。但这也同时是类的
构造函数,其中调用initialize,而这个方法是在类创建时定义的初始化函数。通过如此途径,
就可以实现prototype中的类创建模式

  var vehicle=Class.create();
        vehicle.prototype = {
            initialize: function (type) {
                this.type = type;
            },
            showSelf: function () {
                alert("this vehicle is " + this.type);
            }
        }

var moto=new vehicle("Moto");
moto.showSelf();

 

 

posted @ 2013-01-09 16:19  hongdada  阅读(317)  评论(0编辑  收藏  举报