当前位置: 代码网 > it编程>编程语言>Javascript > 一文搞懂JavaScript中原型与原型链

一文搞懂JavaScript中原型与原型链

2024年05月18日 Javascript 我要评论
前言js中的原型与原型链应该是老生常谈的话题了,在前端面试中基本都是必问的一个问题,但是很多人还是稀里糊涂的,只知道其表层含义,一但面试官问深一点就支支吾吾了(我自己)。为了自己下次能在面试中&quo

前言

js中的原型与原型链应该是老生常谈的话题了,在前端面试中基本都是必问的一个问题,但是很多人还是稀里糊涂的,只知道其表层含义,一但面试官问深一点就支支吾吾了(我自己)。为了自己下次能在面试中"装b",肝了一夜,特此记录一下,加深印象,也希望能帮到有需要的小伙伴。

先来看一张图↓

相信第一眼看到这个图的人,都觉得很繁琐,不想看了,其实你耐心的看完这篇文章就会觉得不过如此。这种图真的特别有用、特别有用、特别有用,重要的事情说三遍,那我们开始吧。

构造函数创建对象

我们先用一个构造函数来创建一个对象

function person() {

}
var person = new person();
person.name = 'kevin';
console.log(person.name) // kevin

这个例子就是用person构造函数new了一个实例对象person,这个就不用多说了吧。

prototype

每个函数都有一个prototype属性,不信的话,你可以随便找个函数,打开f12都能看到。(注意:prototype是函数特有的属性)

function person() {

}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
person.prototype.name = 'kevin';
var person1 = new person();
var person2 = new person();
console.log(person1.name) // kevin
console.log(person2.name) // kevin

那这个函数的 prototype 属性到底指向的是什么呢?是这个函数的原型吗?

其实,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1 和 person2 的原型。那什么是原型呢?你可以这样理解:每一个javascript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。让我们用一张图表示构造函数和实例原型之间的关系:

在这张图中我们用person.prototype表示实例原型。

那么我们该怎么表示实例与实例原型,也就是 person 和 person.prototype 之间的关系呢,这时候我们就要讲到第二个属性:

__proto__

为了证明每一个javascript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型这句话的真实性,我们可以用个例子来证实。

function person() {

}
var person = new person();
console.log(person.__proto__ === person.prototype); // true

既然这样,我们来更新一下关系图:

既然实例对象和构造函数都可以指向原型,那原型中是否有属性可以指向实例或者说是构造函数呢?

首先我们可以排除原型是没有属性指向实例的,因为一个构造函数可以new多个实例。

constructor

主要是讲下原型中的constructor,每个原型都有一个constructor属性指向构造函数。老规矩,可以在浏览器验证一下。

function person() {

}
console.log(person === person.prototype.constructor); // true

得到下面的关系图:

从上面的关系图以及举的例子,我们来梳理总结一下:

function person() {

}

var person = new person();

console.log(person.__proto__ == person.prototype) // true
console.log(person.prototype.constructor == person) // true
// 顺便学习一个es5的方法,可以获得对象的原型
console.log(object.getprototypeof(person) === person.prototype) // true

了解完了构造函数、实例、实例原型之间的关系,我们来讲下实例与原型是怎么样一个关系呢?

实例与原型

当读取上面的实例的属性,找不到的时候,会发生什么呢?如果找不到的话,就会查找与实例相关联的原型的属性中查找,如果还是找不到就会去原型的原型中查找,一直找到最顶层为止。

function person() {

}

person.prototype.name = 'kevin';

var person = new person();

person.name = 'daisy';
console.log(person.name) // daisy

delete person.name;
console.log(person.name) // kevin

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 daisy。

但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.__proto__ ,也就是 person.prototype中查找,幸运的是我们找到了 name 属性,结果为 kevin。

但是万一还没有找到呢?原型的原型又是什么呢?

其实原型对象就是通过 object 构造函数生成的,结合之前所讲,实例的 __proto__ 指向构造函数的 prototype ,所以我们再更新下关系图:

原型链

那 object.prototype 的原型呢?null,我们可以打印:

console.log(object.prototype.__proto__ === null) // true

所以object.prototype.__proto__ 的值为 null 跟 object.prototype 没有原型,其实表达了一个意思。

所以查找属性的时候查到 object.prototype 就可以停止查找了。

到此就分析完了,蓝色的这条线其实就是原型链。

总结

这里有几个点需要注意一下:

constructor

首先是 constructor 属性,我们看个例子:

function person() {

}
var person = new person();
console.log(person.constructor === person); // true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === person.prototype.constructor

_proto_

其次是 __proto__ ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 person.prototype 中,实际上,它是来自于 object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto__ 时,可以理解成返回了 object.getprototypeof(obj)。

到此这篇关于一文搞懂javascript中原型与原型链的文章就介绍到这了,更多相关javascript原型 原型链内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

  • ASP.NET中的Razor语法简介

    ASP.NET中的Razor语法简介

    razor 不是一种编程语言。它是服务器端的标记语言。可以让您将基于服务器的代码(visual basic 和 c#)嵌入到网页中。当服务器读取页面时,它首先运... [阅读全文]
  • JavaScript中的运算符讲解

    JavaScript中的运算符讲解

    一、javascript 算术运算符算数运算符用于对数字执行算数运算:+:加法-:减法*:乘法/:除法%:系数++:递加--:递减加法运算符(+)对数字相加:v... [阅读全文]
  • TypeScript中的装饰器用法

    TypeScript中的装饰器用法

    一、装饰器装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩... [阅读全文]
  • JavaScript中变量的用法

    JavaScript中变量的用法

    一、javascript 变量变量可以使用短名称(比如 x 和 y),也可以使用描述性更好的名称(比如 age, sum, totalvolume)。变量必须以... [阅读全文]
  • js中值类型和引用类型的区别介绍

    js中值类型和引用类型的区别介绍

    1.javascript中的变量类型有哪些?(1)值类型(基本类型):字符串(string)、数值(number)、布尔值(boolean)、undefined... [阅读全文]
  • ES6基础语法之模块化介绍

    ES6基础语法之模块化介绍

    es6 引入了模块化, es6 的模块化分为导出(export) @与导入(import)两个模块。es6模块化特点:(1)es6 的模块自动开启严格模式,不管... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com