javascript 原型与原型链的理解及应用实例分析


Posted in Javascript onFebruary 10, 2020

本文实例讲述了javascript 原型与原型链的理解及应用。分享给大家供大家参考,具体如下:

javascript中一切皆对象,但是由于没有Class类的概念,所以就无法很好的表达对象与对象之间的关系了。

比如对象A与对象B之间,它们两个是相对独立的个体,互不干扰,对象A修改自身的属性不会影响到对象B。

虽然这很好,但是有一个问题,如果对象A与对象B都有一个方法 run() ,并且代码也一样,那对象A与对象B各自都独立拥有一份 run() 方法的完整代码,这是需要资源去保存的。

一旦我们程序中应用的对象过多,那这种资源消耗会是巨大的。那有没有一种方法可以让对象A与对象B拥有一些公共的属性和方法,让它们之前有某种联系?

我们设想一下,会不会存在一个 common对象(公共对象),common对象上保存着公共的属性和方法,而对象A与对象B里面有一个prototype属性指向这个 common对象,

当然我们调用对象A或对象B的属性和方法时,如果在自身对象中没有找到,就去prototype这个属性指向的对象上面去找。

而common对象本身也有一个prototype属性指向更上一级的common对象,然后一直往上找啊找,直到为null,就停止。

这种不断的从下往上找的这种路径,就像链条一样,我们称它为 原型链,而那个common对象,我们称它为 原型对象。

我们来看一个构造函数

function Base(name) {
  this.name = name;
}
let A = new Base('A');
let B = new Base('B');
//每一个函数都有一个prototype属性,指向该函数的原型对象
console.log(Base.prototype);
//当然原型对象也是一个对象,它也有一个constructor,指向构造函数
console.log(Base.prototype.constructor === Base);
//每一个实例对象的constructor都指向创建它们的构造函数
console.log(A.constructor === Base);
console.log(B.constructor === Base);
//每一个实例对象都有一个__proto__属性,该属性指向构造函数的原型对象
console.log(A.__proto__ === Base.prototype);
console.log(B.__proto__ === Base.prototype);

1、每一个函数都有一个prototype属性,它指向该函数的原型对象。

2、原型对象也是对象,它也有自已的constructor,它指向构造函数Base()。换句话说,其实原型对象也是构造函数Base()的一个实例。只不过比较特殊,用来存放公共属性和方法的。

3、每一个通过构造函数Base()创建的实例对象,都有一个constructor,指向创建它们的构造函数。

4、每一个对象,都有一个 __proto__ 属性,指向构造函数Base()的 原型对象。换句话说,__proto__ 是将 原型 串联起来形成链条的关键。不然对象A与对象B都无法找到原型对象上的公共属性和方法。

function Base(name) {
  this.name = name;
}
//我们在原型对象上添加公共属性
Base.prototype.status = '开始';
//我们在原型对象上添加公共方法
Base.prototype.run = function() {
  console.log(this.name + ' run ...');
};
let A = new Base('A');
let B = new Base('B');
A.run();
B.run();
console.log(A.status);
console.log(B.status);
//修改原型上的属性,则实例对象也会跟着改变
Base.prototype.status = '停止';
console.log(A.status);
console.log(B.status);

通过原型与原型链,让对象与对象之间有了关联关系。

那如何通过原型与原型链,让一个构造函数继承于另一个构造函数?

比如,我们要让构造函数Child 继承于 构造函数Base,只需要让 Child 的 prototype 指向 Base的 原型对象,不就可以了?

function Base(name) {
}
Base.prototype.name = 'Base';
Base.prototype.run = function () {
  console.log(this.name + ' run ...');
};
function Child() {
}
Child.prototype = Base.prototype;
//注意这个时候,Child.prototype对象的constructor属性指向了Base
//这就导致通过构造函数Child创建的实例对象,对象的constructor属性会指向Base,而不是Child,这会导致混乱。
//所以我们重新设置Child.prototype.constructor指向Child
Child.prototype.constructor = Child;
let c = new Child();
console.log(c.name);
c.run();

这样有一个问题,Child.prototype 与 Base.prototype 指向同一个原型对象,任何对 Child.prototype 的修改都会反应到 Base.prototype 上面。

这时,Base.prototype.constructor 指向了 Child,这显然是有问题。

我们只能通过一个中间的空构造函数,来完成原型的指向。

function Base(name) {
}
Base.prototype.name = 'Base';
Base.prototype.run = function () {
  console.log(this.name + ' run ...');
};
function Child() {
}
//创建一个中间的空构造函数
function Mid() {
}
//让该空构造函数的prototype指向Base的原型对象
Mid.prototype = Base.prototype;
//再让Child的prototype指向该空构造函数的一个实例
Child.prototype = new Mid();
//这样,当修改Child.prototype.constructor时,Base.prototype就不会受影响了
Child.prototype.constructor = Child;
let c = new Child();
console.log(c.name);
c.run();
//Base.prototype的constructor仍然指向Base,没有受到影响
console.log(Base.prototype.constructor);

那怎么通过原型与原型链,让你一对象继承于另一个对象呢?

比如,我们要让对象B继承于对象A,无非就是想要拿到对象A的属性和方法,这么一想,那通过把对象B的 __proto__  指向 对象A,不就可以实现了?

