详解JavaScript原型与原型链


Posted in Javascript onNovember 16, 2020

正如一些面向对象语言中所实现的那样,在JavaScript中我们有时也需要创建一个拥有公共函数与属性的类作为父类来减少代码重复、实现类型检查与实现更加清晰地代码结构。在JavaScript中,继承是通过原型链实现的。了解JavaScript的继承与原型链之前首先需要了解JavaScript中对象创建的方式。

在JavaScript中创建对象

JavaScript中对象创建的方式有两种:工厂方法(Factory Functions)、构造器方法(Constructor Functions) 。

工厂方法

工厂方法在编程领域是一个非类或构造器的返回对象的方法。在JavaScript中,任何返回不使用new关键词创建对象的方法都是工厂方法。

function person(firstName, lastName, age) {
 const person = {};
 person.firstName = firstName;
 person.lastName = lastName;
 person.age = age;
 return person;
}

构造器方法

构造器方法和工厂方法的区别仅在用例和命名规范上。命名规范上一个构造器方法的名字开头字母需要大写,我们需要通过new关键词来调用构造器方法生成实例。这个实例之后便可以通过instanceof关键词来检查。

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

new的行为

当同时在工厂方法和构造器方法上使用new关键词创建时,工厂方法创建出的对象的__proto__属性指向Object.prototype,构造器方法创建出的对象的__proto__属性指向本身的Xxx.prototype。

const mike = new person('mike', 'grand', 23);

mike.__proto__	// Object.prototype
const jack = new Person('jack', 'grand', 23);

jack.__proto__	// Person.protytype这里的prototype指向Person的Prototype Object
jack.__proto__.__proto__	// Object.prototype

new关键词在后台为构造器方法执行了以下几步

  1. 在构造器方法内创建一个新对象并将其赋值到this上
  2. 设置对象的[[Prototype]]和__proto__为原型的构造函数,这一步也让新对象的构造函数在构造新对象时被添加到原型链上
  3. 如果这个方法内没有返回object、function或array类型的结果,就返回this
  4. 如果这个方法内没有返回任何值则返回this

下面是一个展示new关键词在JavaScript引擎当中执行效果的伪代码,注释当中的是用来示范new关键词添加语句的伪代码

function Person(firstName, lastName, age) {
 // this = {};
 // this.__proto__ = Person.prototype;
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // return this;
}

在构造器方法上没有返回值所以后台创建的this将被返回,而工厂方法内由于返回了对象所以后台不再添加return this自然返回的内容将不一致。

如果没有在构造器方法前使用new关键词,而将构造器方法直接调用执行,其仅作为一个方法来被执行而非构造器。

const bob = Person('bob', 'grand', 23);
bob	// undefined. 因为这里Person当作方法直接调用了且没有返回值
window.firstName	// bob. 函数内的this将指向全局作用域,导致意外操作

继承与原型链

原型

原型(Prototype)可以认为是一个JavaScript方法的属性,每次在JavaScript代码中创建方法时,JavaScript引擎会将一个名为prototype的属性添加上去,这个prototype属性是一个对象(原型对象),这个对象默认有一个constructor属性指向原方法对象。任何添加到prototype的属性和方法都在这个对象里面,所有该类实例共享这个原型对象,实例对象的__proto__属性指向这个对象,方法的prototype属性指向这个对象。

在ECMAScript的标准里object.[[Prototype]]是访问原型的方法,但在ECMAScript 2015中用Object.getPrototypeOf()和Object.setPrototypeOf()来替代。等价的__proto__是多数浏览器使用的事实上的但是非标准的实现。

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

Person.prototype === Person.prototype.constructor.prototype	// 指向Person的原型对象
Person.prototype.constructor === Person	// 指向Person方法对象

let bob = new Person("Bob", "Ross", 21);
Person.prototype === bob.__proto__;	// true

let alex = new Person("Alex", "Wang", 21);
Person.prototype === alex.__proto__;	// true
alex.__proto__ === bob.__proto__;	// true

原型链

首先我们需要了解对象查找机制。当我们使用一个对象的属性时,JavaScript引擎会首先查找本对象里是否有对应属性,如果没有则去对象的原型里查找属性,如果没有则去对象的原型对象的原型对象里查找属性,直至查询到对象的__proto__为null的时候停止。

详解JavaScript原型与原型链

