js中实现继承和传统的面向对象语言中有所不同:传统的面向对象语言的继承由类来实现,而在js中,是通过构造原型来实现的,原型与如下几个术语有关:

①构造函数:在构造函数内部拥有一个prototype属性,这个属性指向原型。在js中,构造函数和函数是属于一个概念范畴,都是引用类型,都可以实例化为对象。唯一不同的地方是使用上的不同,用new关键字来调用函数就能让这个函数变成一个构造函数,这一点很好理解,因为在像java、C#这中类C语言中构造函数就是和方法是同名的。而如果要实例化一个类,那么就用new来构造一个类的实例。prototype保存一个指针,指向这个构造函数的原型。实现继承后,原型中保存的引用类型(像Arrya、Function等)会被所有实例化后的对象所共享。原型是js中实现继承的重要方式,通过构造原型链,可以实现代码复用,后面会用代码来阐述这一点。

②原型:在原型内部保存一个constructor的属性,这个属性保存一个指针,指向构造函数。

③对象(实例):在实例内部保存一个[[prototype]]的指针,指向原型,通过这个[[prototype]],所有实例就可以访问原型中的所有属性和方法。

在继承上面需要注意的是原型中保存的基础类型的属性在继承后能被重写(由于js动态添加特性),这个是没有问题的(如string、number、bool等),问题出在引用类型的属性(和函数)上,如果在原型中定义了一个Array,那么在所有的实例中将共享这个属性,那么,在一个实例中对这个Array所做的任何改变都会体现到其他实例中,这就破坏了面向对象的程序设计中对封装的要求。所以,下面介绍一个如果去有效的建立继承,这里我记录两个最为理想的例子。

第一个:

'use strict';
function Person(name,age) {
    this.name = name;
    this.age = age;
    this.address = ["a", "b"];
}
Person.prototype.getName = function() {
    return this.name;
}
Person.prototype.favoriteColor = ["red", "blue"];
function Student(name, age) {
    Person.call(this, name, age);
}
Student.prototype = new Person("parents", 60);
var student1 = new Student("xp", 20);
var student2 = new Student("xz", 30);
student2.address[2] = "c";
student1.favoriteColor[3] = "green";
console.log(student1.address);//['a','b']
console.log(student2.address);//['a','b','c']
console.log(student1.getName());//'xp'
console.log(student2.getName());//'xz'
console.log(student1.favoriteColor);//['red','green',blue']
console.log(student2.favoriteColor);//['red','green',blue']
 

上面这个代码说明了一个问题:使用构造原型链和借用构造函数这种组合的方式来实现继承的关键要点是在原型中声明函数,而在构造函数中声明属性,这种的意义在于原型中声明的属性或方法会被子类共享,如果属性是基础类型的那么不存在问题,但是如果声明的是引用类型的,那么在其中一个子类中对这个属性做出的修改会延续到其他的子类中,这样就破坏了封装性。我们要做的是在构造函数中声明属性,在原型中声明方法,这样就避免了上述出现的问题。

 

下面介绍第二种方式:

首先定义两个函数:

function object(o) {
function F() { } F.prototype = o.prototype;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}

一个函数是object(),这个函数接受一个构造函数的原型,object内部先定义一个构造函数,然后将传入的原型赋给这个定义好的构造函数的原型。

另一个函数是inheritPrototype,从字面意思上来讲就是继承原型。这个函数接受两个构造函数作为参数,在函数内部,使用object()函数返回一个实例化后的构造函数,接着将这个构造函数当作一个原型,并将为这个构造函数添加一个constructor的属性(constructor是原型中的属性,因为object函数返回的是一个构造函数,并没有constructor这个属性,所以要手动设置一个),并将constructor属性的值手动设置为传入的第一个参数(可以看出传入的第一个参数是作为子类,另一个是基类)。然后将第一个参数的原型设置为这个构造函数。这个函数基本解决了上面第一种所遇到的各种不好的情况:

"use strict";
function object(o) {
function F() { } F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
} function BaseClass(name, age) {
this.name = name;
this.age = age;
this.favoriteColor = ["red", "green"]; //新添加的属性
} BaseClass.prototype.sayName = function () {
console.log(this.name);
};
function DerivedClass(name, age, job) {
this.job = job;
BaseClass.call(this, name, age);
}
inheritPrototype(DerivedClass, BaseClass);//替换DerivedClass.prototype=new BaseClass();
DerivedClass.prototype.sayHi = function () {
console.log(this.job);
}
var derived1 = new DerivedClass("bob", 16, "SoftWare Engineer");
derived1.favoriteColor.push("black");
console.log(derived1.favoriteColor);//["red","green","blacjk"]
derived1.sayName();//bob
var derived2 = new DerivedClass("loryn", 17, "doctor");
console.log(derived2.favoriteColor);//["red","green"]