let A = {
  name: 'A',
  run() {
    console.log(this.name + ' run ...');
  }
};
console.log(A.name);
A.run();
let B = {};
//让对象B的__proto__指向对象A
B.__proto__ = A;
//当对象B调用run()方法时会在自身上找,如果没找到,则通过__proto__向上找
//由于__proto__指向对象A,所以最终会在对象A中找到run()方法
B.run();
B.__proto__.name = 'B';
console.log(A.name);
console.log(B.name);

这样有一个问题,当修改 B.__proto__.name = 'B'; 时,对象A也会受到影响。

我们可以通过ES5提供的 Object.create() 来解决此问题,Object.create()可以通过指定的 原型对象 创建一个新对象。

let A = {
  name: 'A',
  run() {
    console.log(this.name + ' run ...');
  }
};
console.log(A.name);
A.run();
let B = {};
//通过Object.create()创建一个以对象A为原型对象的新对象
//让对象B的__proto__指向该新对象
//这样再操作B.__proto__中的属性就与对象A无关了。
B.__proto__ = Object.create(A);
B.run();
B.__proto__.name = 'B';
console.log(A.name);
console.log(B.name);

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript查找算法技巧总结》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
动态创建样式表在各浏览器中的差异测试代码
Sep 13 Javascript
jquery选择器之层级过滤选择器详解
Jan 27 Javascript
node.js中的fs.writeSync方法使用说明
Dec 15 Javascript
jQuery制作简洁的图片轮播效果
Apr 03 Javascript
jQuery实现带滚动导航效果的全屏滚动相册实例
Jun 19 Javascript
JavaScript原生xmlHttp与jquery的ajax方法json数据格式实例
Dec 04 Javascript
Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
Dec 30 Javascript
JS实现对中文字符串进行utf-8的Base64编码的方法(使其与Java编码相同)
Jun 21 Javascript
pm2 部署 node的三种方法示例
Oct 20 Javascript
Vue路由切换时的左滑和右滑效果示例
May 29 Javascript
JQuery属性操作与循环用法示例
May 15 jQuery
layer.js open 隐藏滚动条的例子
Sep 05 Javascript
在 Vue 中使用 JSX 及使用它的原因浅析
Feb 10 #Javascript
node.js使用http模块创建服务器和客户端完整示例
Feb 10 #Javascript
webpack打包优化的几个方法总结
Feb 10 #Javascript
JS+HTML5本地存储Localstorage实现注册登录及验证功能示例
Feb 10 #Javascript
node.js制作一个简单的登录拦截器
Feb 10 #Javascript
使用 Vue-TCB 快速在 Vue 应用中接入云开发的方法
Feb 10 #Javascript
jQuery实现简易QQ聊天框
Feb 10 #jQuery
You might like
打造计数器DIY三步曲(中)
2006/10/09 PHP
php中fsockopen用法实例
2015/01/05 PHP
PHP远程调试之XDEBUG
2015/12/29 PHP
WordPress开发中的get_post_custom()函数使用解析
2016/01/04 PHP
微信公众平台DEMO(PHP)
2016/05/04 PHP
全面解析PHP面向对象的三大特征
2017/06/10 PHP
ThinkPHP删除栏目(实现批量删除栏目)
2017/06/21 PHP
JQueryiframe页面操作父页面中的元素与方法(实例讲解)
2013/11/19 Javascript
javascript中setTimeout的问题解决方法
2014/05/08 Javascript
jQuery实现响应浏览器缩放大小并改变背景颜色
2014/10/31 Javascript
jquery实现点击向下展开菜单项(伸缩导航)效果
2015/08/22 Javascript
基于javascript实现精确到毫秒的倒计时限时抢购
2016/04/17 Javascript
jquery ajaxfileupload异步上传插件使用详解
2017/02/08 Javascript
使用jQuery的load方法设计动态加载及解决被加载页面js失效问题
2017/03/01 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
layui table设置某一行的字体颜色方法
2019/09/05 Javascript
[01:05]DOTA2完美大师赛趣味视频之选手教你打职业
2017/11/23 DOTA
Python导出数据到Excel可读取的CSV文件的方法
2015/05/12 Python
Python中matplotlib中文乱码解决办法
2017/05/12 Python
在Pycharm中对代码进行注释和缩进的方法详解
2019/01/20 Python
对PyQt5中的菜单栏和工具栏实例详解
2019/06/20 Python
Pandas中DataFrame的分组/分割/合并的实现
2019/07/16 Python
python动态视频下载器的实现方法
2019/09/16 Python
PyQt5中QTableWidget如何弹出菜单的示例代码
2020/02/23 Python
Python基于wordcloud及jieba实现中国地图词云图
2020/06/09 Python
在终端启动Python时报错的解决方案
2020/11/20 Python
设计师家具购买和委托在线市场:Viyet
2016/11/16 全球购物
护士自我鉴定怎么写
2014/02/07 职场文书
党员学习中共十八大思想报告
2014/09/12 职场文书
张家口市高新区党工委群众路线教育实践活动整改方案
2014/10/25 职场文书
2016入党积极分子党课培训心得体会
2016/01/06 职场文书
python函数指定默认值的实例讲解
2021/03/29 Python
详解MySQL中的主键与事务
2021/05/27 MySQL
一次项目中Thinkphp绕过禁用函数的实战记录
2021/11/17 PHP
分享几个实用的CSS代码块
2022/06/10 HTML / CSS
输入框跟随文字内容适配宽实现示例
2022/08/14 Javascript