打算针对js的继承写一系列文章,详细的分析js里继承原理,实现方式,各种继承方式的优缺点,以及最优继承方案,还有多继承的问题等….

面向对象的编程的核心是封装、继承和多态,js可以看作是一种面向对象的语言,而面向对象的扩展性最核心的部分是多态,多态的必要条件有三个,首先就是继承,其次父类的引用指向子类,最后是方法重写。对于js来说,由于其创建对象的方式多种多样,因此,需要对父类的多种属性和方法实现很好的继承,就必须找到一个比较完善的方法。本篇文章首选介绍三种最基本的继承方式,并分析这几种继承方式的缺陷。

介绍js继承前,大家先需要js里类的各种属性以及js创建对象的几种模式有所了解。

js类的属性可以参考: javascript中类的属性研究 这篇文章。

js创建对象的方式可以参考:javascript创建对象的三种模式 这篇文章。

第一种方式:对象冒充

对象冒充,是指将父类的属性和方法一起传给子类作为特权属性和特权方法。

function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = function(){
alert('hi');
}
} Person.prototype.walk = function(){
alert('walk.......');
} function Student(name,age,grade){
this.newMethod = Person;
this.newMethod(name,age);
delete this.newMethod;
this.grade = grade;
} var s1 = new Student('xiaoming',10,3);
console.log(s1.name,s1.age,s1.grade);//xiaoming 10 3
//s1.walk();//s1.walk is not a function

可见Student类只继承了Person类的特权属性和方法,并没有继承Person类的共有属性和方法。

第二种方式:call或apply

使用call或apply改变对象的作用域来实现继承,让父类的this等于新创建的子类的对象(因为call和apply继承实现机制是一样的,就是传参方式不同,call传多个参数用逗号隔开,apply用数组),本文主要介绍call来实现继承。

function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = function(){
alert('hi');
}
} Person.prototype.walk = function(){
alert('walk.......');
} function Student(name,age,grade){
Person.call(this,name,age);
this.grade = grade;
} var s1 = new Student('xiaoming',10,3);
console.log(s1.name,s1.age,s1.grade);//xiaoming 10 3
//s1.walk();//s1.walk is not a function

同第一种问题一样,没有继承共有属性和方法。call改变了Person中this的作用域,使其指向了Student。对于call方法举例如下:

function Person(){
this.name ='xiaoming';
} Person.call(this);
alert(window.name);

此例将Person中this的作用域扩大到window上,使得Person中的name属性变为一个全局变量。

第三种方式:prototype

使用prototype属性实现继承,让父类的prototype赋给子类的prototype,也可以将父类的实例赋给子类的prototype,这里先介绍将父类的原型赋给子类的原型这种方式,并探讨这种方式的缺陷。在以后会着重介绍prototyp这种继承方式。

function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = function(){
alert('hi');
}
} Person.prototype.walk = function(){
alert('walk.......');
} function Student(name,age,grade){
this.grade = grade;
} Student.prototype = Person.prototype; var s1 = new Student('xiaoming',6,3);
s1.walk();//walk.......
console.log(s1.name,s1.age,s1.grade);//xiaoming 6 3
console.log(s1.constructor); // Person(name,age)
Student.prototype.study = function(){
alert('I am study');
}
var p1 = new Person();
p1.study();//I am study

主要缺陷:不能继承父类的特权属性和特权方法,子类的构造函数变成了Person(name,age),直接导致修改子类的原型方法时,父类也跟着修改了,耦合度太高了。

如果将父类的实例指向子类的原型会出现什么情况呢?

function Person(name,age){
this.name = name;
this.age = age;
this.sayHi = function(){
alert('hi');
}
} Person.prototype.walk = function(){
alert('walk.......');
} function Student(name,age,grade){
this.grade = grade;
} Student.prototype = new Person(); var s1 = new Student('xiaoming',6,3);
s1.walk();//walk.......
console.log(s1.name,s1.age,s1.grade);//undefined undefined 3
console.log(s1.constructor); // Person(name,age)
Student.prototype.study = function(){
alert('I am study');
}
var p1 = new Person();
//p1.study();// p1.study is not a function

