javascript中继承机制没有明确定义而是同过模仿实现的,总共有三种实现方式分别是:

1.  对象冒充:原理,构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB:

functionClassA(sColor) {

this.color = sColor;

this.sayColor = function () {

alert(this.color);

};

}

functionClassB(sColor) {

this.newMethod = ClassA;

this.newMethod(sColor);

delete this.newMethod;

}

关键字 this 引用的是构造函数当前创建的对象。不过在这个方法中,this 指向的所属的对象。这个原理是把 ClassA 作为常规函数来建立继承机制,而不是作为构造函数。

在这段代码中,为ClassA 赋予了方法 newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是 ClassB 构造函数的参数 sColor。最后一行代码删除了对 ClassA 的引用,这样以后就不能再调用它。

所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法:

functionClassB(sColor, sName) {

this.newMethod = ClassA;

this.newMethod(sColor);

delete this.newMethod;

this.name = sName;

this.sayName = function () {

alert(this.name);

};

}

为证明前面的代码有效,可以运行下面的例子:

var objA= new ClassA("blue");

var objB= new ClassB("red", "John");

objA.sayColor();         //输出 "blue"

objB.sayColor();         //输出 "red"

objB.sayName();

对象冒充可以支持多重继承。也就是说,一个类可以继承多个超类。用 UML 表示的多重继承机制如下图所示:

例如,如果存在两个类ClassX 和 ClassY,ClassZ 想继承这两个类,可以使用下面的代码:

function ClassZ() {

this.newMethod = ClassX;

this.newMethod();

delete this.newMethod;

this.newMethod = ClassY;

this.newMethod();

delete this.newMethod;

}

注:这里存在一个弊端,如果存在两个类ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

2.  call方法:

call是Function对象的方法。它的第一个参数用作this的对象。其他参数都是直接传递给函数自身。eg:

functionsayColor(sPrefix,sSuffix) {

alert(sPrefix + this.color + sSuffix);

};

var obj =new Object();

obj.color= "blue";

sayColor.call(obj, "The color is", "a very nice color indeed.");

在这个例子中sayColor在对象外定义,然后通过call方法将函数绑定到对象obj中

要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值、调用和删除代码替换即可:

functionClassB(sColor, sName) {

//this.newMethod = ClassA;

//this.newMethod(color);

//delete this.newMethod;

ClassA.call(this, sColor);

this.name = sName;

this.sayName = function () {

alert(this.name);

};

}

3.  apply方法

apply() 方法有两个参数,用作this 的对象和要传递给函数的参数的数组。例如:

functionsayColor(sPrefix,sSuffix) {

alert(sPrefix + this.color + sSuffix);

};

var obj =new Object();

obj.color= "blue";

sayColor.apply (obj, new Array("The color is ", "a very nice colorindeed."));

这个例子与前面的例子相同,只是现在调用的是apply() 方法。调用 apply() 方法时,第一个参数仍是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个参数是由两个字符串构成的数组,与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息仍是 "The color is blue, a very nice color indeed.",将被显示出来。

该方法也用于替换前三行的赋值、调用和删除新方法的代码:

functionClassB(sColor, sName) {

//this.newMethod = ClassA;

//this.newMethod(color);

//delete this.newMethod;

ClassA.apply(this, new Array(sColor));

this.name = sName;

this.sayName = function () {

alert(this.name);

};

}

同样的,第一个参数仍是 this,第二个参数是只有一个值color 的数组。可以把 ClassB 的整个 arguments 对象作为第二个参数传递给 apply() 方法:

functionClassB(sColor, sName) {

//this.newMethod = ClassA;

//this.newMethod(color);

//delete this.newMethod;

ClassA.apply(this, arguments);

this.name = sName;

this.sayName = function () {

alert(this.name);

};

}

4.  原型链

prototype对象是一个模板,要实例化的对象都以这个模板为基础。prototype对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。

如果用原型方式重定义前面例子中的类,它们将变为下列形式:

functionClassA() {

}

ClassA.prototype.color= "blue";

ClassA.prototype.sayColor= function () {

alert(this.color);

};

functionClassB() {

}

ClassB.prototype = new ClassA();

原型方式的神奇之处在于突出显示的蓝色代码行。这里,把ClassB的prototype属性设置成ClassA的实例。

这很有意思,因为想要ClassA的所有属性和方法,但又不想逐个将它们设置为ClassB的prototype属性。还有比把ClassA的实例赋予prototype属性更好的方法吗?

注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。

与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 ClassB 类添加 name 属性和 sayName() 方法的代码如下:

functionClassB() {

}

ClassB.prototype= new ClassA();

ClassB.prototype.name= "";

ClassB.prototype.sayName= function () {

alert(this.name);

};

黑体字的意思是这样会报错:

可通过运行下面的例子测试这段代码:

var objA= new ClassA();

var objB= new ClassB();

objA.color= "blue";

objB.color= "red";

objB.name= "John";

objA.sayColor();

objB.sayColor();

objB.sayName();

此外,在原型链中,instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。例如:

var objB= new ClassB();

alert(objBinstanceof ClassA);  //输出"true"

alert(objBinstanceof ClassB);  //输出"true"

在 ECMAScript 的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。

原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。

5,。混合方式

创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:

functionClassA(sColor) {

this.color = sColor;

}

ClassA.prototype.sayColor= function () {

alert(this.color);

};

functionClassB(sColor, sName) {

ClassA.call(this, sColor);//以普通方法的形式调用ClassA的构造函数

this.name = sName;

}

ClassB.prototype = new ClassA();//继承ClassA的原型方法

ClassB.prototype.sayName= function () {

alert(this.name);

};

在此例子中,继承机制由两行突出显示的蓝色代码实现。在第一行突出显示的代码中,在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性。在第二行突出显示的代码中,用原型链继承 ClassA 类的方法。由于这种混合方式使用了原型链,所以 instanceof 运算符仍能正确运行。

下面的例子测试了这段代码:

var objA= new ClassA("blue");

var objB= new ClassB("red", "John");

objA.sayColor();         //输出 "blue"

objB.sayColor();         //输出 "red"

objB.sayName();       //输出"John"

转载于:https://blog.51cto.com/7613577/1561407

js call和apply方法小结相关推荐

  1. JS call()和apply()方法和区别

    一.方法定义: apply:调用一个对象的一个方法,用另一个对象替换当前对象.例如:B.apply(A, arguments);即A对象应用B对象的方法. call:调用一个对象的一个方法,用另一个对 ...

  2. js设置元素class方法小结及classList相关

        给DOM元素设置class是我们在项目中非常容易遇到的,网上的资料和总结也比较多,下面比较全面的整理一下,希望给到大家一些帮助!并引用两种成熟的classList的兼容方法 一.el.setA ...

  3. 面试官问:能否模拟实现JS的call和apply方法

    写于2018年11月30日,发布在掘金上阅读量近一万,现在发布到微信公众号申明原创.相对比较基础的知识,虽然日常开发可能用得比较少,各种源码中有很多call和apply,需要掌握. 前言 这是面试官问 ...

  4. JS中的call()和apply()方法(转)

    转自:http://uule.iteye.com/blog/1158829 JS中的call()和apply()方法 博客分类: JS 1.方法定义 call方法:  语法:call([thisObj ...

  5. asp.net调用js方法小结

    asp.net调用js方法小结 key:asp.net js方法互调   asp.net 前台如何调用后台方法 1. javaScript函数中执行C#代码中的函数: 方法一:1.首先建立一个按钮,在 ...

  6. js中call()方法和apply方法的使用

    1. 方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  7. JS中的call()和apply()方法

    1.方法定义 call方法:  语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]])  定义:调用一个对象的一个方法,以另一个对象替换当前对象.  说明:  ...

  8. js中call()与apply()方法

    菜鸟级别的选手,学习+意会.欢迎指正 参考文章 http://uule.iteye.com/blog/1158829 http://blog.csdn.net/myhahaxiao/article/d ...

  9. Js中apply方法详解说明

    Js apply 方法 详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了, ...

  10. Js apply 方法 详解

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

最新文章

  1. Mongo DB 2.6 需要知道的一些自身限定
  2. 【算法精讲】集成分类与随机森林
  3. [c++]代理对象模式
  4. 分布式SQL学习总结(2)——TiDB 的现在和未来
  5. 从 SGD 到 Adam —— 深度学习优化算法概览(一) 重点
  6. 《东周列国志》第九十六回 蔺相如两屈秦王 马服君单解韩围
  7. Java上帝类(Object类)源码总结(1)
  8. VGG16 VGG19
  9. IrisSkin 皮肤
  10. 期末前端web大作业:用DIV+CSS技术设计的动漫网站——火影忍者6页 带报告
  11. APT之木马静态免杀
  12. c语言中while中的判断语句为感叹号x时是什么意思?
  13. 兴安雪学运维之:CentOS用户组管理groupadd,groupdel...
  14. 使用connet或者手动关联react和redux
  15. 视频教程-Composer 安装与基本使用-PHP
  16. u盘win7纯净版_系统之家win7纯净版一键清除软件_一键清除系统lj.bat
  17. Python爬虫获取某个网页所有的a标签中的超链接网址
  18. linux-命令-procps-ng工具-top
  19. StarForce学习1-流程
  20. Python爬取糗事百科段子

热门文章

  1. Linux音频驱动-ASOC(ALSA System on Chip)
  2. 静态存储区(BSS、数据段、代码段),堆,栈-----------------(划归在C语言)
  3. 3726.调整数组-AcWing题库
  4. python 异常处理小结 try except raise assert
  5. 【快速乘与快速幂例题讲解】相乘取余爆long long?试试快速乘吧!
  6. 山山的数学(困难版)
  7. Linux下解压.war文件
  8. linux服务器上使用apache部署静态html网页
  9. python中sendmessage的使用_SendMessage函数完全使用手册
  10. matlab 大于并且小于,matlab分段函数中大于、小于(“」”、“「”)的应用