资讯专栏INFORMATION COLUMN

JavaScript原型与原型链

liaosilzu2007 / 1310人阅读

摘要:每个原型对象都有一个属性指向关联的构造函数为了验证这一说话,举个例子。

本文共 1475 字,读完只需 6 分钟
一、概述

在 JavaScript 中,是一种面向对象的程序设计语言,但是 JS 本身是没有 “类” 的概念,JS 是靠原型和原型链实现对象属性的继承。

在理解原型前,需要先知道对象的构造函数是什么,构造函数都有什么特点?

1. 构造函数

// 构造函数 Person()
function Person(name, gender) {
    this.name = name;
    this.gender = gender;
}

var person = new Person("周杰伦", "男");

// 最后创建出来的对象实例 person
person

{
    name: "周杰伦",
    gender: "男"
}

以上代码,普通函数 Person(),加上 new 关键字后,就构造了一个对象 person

所以构造函数的定义就是普通函数加上 new 关键字,并总会返回一个对象。

2. 函数对象
同时,JS 中的对象分为一般对象和函数对象。那什么是一般对象,什么又是函数对象呢?

JavaScript 的类型分为基本数据类型和引用数据类型,基本数据类型目前有 6 种(null, undefined, string, number, boolean, Symbol)。 其余的数据类型都统称为 object 数据类型,其中,包括 Array, Date, Function等,所以函数可以称为函数对象。

let foo = function(){

}
foo.name = "bar";
foo.age = 24;
console.log(foo instanceof Function)  //true
console.log(foo.age)  // 24

以上代码就说明了函数其实是一个对象,也可以具有属性。

二、原型链

JavaScript 中的对象,有一个特殊的 [[prototype]] 属性, 其实就是对于其他对象的引用(委托)。当我们在获取一个对象的属性时,如果这个对象上没有这个属性,那么 JS 会沿着对象的 [[prototype]]链 一层一层地去找,最后如果没找到就返回 undefined;

这条一层一层的查找属性的方式,就叫做原型链。

var o1 = {
    age: 6
}

那么,为什么一个对象要引用,或者说要委托另外一个对象来寻找属性呢?

本文开篇的第一句话,就指出来的,JavaScript 中,和一般的 OOP 语言不同,它没有 "类"的概念,也就没有 "模板" 来创建对象,而是通过字面量或者构造函数的方式直接创建对象。那么也就不存在所谓的类的复制继承。

三、原型

那什么又是原型呢?

既然我们没有类,就用其他的方式实现类的行为吧,看下面这句话↓↓。

1. 每个函数都有一个原型属性 prototype 对象

function Person() {

}

Person.prototype.name = "JayChou";

// person1 和 person2 都是空对象
var person1 = new Person();
var person2 = new Person();

console.log(person1.name) // JayChou
console.log(person2.name) // JayChou

通过构造函数创造的对象,对象在寻找 name 属性时,找到了 构造函数的 prototype 对象上。

这个构造函数的 prototype 对象,就是 原型

用示意图来表示:

查找对象实例属性时,会沿着原型链向上找,在现代浏览器中,标准让每个对象都有一个 __proto__ 属性,指向原型对象。那么,我们可以知道对象实例和函数原型对象之间的关系。

2. 每个原型对象都有一个 constructor 属性指向关联的构造函数

为了验证这一说话,举个例子。

function Person() {}

Person === Person.prototype.constructor; // true

那么对象实例是构造函数构造而来,那么对象实例是不是也应该有一个 constructor 呢?

function Person() {}

const person = new Person();
person.constructor === Person // true

但事实上,对象实例本身并没有 constructor 属性,对象实例的 constructor 属性来自于引用了原型对象的 constructor 属性

person.constructor === Person.prototype.constructor // true

3. 原型链顶层:Object.prototype.__proto__ == null

既然 JS 通过原型链查找属性,那么链的顶层是什么呢,答案就是 Object 对象,Object 对象其实也有 __proto__属性,比较特殊的是 Object.prototype.__proto__ 指向 null, 也就是空。

Object.prototype.__proto__ === null

我们回过头来看函数对象:

所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function)
Number.__proto__ === Function.prototype  // true
Number.constructor == Function //true

Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true

String.__proto__ === Function.prototype  // true
String.constructor == Function //true

// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Object.__proto__ === Function.prototype  // true
Object.constructor == Function // true

// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true

Array.__proto__ === Function.prototype   // true
Array.constructor == Function //true

RegExp.__proto__ === Function.prototype  // true
RegExp.constructor == Function //true