首先解决的是构造函数的使用次数,这个优化后的只使用了一次构造函数:

BaseClass.call(this, name, age);
然后解决的是原型链的问题:
inheritPrototype(DerivedClass, BaseClass);//替换DerivedClass.prototype=new BaseClass();
在inheritPrototype函数中调用object函数,object函数直接将传入的原型赋给新创建的这个构造函数的原型。而在inheritPrototype函数中完成了两个构造函数之间的继承关系。
												

Javascript中实现继承的方式的更多相关文章

  1. JavaScript 中实现继承的方式(列举3种在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。)

    第一种:对象冒充 function ClassA(sColor) { this.color = sColor; this.sayColor = function () { alert(this.col ...

  2. javascript中各种继承方式的优缺点

    javascript中实现继承的方式有很多种,一般都是通过原型链和构造函数来实现.下面对各种实现方式进行分析,总结各自的优缺点. 一 原型继承 let Super = functioin(name = ...

  3. javascript中实现继承的几种方式

    javascript中实现继承的几种方式 1.借用构造函数实现继承 function Parent1(){ this.name = "parent1" } function Chi ...

  4. JavaScript学习13 JavaScript中的继承

    JavaScript学习13 JavaScript中的继承 继承第一种方式:对象冒充 <script type="text/javascript"> //继承第一种方式 ...

  5. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  6. 浅谈 JavaScript 中的继承模式

    最近在读一本设计模式的书,书中的开头部分就讲了一下 JavaScript 中的继承,阅读之后写下了这篇博客作为笔记.毕竟好记性不如烂笔头. JavaScript 是一门面向对象的语言,但是 ES6 之 ...

  7. JavaScript中定义类的方式详解

    本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...

  8. 深入理解JavaScript中的继承

    1前言 继承是JavaScript中的重要概念,可以说要学好JavaScript,必须搞清楚JavaScript中的继承.我最开始是通过看视频听培训班的老师讲解的JavaScript中的继承,当时看的 ...

  9. JavaScript中的继承(原型链)

    一.原型链 ECMAScript中将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 实例1: function SupType() { this.pro ...

随机推荐

  1. spring.factories

    在Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的. Java SPI机制SPI的全名为Service P ...

  2. eclipse中xml下Namespaces显示不全的解决办法

    1.问题描述: 如图,有时候编写spring相关的xml文件时,使用namepace中显示不全或者完全不显示 2.解决方法: Window —— Spring ——     Beans Support ...

  3. 自己编写的Shell

    shell文件 #!/bin/sh ## param 1: log string #下面的$1指的是调用这个function时传过来的第一个参数,依次类推 $2第二个 $3第三个funcLog() { ...

  4. QT获取窗口大小和位置等信息

    QT窗口尺寸,窗口大小和大小改变引起的事件 QResizeEvent. 来源:http://blog.csdn.net/dbzhang800/article/details/6741344?reloa ...

  5. 避免for循环

    http://www.360doc.com/content/10/0610/22/1217721_32411251.shtml 避免使用for循环: 在Matlab中,for循环运算效率非常低,因为M ...

  6. Swift 重点知识汇总

    1.语句末尾的分号可有可无,类似python和JavaScript. print("hello world!") 2.let定义常量,var定义变量 let aConstant = ...

  7. Luogu3175 HAOI2015 按位或 min-max容斥、高维前缀和、期望

    传送门 套路题 看到\(n \leq 20\),又看到我们求的是最后出现的位置出现的时间的期望,也就是集合中最大值的期望,考虑min-max容斥. 由\(E(max(S)) = \sum\limits ...

  8. CF613D Kingdom and its Cities 虚树

    传送门 $\sum k \leq 100000$虚树套路题 设$f_{i,0/1}$表示处理完$i$以及其所在子树的问题,且处理完后$i$所在子树内是否存在$1$个关键点满足它到$i$的路径上不存在任 ...

  9. Bootstrap栅栏布局里col-xs-*、col-sm-*、col-md-*、col-lg-*之间的区别及使用方法

    原文:Bootstrap栅栏布局里col-xs-*.col-sm-*.col-md-*.col-lg-*之间的区别及使用方法 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...

  10. LOJ #6062. 「2017 山东一轮集训 Day2」Pair

    这是Lowest JN dalao昨天上课讲的一道神题其实是水题啦 题意很简单,我们也很容易建模转化出一个奇怪的东西 首先我们对b进行sort,然后我们就可以通过二分来判断出这个数可以和哪些数配对 然 ...