JavaScript继承学习笔记【新手必看】


Posted in Javascript onMay 10, 2016

JavaScript作为一个面向对象语言(JS是基于对象的),可以实现继承是必不可少的,但是由于本身并没有类的概念,所以不会像真正的面向对象编程语言通过类实现继承,但可以通过其他方法实现继承。实现继承的方法很多,下面就只是其中的几种。

一. 原型链继承

function Person() {  //被继承的函数叫做超类型(父类,基类)
      this.name='mumu';
      this.age='18';
    }
    
    Person.prototype.name='susu';//当属性名相同时需就近原则,先在实例里面查找,没找到再到原型里找
       
    function Worker(){ //继承的函数叫做子类型(子类,派生类)
      this.job='student';
    }

    Worker.prototype=new Person();//通过原型链继承,超类型实例化后的对象实例,赋值给子类的原型属性
    var p2=new Worker(); 

    console.log(p2.name);
    console.log(p2 instanceof Object);//ture 所有的构造函数都继承自Object

以上实现继承关键在于:Worker.prototype=new Person();  将Worker的原型成为Person的一个实例,通过原型链继承。

注意:在使用原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会中断关系而重写原型链。

原型链继承问题:

1.出现引用共享问题,他们还是共用一个空间,子类会影响父类

function Person() {  
      this.bodys=['eye','foot'];
    }
    
    function Worker(){ 
    }

    Worker.prototype=new Person();
    var p1=new Worker();
    p1.bodys.push('hand');
    var p2=new Worker(); 
    console.log(p1.bodys);
    console.log(p2.bodys);

JavaScript继承学习笔记【新手必看】

2.在创建子类型的实例时,不能像超类型的构造函数中传递参数。

那么如何解决原型链的两个问题呢?那就继续看下面的继承方式吧~

二. 借用构造函数继承(也叫对象冒充,伪造对象或经典继承)

function Person(name,age){
    this.name=name;
    this.age=age;
    this.bodys=['eye','foot'];
  }

  Person.prototype.showName=function(){
    console.log(this.name);
  }

  function Worker(name,age,job){
    Person.call(this,name,age);
    this.job=job;//子类添加属性
  }

  var p1=new Worker('mumu','18','学生'); 
  p1.bodys.push('hand') ;
  var p2=new Worker();

  console.log(p1.name);
  console.log(p2.bodys);
  console.log(p1.showName());

JavaScript继承学习笔记【新手必看】

简单分析下以上使用借用构造函数的原理:Person.call(this,name,age);这句代码调用父级构造函数,继承父级属性,使用call方法调用Person构造函数改变函数执行时候的this,  这里的this-> new出来的一个Worker对象  构造函数伪装方法:把Worker传给上面的Person。

当引用类型放在构造函数里面的时候就不会被共享,所以p2不受影响。

这里借用构造函数继承方式就解决了原型链不能传递参数以及引用类型共享的问题。

小知识:call()和apply()方法可以改变函数执行的作用域, 简言之就是改变函数中this指向的内容。

call()和apply()都接受两个参数:第一个是在其中运行函数的作用域,另一个是传递的参数。

call和apply的区别就是参数的不同.
call中的参数必须是一个个枚举出来的.
apply中的参数必须是数组或者是arguments对象

那么问题来了:为什么p1.showName()结果是错误的呢?----因为借用构造函数继承方式只能继承构造函数里的属性和方法。这里也就发现了借用构造函数的一个问题。

注意:由于把方法都放在构造函数里,每次我们实例化就会分配内存空间给它造成资源的浪费,所以一般我们都是把方法放在原型里,属性放在构造函数里。

借用构造函数继承问题:

因为借用构造函数只能继承构造函数里的属性和方法,在超类型的原型中定义的方法对子类而言是不可见的,所以就相当于没有了原型。结果所有的方法都只能在构造函数里定义,因此就没有函数复用了。

那么如何解决借用构造函数所产生的问题呢?那就要看下面这种继承方式了

三. 组合继承(伪经典继承)

function Person(name,age){
    this.name=name;
    this.age=age;
  }

  Person.prototype.showName=function(){
    console.log(this.name);
  }

  function Worker(name,age,job){
    Person.call(this,name,age);//借用构造函数
    this.job=job;
  }
  
  Worker.prototype=new Person();//原型链继承
  var p1=new Worker('mumu','18','学生'); 

  console.log(p1.age);
  p1.showName();

组合继承:将原型链与借用构造函数结合。

思路:通过使用原型链实现原型上的属性和方法继承,借用构造函数实现实例属性的继承

以上的例子Person.call(this,name,age);借用构造函数继承了属性

Worker.prototype=new Person();原型链继承了方法 , 避免了两者的缺点,融合了它们的优点,成为最常用的继承模式。

组合继承的问题:

调用两次超类型构造函数,一次是在创建子类型原型时,另一次是在子类型的构造函数内部。

要解决这个问题就要用到寄生组合式继承方式了。

四. 原型式继承

function object(proto) {
    function F() {}
    F.prototype = proto;
    return new F();
  }

  var person = {
    name: 'mumu',
    friends: ['xiaxia', 'susu']
  };

  var anotherPerson = object(person);
  anotherPerson.friends.push('wen');
  var yetAnotherPerson = object(person);
  anotherPerson.friends.push('tian');
  console.log(person.friends);//["xiaxia", "susu", "wen", "tian"]
console.log(anotherPerson.__proto__)//Object {name: "mumu", friends: Array[4]}

