第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2

这篇具有很好参考价值的文章主要介绍了第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

书接上集,在上集中我们给出了一个需求说明,要求利用现学的知识实现原型(prototype)继承,并且我们给出了三种实现方式。但是这三种方式各自有优缺点,都不能很好的满足要求,那是否还有其他更好的实现方式呢?

在看本文之前,诸位可以自己思考下?带着问题去学习总是能够学到更多内容。在以后的岁月中,会找一些有意义的句子,与诸君共勉。

在时间的稿纸上,每个人都在写着自己的历史。当你抓着今天时,你就会前进一步,当你丢弃今天时,你就会停滞不动。

一、临时构造器方式

上集中,我们利用prototype方式实现继承,会带来一个问题:所有的属性都指向了一个相同的对象,父对象就会受到子对象属性的影响。

如何解决这个问题?

这时就必须利用某种中介来打破这种连锁关系。我们可以用一个临时的构造器函数来充当中介。即:我们创建一个空函数f(),并将其原型设置为父级构造器,然后我们既可以用new F()来创建一些不包含父对象属性的对象,同时又可以从父对象prototype中继承一切了。

1.1 代码实现

function Shape(){}
Shape.prototype.name = "Shape";
Shape.prototype.toString = function () {
    return this.name;
}
function TwoDShape(){}
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = "2D Shape";
function Triangle(side, height){
    this.side = side;
    this.height = height;
}
var F = function(){};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = "Triangle";
Triangle.prototype.getArea = function () {
    return this.side * this.height / 2;
}
var my = new Triangle(5, 10);
console.log(my.getArea());  //25
console.log(my.name);   //Triangle
console.log(my.toString()); //Triangle
var supers = new Shape();
console.log(supers.name);   //Shape 注意

1.2 代码分析

从下图中我们可以看出my 对象的结构

第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2,JavaScript,原型模式,javascript,开发语言,前端
那么这个时候toString() 方法查找分几步呢?

  • 在本类中查找
  • my对象的my.[[Prototype]] 中找,此时该[[Prototype]] 对象为TwoDShape的实例,里面只有一个name = "Triangele"属性。
  • my对象的my.[[Prototype]].[[Prototype]] 中找,为Shape的实例,同样里面也只有一个name="2D Shape" 属性
  • my.[[Prototype]].[[Prototype]].[[Prototype]] 中找,为Object实例,此时,就已经找到了 toString() 方法。

二. 增加uber属性,用于子对象访问父对象

2.1 实现分析

uber 属性的名字原本应该是“superclass”,但是这样一来显得JavaScript中有了类的概念(在ES6中引入了class),或许该叫super,但是superJavaScript的保留字,因为改成uber

  • 我们给构造函数增加一个uber属性,使其值为父类的原型Triangle.uber = TwoDShape.prototype;
  • 如下图所示,此时构造函数Triangle() 中,包含了uber属性
    第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2,JavaScript,原型模式,javascript,开发语言,前端

2.2 代码实现

function Shape(){}
Shape.prototype.name = "Shape";
Shape.prototype.toString = function () {
    var result = [];
    if(this.constructor.uber){
        result[result.length] = this.constructor.uber.toString();
    }
    result[result.length] = this.name;
    return result.join(', ');
}
function TwoDShape(){}
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.uber = Shape.prototype;   //增加uber属性,指向父类的原型
TwoDShape.prototype.name = "2D Shape";
function Triangle(side, height){
    this.side = side;
    this.height = height;
}
var F = function(){};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.uber = TwoDShape.prototype;
Triangle.prototype.name = "Triangle";
Triangle.prototype.getArea = function () {
    return this.side * this.height / 2;
}
var my = new Triangle(5, 10);
console.log(my.getArea());  //25
console.log(my.name);   //Triangle
console.log(my.toString()); //Shape, 2D Shape, Triangle
var supers = new Shape();
console.log(supers.name);   //Shape

三. 将继承封装成extend()函数

  • 为了代码的封装和重用,我们可以将实现继承的部分抽取出来,定义一个extend()函数。

3.1 代码实现

