call和apply的区别

来源:互联网 发布:网络协议的作用和功能 编辑:程序博客网 时间:2024/05/21 21:41
call和apply的区别

      我们在项目中经常使用call或者apply来继承某个类的实例属性和方法。但是你知道两者的却区别是什么吗?了解两者的区别,有助于你正确的选择使用call还是apply。

      在javascript中call方法和apply方法调用产生的效果是一样的,只是语法(参数)不一样。

目录:

  1、call和apply的区别,然后实例演示

  2、call和apply的常用应用场合

  3、call和apply不能继承原型的属性和方法

  4、怎样继承原型的属性和方法

 

1、call和apply的区别,然后实例演示

 call语法如下:

      obj.call(要替换的执行环境,参数1, 参数2,……,参数n);

 【实例】创建Person类,接收name和age两个参数及提供getName()和getAge()方法。然后创建一个Student对象从Person中继承name和age实例属性和方法。

// Person构造函数function Person(name, age){this.name = name;this.age = age;// 添加方法到原型if (typeof Person.prototype.getName != "function") {Person.prototype.getName = function(){return this.name;};Person.prototype.getAge = function(){return this.age;}}}// Student构造函数function Student(name, stuNum, age, qq){this.stuNum = stuNum;this.qq = qq;// 继承Person类的实例属性Person.call(this, name, age);}var stu = new Student("administritor", "No.1001", 23, "1840554");alert([stu.name, stu.age]); // 结果:administritor,23

 

apply语法如下:

      object.apply(要替换的执行环境,[参数1, 参数2,……,参数n ]);

 【实例】创建Person类,接收name和age两个参数及提供getName()和getAge()方法。然后创建一个Student对象从Person中继承name和age实例属性和方法。

// Person的构造函数function Person(name, age){this.name = name;this.age = age;// 添加方法到原型if (typeof Person.prototype.getName != "function") {Person.prototype.getName = function(){return this.name;};Person.prototype.getAge = function(){return this.age;}}}// Student的构造函数function Student(name, stuNum, age, qq){this.stuNum = stuNum;this.qq = qq;// 继承Person类的实例属性Person.apply(this, [name, age]);}var stu = new Student("administritor", "No.1001", 23, "1840554");alert([stu.name, stu.age]); // 结果:administritor,23

从上面实例可以看出,call和apply的主要区别是在指定调用object对象时传递构造参数的方式。call使用的类似java中的可变参数,即将构造参数一次排在“要替换的执行环境”后面。apply则使用一个数组将构造参数进行包装,然后传递。

 

2、call和apply的常用应用场合

【实例】如果Person对象的构造参数和Student对象的构造参数完全一样(包括顺序)。此时,我们应该选择call还是apply呢?由于apply接收一个数组、Person和Student的构造参数一样且arguments也是一个数组。则,我们可以直接用:object.apply(this, arguments);就可进行继承。但是有人说,call也可以啊。我直接将参数依次写在object.call(this, arg1, arg2,...,argn)。如果Person和Student的参数有n个,则你需要写多少呢,你能保证你不会把顺序写错,你觉得代码可读性好吗?因此,如果被继承和继承的构造函数一样(包括参数顺序),则推荐使用apply方式。

// Person构造函数function Person(name, age){this.name = name;this.age = age;// 添加方法到原型if (typeof Person.prototype.getName != "function") {Person.prototype.getName = function(){return this.name;};Person.prototype.getAge = function(){return this.age;}}}// Student构造函数function Student(name, age){//Person.apply(this, [name, age]);// 同上Person.apply(this, arguments);if (typeof Student.prototype.setName != "function") {Student.prototype.setName = function(name){this.name = name;};Student.prototype.setAge = function(age){this.age = age;};}}// 测试var stu = new Student("administritor", 23);alert([stu.name, stu.age]);stu.setName("operation");stu.setAge(41);alert([stu.name, stu.age]);

如果Person和Student的参数不一样,则两种方式你就选择你自己喜欢的方式。

// Person构造函数function Person(name, age){this.name = name;this.age = age;}// 方式一:function Student(name, sex, age, email){this.sex = sex;this.email = email;        Person.call(this, naem, age);}方式二:function Student(name, sex, age, email){this.sex = sex;this.email = email;Person.apply(this, [name, age]);}
3、call和apply不能继承原型的属性和方法
在上面的Person和Student例子中如果调用Person的getName()和getAge()方法,则会抛出”对象不支持属性和方法“错误;
代码如下:
function Person(name, age){this.name = name;this.age = age;// 添加方法到原型if (typeof Person.prototype.getName != "function") {Person.prototype.getName = function(){return this.name;};Person.prototype.getAge = function(){return this.age;}}}function Student(name, stuNum, age, qq){this.stuNum = stuNum;this.qq = qq;Person.call(this, name, age);}var stu = new Student("administritor", "No.1001", 23, "1840554");alert([stu.getName(), stu.getAge()]);
 为什么呢?
我们先看一下call和apply的运行方式。当执行Person.call(this, name, age); 这行代码时,实际是将Person构造函数内部的this替换成Student的,相当于将Person中的this.name=name;this.age=age;两行代码移植到Student构造函数内部。所以我们可以通过Student的实例访问name和age的原因。为什么不能访问Person.prototype上面的getName()和getAge()方法呢?我认为是,call或apply只是替换了Person中的this,而且Student自己存在Student.prototype。依照js的变量搜索方法,先在Student.prototype,如果不存在,则在Person中去找Person.prototype。
4、怎样继承原型的属性和方法
要继承原型中的属性和方法,则只能通过原型链方式进行继承。如:
Student.prototype = new Person("zhangsan", 23);
调用了该语句后,Student的实例对象就可以调用Person.prototype的getName和getAge方法了。为什么呢?
调用Student.prototype = new Person("zhangsan", 23);前的模型如下图:


调用后:

 如果现在要在Student的实例上调用getName(),则搜索路径如下:
1、现在Student中查找,如果找到则返回。否则,执行2
2、在Student的原型中查找,如果找到则返回。否则,执行3
3、在Student的原型的原型中找(Person的原型中找),如果找到则返回。否则,执行4。
4、在Object中查找,如果找到则返回,否则,抛出”对象没有属性和方法“错误。
注意:2和3步依次类推,直到Object。
【实例】实现实例属性和原型方法的继承。
// Person的构造方法function Person(name, age){this.name = name;this.age = age;if (typeof Person.prototype.getName != "function") {Person.prototype.getName = function(){return this.name;};Person.prototype.getAge = function(){return this.age;}}}// Student的构造方法function Student(name, stuNum, age, qq){this.stuNum = stuNum;this.qq = qq;// 继承实例属性和方法Person.call(this, name, age);}// 继承原型的属性和方法Student.prototype = new Person();var stu = new Student("administritor", "No.1001", 23, "1840554");alert([stu.getName(), stu.age]);
0 0
原创粉丝点击