资讯专栏INFORMATION COLUMN

探索 proto & prototype 与继承之间的关系

dockerclub / 3569人阅读

摘要:而和的存在就是为了建立这种子类与父类间的联系。创建一个基本对象建立新对象与原型我把它理解为类之间的连接执行构造函数小结可以理解为类,也就是存储一类事物的基本信息。原型原型链和继承之间的关系。

原型 原型的背景

首先,你应该知道javascript是一门面向对象语言。

是对象,就具有继承性。

继承性,就是子类自动共享父类的数据结构和方法机制。

而prototype 和 __proto__ 的存在就是为了建立这种子类与父类间的联系。

我们将prototype称作原型,将通过__proto__来建立起来的对象与对象的关系称作原型链。

下面,通过创建一个简单对象,来探索原型和原型链到底是什么。

原型与原型链

首先,创建一个最简单的对象

function Foo(){}
var o = new Foo();

ps:这是刚从java转入JavaScript时,最令我费解的一段代码,凭什么一个function就可以用来创建一个对象。下面就是new 关键字的分解动作。。。这个关键字究竟做了什么,能创建一个对象。。

这个创建的过程,可以分解成下面代码

  function Foo(){}
 // 创建一个基本对象
 var o = new Object();
 // 创建对象和父类原型之间的链接 
 o.__proto__ = Foo.prototype;
 // 执行构造函数
 Foo.call(o); 

为了更好的理解这段代码,我们先理解这几个概念

什么是构造函数constructor

构造函数就是对象创建时,自动调用的方法

prototype

prototype,长这样

{
    constructor: f foo()
    __proto__: Object
}

它是一个对象,存储着一类事物的基本信息,所以可以将它称作类。

__proto__

__proto__,这个属性用来建立对象和类之间的关系。

有了这些概念,我们来分析创建对象的过程中,究竟做了些什么.
创建一个对象,会做如下三件事。

创建一个基本对象 new Object()

建立新对象与原型(我把它理解为类)之间的连接

执行构造函数

小结:prototype可以理解为类,也就是存储一类事物的基本信息。__proto__可以理解为一条线索,用来建立原型(类)和对象之间的关系。

原型、原型链和继承之间的关系。

继承,需要满足如下三个要求。

子类继承父类的成员变量

子类继承父类的方法

子类继承父类的构造器,如果父类的构造函数带有参数,那么子类中应该显示调用

我们该如何实现继承呢?

// 创建一个构造函数,我认为 a.prototype就是父类对象。
function a(x,y) {
    a.prototype.x = x;
    a.prototype.y = y
}
// 为父类对象添加一个method 
a.prototype.console = function() {
    console.log(this.x);
    console.log(this.y);
}
//创建子类构造函数
function b(x,y) {
    // 子类显示的调用父类构造方法
    a.call(this,x,y);
}
// 子类继承父类的成员变量以及父类的方法
b.prototype = Object.create(a.prototype); = b.prototype.constructor = b;
// 创建对象
var c = new b(1,2);
 // 这里Object.create 是用来创建一个新的prototype,用来记录新类的信息,并与父类建立联系
 Object.create = function() {
  //创建一个基本对象
  var temp = new Object();
  //与父类的的原型建立联系
  temp.__proto__ = proto;
  //返回新类的原型
  return temp;
 }

小结:继承关系的实现,做了如下两件事情

子类显示的调用父类的构造函数

子类通过原型来与父类建立联系,从而能让子类拥有父类的成员变量和方法。

原型就是类,原型链就是来建立子类和父类之间的联系。

原型链的实际表现

先创建一个类

function people() {}
// 为父类对象添加一个method
people.prototype.run = function() {
   console.log("I am running");
}

通过类来创建一个对象

var p = new people();
p.run();
// i am running

这里p对象长这样

{
__proto__: Object
}

很显然,这个对象之中并没有run方法。

但是它却能调用run,因为它会通过__proto__(原型链)来寻找类中的方法。

经常有人这么问proto 和prototype有什么区别?

我想看到这里,你应该很明白了。

prototype 一个存储类信息的对象,只存在function中.(下图中绿块)

proto 单纯是对象用来指向上级的一链接。(看下图黄线)

那么又有人会问function中__proto__又是什么关系呢?

function 本身是对象,所以当然也有自己原型。function继承于Function.(看下图蓝线)。

下面介绍一下原型继承和类继承的关系。

原型继承和类继

An example that shows the difference between creating a JavaScript class and subclass in ES5 and ES6.

ES5

"use strict";

/**
 * Shape class.
 * 
 * @constructor
 * @param {String} id - The id.
 * @param {Number} x  - The x coordinate.
 * @param {Number} y  - The y coordinate.
 */
function Shape(id, x, y) {
    this.id = id;
    this.setLocation(x, y);
}

/**
 * Set shape location.
 * 
 * @param {Number} - The x coordinate.
 * @param {Number} - The y coordinate.
 */
Shape.prototype.setLocation = function(x, y) {
    this.x = x;
    this.y = y;
};

/**
 * Get shape location.
 * 
 * @return {Object}
 */
Shape.prototype.getLocation = function() {
    return {
        x: this.x,
        y: this.y
    };
};

/**
 * Get shape description.
 * 
 * @return {String}
 */
Shape.prototype.toString = function() {
    return "Shape("" + this.id + "")";
};