Error.__proto__ === Function.prototype   // true
Error.constructor == Function //true

Date.__proto__ === Function.prototype    // true
Date.constructor == Function //true
所有的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind

以图会友,这就是网上经常看到的 JS 原型和原型链关系图:

对于以上看似很复杂的关系图,只需要理解 5 点:

每个函数都有一个原型属性 prototype 对象

普通对象的构造函数是 Object(),所以 Person.prototype.__proto__ === Object.prototype

函数对象都来自于 Function.prototype

函数对象也是对象,所有 Function.prototype.__proto__ === Object.prototype

记住,所有函数的默认原型都是 Object() 的实例,所以,Function.prototype.__proto__ === Object.prototype

Object.prototype.__proto__ 是 null

总结

以上就是 JavaScript 中原型和原型链的知识。由于 JS 没有"类", 所以采用了原型的方式实现继承,正确的说法是引用或者委托,因为对象之间的关系不是复制,而是委托。在查找属性的时候,引用(委托)原型对象的属性,也就是我们常说的原型继承。

欢迎关注个人微信订阅号,专注分享原创文章

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

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

相关文章

  • javascript高级程序设计》笔记:原型图解

    摘要:不理解没关系,下面会结合图例分析上一篇高级程序设计笔记创建对象下一篇高级程序设计笔记继承参考之原型链的解读三张图搞懂的原型对象与原型链继承与原型链 文章直接从原型图解开始的,如果对一些概念不太清除,可以结合后面几节查看 1. 图解原型链 1.1 铁三角关系(重点) function Person() {}; var p = new Person(); showImg(https://s...

    vspiders 评论0 收藏0
  • JavaScript中的原型原型

    摘要:前言作为前端高频面试题之一,相信很多小伙伴都有遇到过这个问题。 前言 作为前端高频面试题之一,相信很多小伙伴都有遇到过这个问题。那么你是否清楚完整的了解它呢? 国际惯例,让我们先抛出问题: 什么是原型、原型链 它们有什么特点 它们能做什么 怎么确定它们的关系 或许你已经有答案,或许你开始有点疑惑,无论是 get 新技能或是简单的温习一次,让我们一起去探究一番吧 如果文章中有出现纰...

    laoLiueizo 评论0 收藏0
  • 进击JavaScript之(四)原型原型

    摘要:每一个由构造函数创建的对象都会默认的连接到该神秘对象上。在构造方法中也具有类似的功能,因此也称其为类实例与对象实例一般是指某一个构造函数创建出来的对象,我们称为构造函数的实例实例就是对象。表示该原型是与什么构造函数联系起来的。 本文您将看到以下内容: 传统构造函数的问题 一些相关概念 认识原型 构造、原型、实例三角结构图 对象的原型链 函数的构造函数Function 一句话说明什么...

    XBaron 评论0 收藏0
  • 继承原型

    摘要:既然构造函数有属于自己的原型对象,那么我们应该能让另一个构造函数来继承他的原型对象咯我们在构造函数内部执行了函数并改变了函数内部的指向其实这个指向的是实例化之后的对象。 我们在讨(mian)论(shi)JavaScript这门语言时,总是绕不过的一个话题就是继承与原型链。那么继承与原型链到底是什么呢? 我很喜欢的一个聊天模式是:我不能说XX是什么,我只能说XX像什么。也就是说我不直接跟...

    My_Oh_My 评论0 收藏0
  • JavaScript系列--浅析原型继承

    摘要:综上所述有原型链继承,构造函数继承经典继承,组合继承,寄生继承,寄生组合继承五种方法,寄生组合式继承,集寄生式继承和组合继承的优点于一身是实现基于类型继承的最有效方法。 一、前言 继承是面向对象(OOP)语言中的一个最为人津津乐道的概念。许多面对对象(OOP)语言都支持两种继承方式::接口继承 和 实现继承 。 接口继承只继承方法签名,而实现继承则继承实际的方法。由于js中方法没有签名...

    draveness 评论0 收藏0
  • 【5】JavaScript 函数高级——原型原型深入理解(图解)

    摘要:探索是如何判断的表达式如果函数的显式原型对象在对象的隐式原型链上,返回,否则返回是通过自己产生的实例案例案例重要注意的显示原型和隐式原型是一样的。面试题测试题测试题报错对照下图理解 原型与原型链深入理解(图解) 原型(prototype) 函数的 prototype 属性(图) 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象) 原型对象中有...

    马龙驹 评论0 收藏0

发表评论

0条评论

liaosilzu2007

|高级讲师

TA的文章

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