简单分析下:function object(proto)是一个临时中转函数,里面的参数proto表示将要传递进入的一个对象,F()构造函数是临时新建的对象,用来存储传递过来的对象,F.prototype = proto;将对象实例赋值给F构造函数的原型对象,最后返回传递过来的对象的对象实例。原型式继承还是会共享引用类型的属性。

五. 寄生式继承

//临时中转函数  
function object(proto) {
    function F() {}
    F.prototype = proto;
    return new F();
  }

  //寄生函数
  function create(proto){
    var f=object(proto);
    f.love=function(){
      return this.name;
    }
    return f;
  }

  var person = {
    name: 'mumu',
    friends: ['xiaxia', 'susu']
  };

  var anotherPerson = create(person);
  console.log(anotherPerson.love());寄生组合式继承

六. 寄生组合式继承

function object(proto) {
    function F() {}
    F.prototype = proto;
    return new F();
  }

  //寄生函数
  function create(Person,Worker){
    var f=object(Person.prototype);//创建对象
    f.constructor=Worker;//调整原型构造指针,增强对象
    Worker.prototype=f;//指定对象
  }
  
  function Person(name,age){
    this.name=name;
    this.age=age;
  }
  Person.prototype.showName=function(){
    console.log(this.name);
  }
  function Worker(name,age,job){
    Person.call(this,name,age);
    this.job=job;
  }
  
  create(Person,Worker);//寄生组合式继承
  var p1=new Person('mumu','18','学生');
p1.showName();

这种方法也是现在实现继承方法中最完美的,也是最理想的。

以上这篇JavaScript继承学习笔记【新手必看】就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基本jquery的控制tabs打开的数量的代码
Oct 17 Javascript
基于jquery完美拖拽,可返回拖动轨迹
Mar 29 Javascript
一种Javascript解释ajax返回的json的好方法(推荐)
Jun 02 Javascript
Jquery组件easyUi实现选项卡切换示例
Aug 23 Javascript
JS+HTML+CSS实现轮播效果
Nov 28 Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
Jan 18 Javascript
Node.js使用MySQL连接池的方法实例
Feb 11 Javascript
详解easyui 切换主题皮肤
Apr 04 Javascript
浅谈React Native 传参的几种方式(小结)
May 21 Javascript
Vue 3.0 前瞻Vue Function API新特性体验
Aug 12 Javascript
Vue项目实现换肤功能的一种方案分析
Aug 28 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
Nov 11 Javascript
实例讲解使用原生JavaScript处理AJAX请求的方法
May 10 #Javascript
深入剖析JavaScript:Object类型
May 10 #Javascript
JavaScript的React Web库的理念剖析及基础上手指南
May 10 #Javascript
快速解决Canvas.toDataURL 图片跨域的问题
May 10 #Javascript
jQuery事件的绑定、触发、及监听方法简单说明
May 10 #Javascript
网页前端登录js按Enter回车键实现登陆的两种方法
May 10 #Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【二】
May 10 #Javascript
You might like
PHP的SQL注入过程分析
2012/01/06 PHP
CodeIgniter模板引擎使用实例
2014/07/15 PHP
PHP模块memcached使用指南
2014/12/08 PHP
PHP程序员不应该忽略的3点
2015/10/09 PHP
JQuery扩展插件Validate 1 基本使用方法并打包下载
2011/09/05 Javascript
jquery遍历select元素(实例讲解)
2013/12/31 Javascript
JQuery中serialize()用法实例分析
2015/02/06 Javascript
jQuery使用after()方法在元素后面添加多项内容的方法
2015/03/26 Javascript
js微信扫描二维码登录网站技术原理
2016/12/01 Javascript
JS中静态页面实现微信分享功能
2017/02/06 Javascript
jQuery实现使用sort方法对json数据排序的方法
2018/04/17 jQuery
浅谈Webpack打包优化技巧
2018/06/12 Javascript
Vue 页面状态保持页面间数据传输的一种方法(推荐)
2018/11/01 Javascript
jquery-ui 进度条功能示例【测试可用】
2019/07/25 jQuery
VUE.js实现动态设置输入框disabled属性
2019/10/28 Javascript
JS中数组实现代码(倒序遍历数组,数组连接字符串)
2019/12/29 Javascript
vue实现简单学生信息管理
2020/05/30 Javascript
[55:35]DOTA2-DPC中国联赛 正赛 CDEC vs Dragon BO3 第二场 1月22日
2021/03/11 DOTA
python定时采集摄像头图像上传ftp服务器功能实现
2013/12/23 Python
Python中subprocess模块用法实例详解
2015/05/20 Python
用Python实现随机森林算法的示例
2017/08/24 Python
Python实现读取json文件到excel表
2017/11/18 Python
python制作mysql数据迁移脚本
2019/01/01 Python
解析Python的缩进规则的使用
2019/01/16 Python
对Python 中矩阵或者数组相减的法则详解
2019/08/26 Python
Django用户身份验证完成示例代码
2020/04/03 Python
Python引入多个模块及包的概念过程解析
2020/09/21 Python
Spy++的使用方法及下载教程
2021/01/29 Python
用html5的canvas画布绘制贝塞尔曲线完整代码
2013/08/14 HTML / CSS
天网面试题
2013/04/07 面试题
师范生自荐信
2013/10/27 职场文书
新闻编辑求职信
2014/07/13 职场文书
学校艾滋病宣传活动总结
2015/05/09 职场文书
乔布斯辞职信(中英文对照)
2015/05/12 职场文书
学校元旦晚会开场白
2015/05/29 职场文书
企业开发CSS命名BEM代码规范实践
2022/02/12 HTML / CSS