extend()相比,extend2() 显得略逊一筹。因为这里执行的是子对象原型的逐一拷贝,而非简单的原型链查询。所以我们必须要记住,这种方式仅适用于只包含基本数据类型的对象,所有的对象类型(包括函数和数组)都是不可复制的,因为他们只支持引用传递。

这里toString()方法实际上是同一个函数对象。这里只是一个函数引用,函数本身并没有再次被创建。

优缺点

  • extend2()方法的效率要低于extend()方法,主要是前者对部分原型属性进行了重建。
  • 当然了,这对于只包含基本数据类型的对象来说,是有好处的。因为这样做能使属性查找操作更多的停留在对象本身,从而减少了原型链上的查找。

3.1.1 临时构造器实现extend()

//定义extend函数
function extend(Child, Parent){
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;

}

3.1.2 原型复制实现extend2()

function extend2(Child, Parent){
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p){
        c[i] = p[i];
    }
    c.uber = p; //扩展子类原型,增加一个uber属性
}

3.2 代码测试

3.2.1 测试extend()函数

  • 利用上述extend() 函数实现继承。

//定义Shape类
function Shape(){}
Shape.prototype.name = "Shape";
Shape.prototype.toString = function () {
    return this.name;
}

//定义TwoDShape类
function TwoDShape(){}
extend(TwoDShape, Shape);
TwoDShape.prototype.name = "2D Shape";

//定义Triangle类
function Triangle(side, height){
    this.side = side;
    this.height = height;
}
extend(Triangle, TwoDShape);
Triangle.prototype.name = "Triangle";
Triangle.prototype.getArea = function () {
    return this.side * this.height / 2;
}

//测试
var my = new Triangle(5, 10);
console.log(my.getArea());  //25
console.log(my.name);   //Triangle
console.log(my.toString()); // Triangle
var supers = new Shape();
console.log(supers.name);   //Shape

3.2.1 测试extend2() 函数

//定义Shape类
function Shape(){}
Shape.prototype.name = "Shape";
Shape.prototype.toString = function () {
    return this.name;
}

//定义TwoDShape类
function TwoDShape(){}
extend(TwoDShape, Shape);

//extend测试结果
var td = new TwoDShape();
 console.log(td.name);   //Shape
 console.log(TwoDShape.prototype.name); //Shape
 console.log(td.__proto__.name); //Shape
 console.log(td.hasOwnProperty("name")); //false
 console.log(td.__proto__.hasOwnProperty("name"));   //false

//extend2测试结果
var td = new TwoDShape();
console.log(td.__proto__.hasOwnProperty("name"));   //true
console.log(td.__proto__.hasOwnProperty("toString"));   //true
console.log(td.__proto__.toString == Shape.prototype.toString); //true

四、实例对象原型继承:以实例对象为原型创建新对象

4.1 功能分析

基于这种在对象之间直接构建继承关系的理念,我们可以创建一个object()函数,接受父对象,并返回一个以该对象为原型的新对象。这和Object.create() 类似。如下代码所示:

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

如果需要访问父类,则可加添加uber属性。文章来源地址https://www.toymoban.com/news/detail-532800.html

function object(o){
    var n;
    var F = function(){};
    F.prototype = o;
    n = new F();
    n.uber = o;
    return n;
}

4.2 功能测试

//定义Shape类
 function Shape(){}
 Shape.prototype.name = "Shape";
 Shape.prototype.toString2 = function () {
     return this.name;
 }
 
 var shapeObj = new Shape();
 var twoDShape = object(shapeObj);
 twoDShape.name = "HHH"
 console.log(twoDShape.toString2()); //HHH
  • twoDShape 对象的结构如下所示
    第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2,JavaScript,原型模式,javascript,开发语言,前端

