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 相关文章推荐
Input 特殊事件onpopertychange和oninput
Jun 17 Javascript
js 兼容多浏览器的回车和鼠标焦点事件代码(IE6/7/8,firefox,chrome)
Apr 14 Javascript
动态的9*9乘法表效果的实现代码
May 16 Javascript
如何用js实现鼠标向上滚动时浮动导航
Jul 18 Javascript
JS实现touch 点击滑动轮播实例代码
Jan 19 Javascript
浅谈原生JS中的延迟脚本和异步脚本
Jul 12 Javascript
JS实现前端页面的搜索功能
Jun 12 Javascript
详解Vue项目部署遇到的问题及解决方案
Jan 11 Javascript
Vue 中可以定义组件模版的几种方式
Aug 06 Javascript
JavaScript 装逼指南(js另类写法)
May 10 Javascript
使用 UniApp 实现小程序的微信登录功能
Jun 09 Javascript
如何基于jQuery实现五角星评分
Sep 02 jQuery
实例讲解使用原生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 无限级分类,超级简单的无限级分类,支持输出树状图
2014/06/29 PHP
Laravel5.5 数据库迁移:创建表与修改表示例
2019/10/23 PHP
ExtJS下grid的一些属性说明
2009/12/13 Javascript
jquery下利用jsonp跨域访问实现方法
2010/07/29 Javascript
javascript里模拟sleep(两种实现方式)
2013/01/25 Javascript
S2SH整合JQuery+Ajax实现登录验证功能实现代码
2013/01/30 Javascript
jquery无刷新验证邮箱地址实现实例
2014/02/19 Javascript
js实现鼠标悬浮给图片加边框的方法
2015/01/30 Javascript
深入理解JavaScript编程中的原型概念
2015/06/25 Javascript
js实现拉幕效果的广告代码
2015/09/02 Javascript
JavaScript如何禁止Backspace键
2015/12/02 Javascript
jQuery Mobile开发中日期插件Mobiscroll使用说明
2016/03/02 Javascript
CascadeView级联组件实现思路详解(分离思想和单链表)
2016/04/12 Javascript
node.js 和HTML5开发本地桌面应用程序
2016/12/13 Javascript
React.js绑定this的5种方法(小结)
2018/06/05 Javascript
vue如何引入sass全局变量
2018/06/28 Javascript
详解React 服务端渲染方案完美的解决方案
2018/12/14 Javascript
详解Vue前端生产环境发布配置实战篇
2019/05/07 Javascript
JS拖动选择table里的单元格完整实例【基于jQuery】
2019/05/28 jQuery
vue+Element实现搜索关键字高亮功能
2019/05/28 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
[05:36]DOTA2 2015国际邀请赛中国区预选赛第四日TOP10
2015/05/29 DOTA
Python初学时购物车程序练习实例(推荐)
2017/08/08 Python
flask-socketio实现WebSocket的方法
2018/07/31 Python
python的继承知识点总结
2018/12/10 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
Python selenium文件上传下载功能代码实例
2020/04/13 Python
纽约的奢华内衣店:Journelle
2016/07/29 全球购物
毕业生优秀推荐信
2013/11/26 职场文书
租房协议书范本
2014/04/09 职场文书
硕士研究生就业推荐信
2014/05/18 职场文书
教师党员个人自我剖析材料
2014/09/29 职场文书
保研推荐信格式
2015/03/25 职场文书
专职安全员岗位职责
2015/04/11 职场文书
CSS3 制作的悬停缩放特效
2021/04/13 HTML / CSS
laravel添加角色和模糊搜索功能的实现代码
2021/06/22 PHP