原型污染和猴子补丁 Prototype Pollution and Monkey-Patching,monkeypatching

本文主要是介绍原型污染和猴子补丁 Prototype Pollution and Monkey-Patching,monkeypatching,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自文章 http://www.bkjia.com/webzh/974992.html


上两篇介绍了原型对象和原型链:

JavaScript对象创建模式:http://blog.csdn.net/hongse_zxl/article/details/44595809

深入理解JavaScript的原型对象 :http://blog.csdn.net/hongse_zxl/article/details/44622997

原型对象是JavaScript模拟类并实现继承的灵魂。这一篇介绍两个典型的问题:原型污染和猴子补丁

原型污染 Prototype Pollution

先看个例子:

function Person() { }               //先定义个空函数(空函数也有对应的原型对象)//原型对象中声明两个方法,一个count,一个otherFunc
Person.prototype.count = function() {  //count方法统计原型对象中有多少个属性和方法var i = 0;for (var prop in this) { i++; }return i;
};
Person.prototype.otherFunc  = function() { };  //随便定义个空方法,起名叫otherFuncvar p = new Person();
p.name = "Jack";      //为对象添加两个属性name和age
p.age = 32;alert(p.count());     //4

有了前两篇的基础,应该能明白为何最后结果为4,而不是2。对象p有两个属性name和age,而Person是个空函数,预想应该返回2才对。但实际结果返回了4,枚举时将对象属性(name,age)和原型对象中的方法(count,otherFunc)都算进去了。这就是原型污染。

原型污染是指当枚举条目时,可能会导致出现一些在原型对象中不期望出现的属性和方法。

上面这个例子只是抛砖引玉引出原型污染的概念,并不具备太多现实意义,一个更现实的例子:

var book = new Array();
book.name = "Love in the Time of Cholera";  //《霍乱时期的爱情》看完后整个人生都在里面
book.author = "Garcia Marquez";             //加西亚马尔克斯著。另推荐《百年孤独》,永远的马孔多
book.date = "1985";alert(book.name);   //Love in the Time of Cholera
定义个Array对象,用于管理书本。结果很正确,看似没什么问题,但这个代码很脆弱,一不小心就会遇到原型污染的问题:
//为Array增加两个方法,first和last(猴子补丁后面会介绍)
Array.prototype.first = function() {  //获取第一个return this[0]; 
};
Array.prototype.last = function() {   //获取最后一个return this[this.length-1];
};var bookAttributes = [];  //定义个book的属性的数组
for (var v in book) {     //将上面创建的Array对象book中属性一个个取出来,加入数组中bookAttributes.push(v);
}
alert(bookAttributes);    //name,author,date,first,last
我们定义了个book对象,里面有name书名,author作者,date出版日这3个属性。通过枚举将3个属性加入到bookAttributes数组中后,发现不仅这3个属性,连Array的原型对象中的方法也被加入到了数组中了,这不是我们希望看到的

你可以用hasOwnProperty方法,来测试属性是否来自对象而非来自原型对象:

