资讯专栏INFORMATION COLUMN

JavaScript实现继承

kamushin233 / 941人阅读

摘要:以下内容均基于本人对高级程序设计第三版小节的理解先看一下父类私有受保护成员,只允许在父类的构造函数中赋值公有成员引用类型的成员构造函数中的方法,打印一些基本信息原型中的方法,将构造函数中的非函数成员以格式打印方式一原型链继承实现方式子类的原

以下内容均基于本人对《JavaScript高级程序设计》第三版6.3小节的理解

先看一下父类
function Animal(name) {
    var name = name;             //"私有(受保护)"成员,只允许在父类的构造函数中赋值
    this.food = undefined;       //"公有"成员

    //引用类型的成员
    this.birthday = {            
      year: undefined
    };

    //构造函数中的方法,打印一些基本信息
    this.greeting = function() {
      console.log("Hi, my name is {" + name + "} I like eat {" + this.food + "} and my birth year is {" + this.birthday.year + "}");
    };

    //原型中的方法,将构造函数中的非函数成员以JSON格式打印
    Animal.prototype.briefInfo = function() {
      var brief = {
        name: name,
        food: this.food,
        birthday: this.birthday
      };
      console.log(JSON.stringify(brief));
    };
  }
方式一:原型链继承

实现方式:子类的原型指向父类的实例

子类:

function Dog() {}
Dog.prototype = new Animal();        //原型指向父类的实例

测试:

var dog1 = new Dog();
dog1.food = "shit";
dog1.birthday.year = 2015;

var dog2 = new Dog();
dog2.food = "bones";
dog2.birthday.year = 2016;

dog1.greeting();  //console: Hi, my name is {undefined} I like eat {shit} and my birth year is {2016}
dog2.greeting();  //console: Hi, my name is {undefined} I like eat {bones} and my birth year is {2016}

dog1.briefInfo();  //console: {"food":"shit","birthday":{"year":2016}}
dog2.briefInfo();  //console: {"food":"bones","birthday":{"year":2016}}

//以上,
//birthday是引用类型的属性,所以dog1的birthday.year被dog2覆盖了;
//无法给dog1和dog2的name赋值

存在的问题:

引用类型的对象会被子类的所有实例共享(1.1)

无法在创建子类的实例时,给父类的构造函数传递参数(1.2)

方式二:借用构造函数(伪造对象、经典继承)

实现方式:在子类的构造函数中利用call(或者apply)方法执行父类构造函数(问题1.2解决),将执行对象设为子类的this,相当于把父类构造函数中的成员拷贝了一份到子类(问题1.1解决)

子类

function Dog(name) {
  Animal.call(this, name);
}

测试

var dog1 = new Dog("tom");
dog1.food = "shit";
dog1.birthday.year = 2015;

var dog2 = new Dog("mike");
dog2.food = "bones";
dog2.birthday.year = 2016;

dog1.greeting();  //console: Hi, my name is {tom} I like eat {shit} and my birth year is {2015}
dog2.greeting();  //console: Hi, my name is {mike} I like eat {bones} and my birth year is {2016}

//briefInfo是父类原型中的属性,并没有被继承,以下语句会报错
dog1.briefInfo();  //error: dog1.briefInfo is not a function
dog2.briefInfo();  //error: dog2.briefInfo is not a function 

存在的问题:

父类原型中定义的属性无法被继承

综合方式一方式二,一种很明显的方式呼之欲出了:

方式三:组合继承

实现方式:结合原型链继承和经典继承

子类

function Dog(name) {
  Animal.call(this, name);    //经典继承
}
Dog.prototype = new Animal();    //原型链继承

测试

var dog1 = new Dog("tom");
dog1.food = "shit";
dog1.birthday.year = 2015;

var dog2 = new Dog("mike");
dog2.food = "bones";
dog2.birthday.year = 2016;

dog1.greeting();  //console: Hi, my name is {tom} I like eat {shit} and my birth year is {2015}
dog2.greeting();  //console: Hi, my name is {mike} I like eat {bones} and my birth year is {2016}
dog1.briefInfo();  //console: {"name":"tom","food":"shit","birthday":{"year":2015}}
dog2.briefInfo();  //console: {"name":"mike","food":"bones","birthday":{"year":2016}}

//终于得到了预期的结果,算是较好的实现了继承。
//但是,并不完美

存在的问题

父类的构造函数被调用了两次

为了引出下一个继承方式,先将函数的继承放在一边,看一下js中对象的继承

(摘抄原文)

1. 原型式继承

var person = {
  name: "martin"
  firend: ["bob", "steven"]
};
  
