详解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 相关文章推荐
对联广告js flash激活
Oct 19 Javascript
如何让动态插入的javascript脚本代码跑起来。
Jan 09 Javascript
jQuery的.live()和.die() 使用介绍
Sep 10 Javascript
node在两个div之间移动,用ztree实现
Mar 06 Javascript
探讨JQUERY JSON的反序列化类 using问题的解决方法
Dec 19 Javascript
JavaScript实现可拖拽的拖动层Div实例
Aug 05 Javascript
jQuery on()方法示例及jquery on()方法的优点
Aug 27 Javascript
jQuery animate和CSS3相结合实现缓动追逐效果附源码下载
Apr 18 Javascript
Bootstrap基本样式学习笔记之图片(6)
Dec 07 Javascript
jquery.tableSort.js表格排序插件使用方法详解
Aug 12 Javascript
BootStrap的双日历时间控件使用
Jul 25 Javascript
node puppeteer(headless chrome)实现网站登录
May 09 Javascript
详解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
法兰绒滤网冲泡
2021/03/03 冲泡冲煮
用PHP与XML联手进行网站编程代码实例
2008/07/10 PHP
域名和cookie问题(域名后缀)
2012/10/10 PHP
php 批量生成html,txt文件的实现代码
2013/06/26 PHP
PHP中把数据库查询结果输出为json格式简单实例
2015/04/09 PHP
详解WordPress中添加和执行动作的函数使用方法
2015/12/29 PHP
php设计模式之建造器模式分析【星际争霸游戏案例】
2020/01/23 PHP
JavaScript splice()方法详解
2020/09/22 Javascript
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
2014/01/08 Javascript
jquery实现页面常用的返回顶部效果
2016/03/04 Javascript
详解js数组的完全随机排列算法
2016/12/16 Javascript
原生JS仿QQ阅读点击展开、收起效果
2017/03/08 Javascript
微信jssdk逻辑在vue中的运用详解
2018/11/14 Javascript
vue计算属性computed的使用方法示例
2019/03/13 Javascript
Layui数据表格判断编辑输入的值,是否为我需要的类型详解
2019/10/26 Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
2020/03/14 Javascript
vue-router之解决addRoutes使用遇到的坑
2020/07/19 Javascript
vue+element_ui上传文件,并传递额外参数操作
2020/12/05 Vue.js
python根据文件大小打log日志
2014/10/09 Python
简单介绍利用TK在Python下进行GUI编程的教程
2015/04/13 Python
浅析Python中yield关键词的作用与用法
2016/11/29 Python
python中reader的next用法
2018/07/24 Python
解决Python找不到ssl模块问题 No module named _ssl的方法
2019/04/29 Python
python实现爬取百度图片的方法示例
2019/07/06 Python
pycharm 设置项目的根目录教程
2020/02/12 Python
python编程进阶之异常处理用法实例分析
2020/02/21 Python
python实现坦克大战
2020/04/24 Python
html5新特性与用法大全
2018/09/13 HTML / CSS
canvas绘制太极图的实现示例
2020/04/29 HTML / CSS
HQhair美国/加拿大:英国化妆品、美容及美发产品商城
2019/04/15 全球购物
暑假家长评语大全
2014/04/17 职场文书
中华在我心中演讲稿
2014/09/13 职场文书
2014年安全管理工作总结
2014/12/01 职场文书
2014年度个人总结范文
2015/03/09 职场文书
如何利用Matlab制作一款真正的拼图小游戏
2021/05/11 Python
【海涛DOTA】D-cup邀请赛NV.cn vs DT.Love
2022/04/01 DOTA