var bookAttributes = [];
for (var v in book) { if(dict.hasOwnProperty(v)){  //为每个属性加上hasOwnProperty的测试bookAttributes.push(v);  //只有对象自身的属性才会被加入数组}
}
alert(bookAttributes);    //name,author,date
当然更好的方式应该是仅仅将Object的直接实例作为字典,而非Array,或Object的子类(如上述Person,函数本身也是Object):
var book = {};      //等价于var book = new Object(),不是new Array() 
book.name = "Love in the Time of Cholera";
book.author = "Garcia Marquez";
book.date = "1985";var bookAttributes = [];
for (var v in book) { bookAttributes.push(v);
}alert(bookAttributes);     // name,author,date 这样就避免了原型污染

当然你可能疑惑:仍旧可以像在Array.prototype中加入猴子补丁一样,在Object.prototype中增加属性,这样不还是会导致原型污染吗?确实如此,但Object对象是JavaScript的根对象,即便技术上能够实现,你也永远不要对Object对象做任何修改。

如果你是做业务项目,上述这些已经足以让你避免原型污染问题了。不过如果你要开发通用的库,还需要考虑些额外的问题。

比如,你的库中提供has方法,能判断对像中是否有该属性(非来自原型对象的属性),你可能这么做:

function Book(elements) {this.elements = elements || {};
}
Book.prototype.has = function(key) {return this.elements.hasOwnProperty(key);
};var b = new Book({name : "Love in the Time of Cholera",author : "García Márquez",date : "1985"
});
alert(b.has("author"));  //true
alert(b.has("has"));     //false
你在Book的原型对象中添加了has方法,判断传入的属性是否是对象自身的属性,如果是,返回true,如果不是(比如来自原型对象的属性)则返回false。结果表明author来自对象,因此返回了true,而has来自原型对象,因此返回了false。

一切都很完美,但万一有人在对象中有一个自定义的同名的hasOwnProperty属性,这将覆盖掉ES5提供的Object.hasOwnProperty。当然你会认为绝不可能有人会将一个属性起名为hasOwnProperty。但作为通用接口,你最好不做任何假设,可以用call方法改进:

Book.prototype.has = function(key) {return {}.hasOwnProperty.call(this.elements, key);
};
运行结果和改进前一样,没有任何区别,但现在就算有人在对象中定义了同名的hasOwnProperty属性,has方法内仍旧会正确调用ES5提供的Object.hasOwnProperty方法。

猴子补丁 Monkey-Patching

猴子补丁的吸引力在于方便,数组缺少一个有用的方法?加一个就是了:

Array.prototype.split = function(i) { return [this.slice(0, i), this.slice(i)];
};
环境太旧,不支持ES5中Array的新方法如forEach,map,filter?加上就是了:
if (typeof Array.prototype.map !== "function") {  //确保如存在的话,它不被覆盖Array.prototype.map = function(f, thisArg) {var result = [];for (var i = 0, n = this.length; i < n; i++) {result[i] = f.call(thisArg, this[i], i);}return result;};
}
但是当多个库给同一原型打猴子补丁时会出现问题,如项目中依赖的另一个库也有个Array的split方法,但和上面的实现不同:
Array.prototype.split = function() {var i = Math.floor(this.length / 2);return [this.slice(0, i), this.slice(i)];
};
现在对Array调用split方法会有50%的几率出错,这取决于哪个库哪个版本先被加载(假设它们之间没有依赖的先后顺序)被调用。
解决方案是,将想要的版本封装起来:
function addArrayMethods() {Array.prototype.split = function(i) {return [this.slice(0, i), this.slice(i)];};
};
需要调用split方法时,改为调用封装函数可以避免错误。

这篇关于原型污染和猴子补丁 Prototype Pollution and Monkey-Patching,monkeypatching的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1052703

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

PMP–一、二、三模–分类–14.敏捷–技巧–原型MVP

文章目录 技巧一模14.敏捷--原型法--项目生命周期--迭代型生命周期,通过连续的原型或概念验证来改进产品或成果。每个新的原型都能带来新的干系人新的反馈和团队见解。题目中明确提到需要反馈,因此原型法比较好用。23、 [单选] 一个敏捷团队的任务是开发一款机器人。项目经理希望确保在机器人被实际建造之前,团队能够收到关于需求的早期反馈并相应地调整设计。项目经理应该使用以下哪一项来实现这个目标?

Axure元件库Ant Design中后台原型模板:提升设计与开发效率的利器

企业对于中后台产品的设计与开发需求日益增长。为了提升用户体验和开发效率,设计者和开发者们不断寻求更加高效、统一的解决方案。Ant Design,作为阿里巴巴开源的一套企业级UI设计语言和React组件库,凭借其丰富的组件和统一的设计风格,已成为众多项目的首选。而在Axure中使用Ant Design元件库,更是为中后台产品的原型设计带来了极大的便利。 Ant Design简介 Ant D

基于11GR2的PSU补丁安装

基于11GR2的PSU补丁安装   场景:hp-unix新装数据库11.2.0.4.0,为了便于在线上触发此版本的一些bug而导致停机来维护,在安装后,应用MOS上提供最新的PSU补丁, 操作:利用OPatch工具来打GI和ORACLE软件的PSU 操作系统版本: $ uname -a HP-UX dbsrv B.11.31 U ia64 3837480657unlimited-use

《GOF设计模式》—原型(Prototype)—Delphi源码示例:原型接口

 示例:原型接口 说明: (1)、定义 用原型实例指定要创建对象的种类,并且通过拷贝这些原型实例创建新的同类对象。 (2)、结构 原型 Prototype:抽象原型,声明一个克隆自身的接口。 ConcretePrototype:具体原型,实现一个克隆自身的操作。 客户端 Client:让一个原型克隆自身从而创建一个新的对象。 代码: unit uProtot

《GOF设计模式》—原型(Prototype)—Delphi源码示例:浅拷贝和深拷贝

 示例:浅拷贝和深拷贝 说明: Prototype模式最困难的部分在于正确实现Clone操作。例如,当所考虑的类已经存在时就难以新增Clone操作。当类内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能会很困难。 大多数语言都对克隆对象提供了一些支持。例如,Smalltalk提供了一个copy的实现,它被所有Object的子类所继承。C++提供了一个拷贝构造器。但这些措施并不

【办公效率】Axure会议室预订小程序原型图,含PRD需求文档和竞品分析

作品说明 作品页数:共50+页 兼容版本:Axure RP 8/9/10 应用领域:中小型企业的会议室在线预订 作品申明:页面内容仅用于功能演示,无实际功能 作品特色 本作品为会议室预订小程序原型图,定位于拥有中大型组织架构的企业、办公楼、园区等群体,为其提供简易化的线上会议室管理的服务。 本作品从业务分析、竞品分析、用例图、原型设计,到需求清单,依照(敏捷开发)标准实战流程输出一套

Win 11补丁让AMD成亲儿子,性能最高提升35%

前段时间 AMD 与微软闹出的大瓜大伙儿都恰到了吧?没吃过也没关系,咱们可点击跳转往期内容回味: AMD 官方诉苦,CPU 性能被 Windows 限制 13%! 事情是这么个情况,AMD 不是在上个月先后正式上架了 Zen 5 锐龙 9000 系桌面 CPU 嘛。 来源:AMD 随后有外媒对那几颗 CPU 游戏性能进行了实测,他们发现似乎不管怎么折腾都无法到达官方 PPT 介绍的

Android热补丁动态更新实践

前言 好几个月之前关于Android App热补丁修复火了一把,源于QQ空间团队的一篇文章安卓App热补丁动态修复技术介绍,然后各大厂的开源项目都出来了,本文的实践基于HotFix,也就是QQ空间技术团队那篇文章所应用的技术,笔者会把整个过程的细节和思路在文章中详说,研究这个的出发点也是为了能紧急修复app的bug,而不需要重复发包,不需要用户重新下载app就能把问题解决,个人觉得这个还是蛮

JS中的prototype和__proto__

prototype 在JS中,每一个函数都有一个prototype属性,它的作用,简单的理解,就是当使用new关键字实例化一个函数的时候,这个函数prototype里面的对象也会共享到新实例里面。 function M1(){name:'john'}M1.prototype.sex = 'male'M1.age = 18var m2 = new M1()console.log(m2.n