const obj = {};
console.log(obj);	// [object Object]	obj的toString()方法从Object的原型中查找到并使用

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // 在Person.prototype上定义了toString覆写了Object.prototype上的toString
 Person.prototype.toString = function() {
  return `${this.firstName} It Is`;
 }
}

let bob = new Person("Bob", "Ross", 21);
let alex = new Person("Alex", "Wang", 21);
console.log(bob);	// Bob It Is
console.log(alex);	// Alex It Is

以上就是详解JavaScript原型与原型链的详细内容,更多关于JavaScript原型与原型链的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript实现重置表单(reset)的方法
Apr 02 Javascript
JavaScript使用二分查找算法在数组中查找数据的方法
Apr 07 Javascript
JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解
May 31 Javascript
Javascript中的数组常用方法解析
Jun 17 Javascript
AngularJS实现用户登录状态判断的方法(Model添加拦截过滤器,路由增加限制)
Dec 12 Javascript
详解Vuejs2.0 如何利用proxyTable实现跨域请求
Aug 03 Javascript
Three.js基础学习教程
Nov 16 Javascript
基于vue+canvas的excel-like组件实例详解
Nov 28 Javascript
微信小程序实战篇之购物车的实现代码示例
Nov 30 Javascript
Node 搭建一个静态资源服务器的实现
May 20 Javascript
JavaScript常用8种数组去重代码实例
Sep 09 Javascript
vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)
Mar 01 Vue.js
详解JavaScript执行模型
Nov 16 #Javascript
Vue 实现拨打电话操作
Nov 16 #Javascript
微信小程序实现页面左右滑动
Nov 16 #Javascript
Vertx基于EventBus发送接受自定义对象
Nov 16 #Javascript
vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能
Nov 16 #Javascript
angular8.5集成TinyMce5的使用和详细配置(推荐)
Nov 16 #Javascript
js实现纯前端压缩图片
Nov 16 #Javascript
You might like
PHP新手上路(十二)
2006/10/09 PHP
兼容FireFox 的 js 日历 支持时间的获取
2009/03/04 Javascript
js 获取(接收)地址栏参数值的方法
2013/04/01 Javascript
使用js检测浏览器的实现代码
2013/05/14 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
jQuery中:first-child选择器用法实例
2014/12/31 Javascript
jQuery实现的产品自动360度旋转展示特效源码分享
2015/08/21 Javascript
论Bootstrap3和Foundation5网格系统的异同
2016/05/16 Javascript
bootstrap table实现点击翻页功能 可记录上下页选中的行
2017/09/28 Javascript
JavaScript分步实现一个出生日期的正则表达式
2018/03/22 Javascript
Angular使用过滤器uppercase/lowercase实现字母大小写转换功能示例
2018/03/27 Javascript
原生JS实现简单的倒计时功能示例
2018/08/30 Javascript
详解Vue项目在其他电脑npm run dev运行报错的解决方法
2018/10/29 Javascript
jQuery实现表格的增、删、改操作示例
2019/01/27 jQuery
使用vue2.6实现抖音【时间轮盘】屏保效果附源码
2019/04/24 Javascript
Node.js 的 GC 机制详解
2019/06/03 Javascript
iview实现图片上传功能
2020/06/29 Javascript
Vue实现省市区三级联动
2020/12/27 Vue.js
python用来获得图片exif信息的库实例分析
2015/03/16 Python
Python中字典创建、遍历、添加等实用操作技巧合集
2015/06/02 Python
python 数据的清理行为实例详解
2017/07/12 Python
Python+selenium实现截图图片并保存截取的图片
2018/01/05 Python
Python模块WSGI使用详解
2018/02/02 Python
PyGame贪吃蛇的实现代码示例
2018/11/21 Python
Python正则匹配判断手机号是否合法的方法
2020/12/09 Python
python读取几个G的csv文件方法
2019/01/07 Python
Python3转换html到pdf的不同解决方案
2019/03/11 Python
Python爬虫实现vip电影下载的示例代码
2020/04/20 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
2020/06/23 Python
医生自荐信
2013/10/11 职场文书
模具设计与制造专业应届生求职信
2013/10/18 职场文书
技能比赛获奖感言
2014/02/14 职场文书
春节联欢会主持词
2014/03/24 职场文书
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
MySQL分区路径子分区再分区
2022/04/13 MySQL
MySQL数据库中的锁、解锁以及删除事务
2022/05/06 MySQL