到了这里,关于第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • javascript中的prototype;javascript中的原型链

    在JavaScript中,每个对象都有一个原型(prototype),并且原型可以有自己的原型,形成了一个链式结构,被称为原型链。这个机制是JavaScript中实现继承和对象属性查找的基础。 原型链是由对象之间的连接构成的。每个对象都有一个指向它原型的链接,这个链接可以追溯到顶层

    2024年02月20日
    浏览(42)
  • 什么是原型链(Prototype Chain)?它在JavaScript中有什么作用?请解释一下JavaScript中的“this”关键字的含义和用法。

    原型链(Prototype Chain)是一种在JavaScript中创建对象的方式,它允许我们通过继承来扩展对象的属性和方法。 在原型链中,每个对象都有一个原型对象(也称为“原型”或“ proto ”),该对象继承了其父对象的属性和方法。当我们在一个对象上定义一个属性或方法时,如果该

    2024年02月11日
    浏览(58)
  • 什么是JavaScript中的类(Class)和继承(Inheritance)?它们与原型链继承相比有哪些优缺点?

    JavaScript中的类(Class)和继承(Inheritance)是面向对象编程的重要概念。类是一种抽象的概念,它定义了一组属性和方法,并且这些属性和方法可以在同一组对象中重复使用。继承是类之间的层次关系,其中一个类继承了另一个类的属性和方法,从而能够共享其代码和行为。 在Ja

    2024年02月12日
    浏览(58)
  • 设计模式之原型模式Prototype的C++实现

    1、原型模式提出 在软件功能设计中,经常面临着“某些结构复杂的对象”的创建工作,且创建的对象想拥有其他对象在某一刻的状态,则可以使用原型模型。原型模型是通过拷贝构造函数来创建对象,并且该对象拥有其他对象在某一刻的状态。 2、需求描述 设计产品A,B,这

    2024年02月12日
    浏览(42)
  • SAP Fiori开发中的JavaScript基础知识15 - 原型,object,constructor,class,继承

    本文将介绍JavaScript中的核心概念 - 原型,并会介绍基于原型的应用场景object,constructor,class,继承。 本文会将这几个核心概念汇总在一篇博客中,因为这些概念是触类旁通的,希望对你有帮助。 在JavaScript中,几乎所有的东西都是对象,每个对象都有一个 特殊的内部属性

    2024年04月23日
    浏览(121)
  • 【设计模式——学习笔记】23种设计模式——原型模式Prototype(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    原型模式指用通过拷贝原型实例创建新的实例,新实例和原型实例的属性完全一致 原型模式是一种创建型设计模式 工作原理是通过调用原型实例的 clone() 方法来完成克隆,原型实例需要实现Cloneable接口,并重写 clone() 方法 需要为每个类开发一个克隆方法,这对全新的类来说

    2024年02月16日
    浏览(52)
  • JavaScript中手动实现Array.prototype.map方法

    在前端开发中,我们经常需要对数组进行操作和处理。在JavaScript中,数组是常用的数据类型之一。而数组的map方法可以将一个数组中的每个元素都进行某种操作,并返回一个新的数组。今天,我们就来手动实现JavaScript中数组原型的map方法。 首先,让我们回顾一下map方法的基

    2024年02月21日
    浏览(41)
  • 原型模式(Prototype)

    原型模式是一种创建型设计模式,使调用方能够复制已有对象,而又无需使代码依赖它们所属的类。当有一个类的实例(原型),并且想通过复制原型来创建新对象时,通常会使用原型模式。 原型模式包含如下角色: Prototype,原型类,用来声明克隆方法。在绝大多数情况下

    2024年02月14日
    浏览(44)
  • 原型模式(Prototype Pattern)

    原型模式(Prototype Pattern)结构较为简单,它是一种特殊的创建型模式, 当需要创建大量相同或者相似对象时 ,可以 通过对一个已有对象的复制获取更多对象 。Java语言提供了较为简单的原型模式解决方案,只需要创建一个原型对象,然后通过在类中定义的克隆方法复制自己

    2024年02月03日
    浏览(40)
  • 原型模式(Prototype Pattern)

    原型模式(Prototype Pattern)是一种创建型设计模式,它用于通过复制现有对象来创建新对象,而无需依赖显式的构造函数。 在原型模式中,我们创建一个原型对象,并通过复制该原型对象来创建新的对象。这样做的好处是,我们可以避免创建对象时的复杂实例化过程,而是通

    2024年02月15日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包