function object(o) {
  function F() {};
  F.prototype = o;
  return new F();
}
var anotherPerson = object(person);    //antherPerson继承了person

2. 寄生式继承

function createAnother(original) {
  var clone = object(original);    //原型式继承定义的方法
  //扩展对象
  clone.sayHi = function() {
    console.log("hi");
  }
  return clone;
}

回到正题,接下来介绍一颗 “银弹”

方式四:寄生组合式继承

实现方式:

利用经典继承拷贝父类构造中的属性到子类

利用原型式继承创建一个继承父类原型的对象

将该对象的constructor属性指向子类的构造函数(寄生式继承:扩展对象)

将子类的prototype指向该对象

子类

function Dog(name) {
  Animal.call(this, name);
}

function F() {}
var supProto = Animal.prototype;
F.prototype = supProto;
var subProto = new F();
subProto.constructor = Dog;
Dog.prototype = subProto;

测试

var dog1 = new Dog("tom");
dog1.food = "shit";
dog1.birthday.year = 2015;

var dog2 = new Dog("mike");
dog2.food = "bones";
dog2.birthday.year = 2016;

dog1.greeting();   //console: Hi, my name is {tom} I like eat {shit} and my birth year is {2015}
dog2.greeting();   //console: Hi, my name is {mike} I like eat {bones} and my birth year is {2016}
dog1.briefInfo();  //console: {"name":"tom","food":"shit","birthday":{"year":2015}}
dog2.briefInfo();  //console: {"name":"mike","food":"bones","birthday":{"year":2016}}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79731.html

相关文章

  • 讲清楚之 javascript 对象继承

    摘要:中的继承并不是明确规定的,而是通过模仿实现的。继承中的继承又称模拟类继承。将函数抽离到全局对象中,函数内部直接通过作用域链查找函数。这种范式编程是基于作用域链,与前面讲的继承是基于原型链的本质区别是属性查找方式的不同。 这一节梳理对象的继承。 我们主要使用继承来实现代码的抽象和代码的复用,在应用层实现功能的封装。 javascript 的对象继承方式真的是百花齐放,属性继承、原型继承、...

    Jonathan Shieber 评论0 收藏0
  • javascript继承你了解多少?

    摘要:和构造函数前面提到,是个内置隐藏属性,虽然在可以通过访问,但是其设计本意是不可被读取和修改的,那么我们如何利用原型链来建立继承关系提供了关键字。到这儿,思路就清晰了,怎么让对象和对象的相连实现继承只需把的构造函数的连接到就行了。 什么是继承? 大多数人使用继承不外乎是为了获得这两点好处,代码的抽象和代码的复用。代码的抽象就不用说了,交通工具和汽车这类的例子数不胜数,在传统的OO语言中(...

    baishancloud 评论0 收藏0
  • 理解JavaScript的核心知识点:原型

    摘要:首先,需要来理清一些基础的计算机编程概念编程哲学与设计模式计算机编程理念源自于对现实抽象的哲学思考,面向对象编程是其一种思维方式,与它并驾齐驱的是另外两种思路过程式和函数式编程。 JavaScript 中的原型机制一直以来都被众多开发者(包括本人)低估甚至忽视了,这是因为绝大多数人没有想要深刻理解这个机制的内涵,以及越来越多的开发者缺乏计算机编程相关的基础知识。对于这样的开发者来说 J...

    iKcamp 评论0 收藏0
  • JavaScript中的继承

    摘要:前言作为中最重要的内容之一,继承问题一直是我们关注的重点。如果一个类别继承自另一个类别,就把这个称为的子类,而把称为的父类别也可以称是的超类。 前言 作为 JavaScript 中最重要的内容之一,继承问题一直是我们关注的重点。那么你是否清晰地知道它的原理以及各种实现方式呢 阅读这篇文章,你将知道: 什么是继承 实现继承有哪几种方式 它们各有什么特点 这里默认你已经清楚的知道构造函...

    guyan0319 评论0 收藏0
  • javascript继承 --- 多种继承方式解析(ES5)

    摘要:继承前言作为一门轻量级的脚本语言在和的横空出世之后将其推向的新的高度虽然中出现的新的生成对象的类语法格式但依然为的语法糖而我们依然有必要从的原生实现入手来了解它的继承实现方式给出了更加简洁的固定的类声明方式有兴趣的可以查看阮一峰的入门下面给 javascript继承 前言 javascript作为一门轻量级的脚本语言在ES6和node.js的横空出世之后将其推向的新的高度,虽然 ES6...

    yankeys 评论0 收藏0

发表评论

0条评论

kamushin233

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<