/**
 * Circle class.
 * 
 * @constructor
 * @param {String} id     - The id.
 * @param {Number} x      - The x coordinate.
 * @param {Number} y      - The y coordinate.
 * @param {Number} radius - The radius.
 */
function Circle(id, x, y, radius) {
    Shape.call(this, id, x, y);
    this.radius = radius;
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

/**
 * Get circle description.
 * 
 * @return {String}
 */
Circle.prototype.toString = function() {
    return "Circle > " + Shape.prototype.toString.call(this);
};

// test the classes
var myCircle = new Circle("mycircleid", 100, 200, 50); // create new instance
console.log(myCircle.toString()); // Circle > Shape("mycircleid")
console.log(myCircle.getLocation()); // { x: 100, y: 200 }

ES6

"use strict";

/**
 * Shape class.
 * 
 * @constructor
 * @param {String} id - The id.
 * @param {Number} x  - The x coordinate.
 * @param {Number} y  - The y coordinate.
 */
class Shape(id, x, y) {
    constructor(id, x, y) { // constructor syntactic sugar
        this.id = id;
        this.setLocation(x, y);
    }
    
    /**
     * Set shape location.
     * 
     * @param {Number} - The x coordinate.
     * @param {Number} - The y coordinate.
     */
    setLocation(x, y) { // prototype function
        this.x = x;
        this.y = y;
    }
    
    /**
     * Get shape location.
     * 
     * @return {Object}
     */
    getLocation() {
        return {
            x: this.x,
            y: this.y
        };
    }
    
    /**
     * Get shape description.
     * 
     * @return {String}
     */
    toString() {
        return `Shape("${this.id}")`;
    }
}

/**
 * Circle class.
 * 
 * @constructor
 * @param {String} id     - The id.
 * @param {Number} x      - The x coordinate.
 * @param {Number} y      - The y coordinate.
 * @param {Number} radius - The radius.
 */
function Circle extends Shape {
    constructor(id, x, y, radius) {
        super(id, x, y); // call Shape"s constructor via super
        this.radius = radius;
    }
    
    /**
     * Get circle description.
     * 
     * @return {String}
     */
    toString() { // override Shape"s toString
        return `Circle > ${super.toString()}`; // call `super` instead of `this` to access parent
    }
}

// test the classes
var myCircle = new Circle("mycircleid", 100, 200, 50); // create new instance
console.log(myCircle.toString()); // Circle > Shape("mycircleid")
console.log(myCircle.getLocation()); // { x: 100, y: 200 }

这段代码,自己体会。。。。

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

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

相关文章

  • 一张图让自己搞懂(mēng)原型&原型链

    摘要:要搞清这三种关系指向之间的关系拗口,其实也就是要搞懂,构造函数由构造函数操作创造出的实例对象和构造函数的原型对象之间的关系。 写在前面 这篇博客来源于,有天mentor突然传给我了这张祖传的图片,并且发誓一定要给我讲清楚,然鹅在他的一番激情讲解之后,他自己也被绕懵了...于是后来我决定整理一下似乎还有点清晰的思路,记录一下我对这张图的理解。作为一个小白,对于js中这些比较复杂的概念的理...

    CntChen 评论0 收藏0
  • JS之继承(ES5 & ES6)

    摘要:继承可以使得子类具有父类别的各种属性和方法。继承是类与类之间的关系。继承的实质就是两次的原型搜索,像是实例属性而不是继承,才是继承。更多用法见继承。 前言 面试中最常会问到的问题:什么是继承?如何分别用 ES5 和 ES6 实现?想要学习继承,必须先学好原型与原型链,如果此部分还不清楚,请先学习此部分再来阅读本文,可参考我的文章JS之原型与原型链或浏览其他相关的学习网站。 定义 继承...

    antyiwei 评论0 收藏0
  • 汇总有关JS对象创建继承

      之前也有和大家讲过有关JS的对象创建和对象继承,本篇文章主要为大家做个汇总和梳理。  JS中其实就是原型链继承和构造函数继承的毛病,还有就是工厂、构造、原型设计模式与JS继承。 JS高级程序设计4:class继承的重点,不只是简简单单的语法而已。  对象创建  不难发现,每一篇都离不开工厂、构造、原型这3种设计模式中的至少其一!  那JS为什么非要用到这种3种设计模式了呢??  我们先从对...

    3403771864 评论0 收藏0
  • 《你不知道javascript》笔记_对象&原型

    摘要:上一篇你不知道的笔记写在前面这是年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响年是向上的一年在新的城市稳定连续坚持健身三个月早睡早起游戏时间大大缩减,学会生活。 上一篇:《你不知道的javascript》笔记_this 写在前面 这是2019年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响2018年是向上的一年:在新的城市稳定、...

    seasonley 评论0 收藏0
  • ES6 class继承super关键词深入探索

    摘要:请看对应版本干了什么可知,相当于以前在构造函数里的行为。这种写法会与上文中写法有何区别我们在环境下运行一下,看看这两种构造函数的有何区别打印结果打印结果结合上文中关于原型的论述,仔细品味这两者的差别,最好手动尝试一下。 ES6 class 在ES6版本之前,JavaScript语言并没有传统面向对象语言的class写法,ES6发布之后,Babel迅速跟进,广大开发者也很快喜欢上ES6带...

    jubincn 评论0 收藏0

发表评论

0条评论

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