虽然子类Student的实例s1仍然指向父类Person的构造函数,但此时修改子类的共有方法并不会对父类有所影响。然后这种方式存在一个更为严重的问题是,子类虽然继承父类的特权属性,但是没法进行修改。并且每创建一个子类的实例时都会把父类的所有属性和方法创建一遍,相对于继承父类的prototype属性中共有方法使用同一代码块对代码空间存在较为严重的浪费。

总结:几种继承方式各有各的缺陷,那么如何实现完美的继承呢。也许将其中的某两种继承方式结合起来才行。在以后会接着介绍call和prototype结合实现js的继承功能。

javascript继承(三)—继承的实现原理的更多相关文章

  1. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

  2. JavaScript 继承——三种继承方法及其优劣

    原文地址   本文内容 目的 继承的第一步--最简单的继承 私有变量/成员和原型 三种继承方式及其优劣 基本的原型继承 Yahoo JavaScript 模块模式 创建闭包的构造函数 三种方法的代码执 ...

  3. 【设计模式+原型理解】第三章:javascript五种继承父类方式

    [前言] 我们都知道,面向对象(类)的三大特征:封装.继承.多态 继承:子类继承父类的私有属性和公有方法 封装:把相同的代码写在一个函数中 多态: ->重载:JS严格意义上是没有重载,但可以通过 ...

  4. JavaScript 继承 封装 多态实现及原理详解

    面向对象的三大特性 封装 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.封装是面向对象的特征之一,是对象和类概念的主要特性. ...

  5. Javascript 面向对象编程—继承和封装

      前  言 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类) ...

  6. JavaScript 的对象继承方式,有几种写法?

    JavaScript 的对象继承方式,有几种写法? 一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Pa ...

  7. 架构师JavaScript 的对象继承方式,有几种程序写法?

    架构师JavaScript 的对象继承方式,有几种程序写法?   一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数, ...

  8. JavaScript中的继承

    一.原型链(默认) function Person(){}; function Student(){}; Student.prototype = new Person(); Student.proto ...

  9. JavaScript学习13 JavaScript中的继承

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

随机推荐

  1. 在linux下修改mysql的root密码

    第一种方法: root用户登录系统 /usr/local/mysql/bin/mysqladmin -u root -p password 新密码 enter password 旧密码 第二种方法: ...

  2. 通过反射获取SSM的controller层的注解以及注解中的value值

    package com.reflection.test; import java.lang.annotation.Annotation; import java.lang.reflect.Invoca ...

  3. 记一次Web应用CPU偏高

    LZ开发的一个公司内部应用供查询HIVE数据使用.部署上线后总是会出现CPU偏高的情况,而且本地测试很难重现.之前出现几次都是通过直接重启后继续使用,因为是内部使用,重启一下也没有很大影响(当然,每次 ...

  4. I2C 总线协议

    1.I2C协议     2条双向串行线,一条数据线SDA,一条时钟线SCL.   SDA传输数据是大端传输,每次传输8bit,即一字节.   支持多主控(multimastering),任何时间点只能 ...

  5. PAT之我要通过

    题目描述 “答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输 出“答案正确”,否则输出“答案错误”. 得到“答案正确”的 ...

  6. js制作倒计时效果

    该程序可以计算任意指定的两个日期中间的差值. 本例子的指定日期是2017年1月1日,当前时间是2016年10月21日:计算它们之间的差值,在网页上显示如图所示: 关键部分代码: var nowtime ...

  7. LeetCode题解-----Median of Two Sorted Arrays

    题目描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of t ...

  8. selenium如何解决window安全验证问题

    解决办法 IE浏览器: 1.使用autoit,捕捉到控件后,编写au3脚本,生成exe,然后java调用exe au3脚本 Dim $account = "username" Di ...

  9. OpenCV 之 数字图像

    1  数字图像 数字图像可看作一个数值矩阵, 其中的每个元素代表一个像素点,如下图所示: 2  存储 M行N列图像的存储位数: b = M * N * k   ( L=2k, l ∈ [0, L-1] ...

  10. codeforces 710E E. Generate a String(dp)

    题目链接: E. Generate a String time limit per test 2 seconds memory limit per test 512 megabytes input s ...