41条对违反抽象原则行为的讨论之后,下面聊一聊终极违例。由于对象共享原型,因此每一个对象都可以增加、删除或修改原型的属性。这个有争议的实践通常称为猴子补丁。

猴子补丁示例

猴子补丁的吸引力在于其强大。数组缺少一个有用的方法吗?你自己就可以增加它。

Array.prototype.split=function(i){
return [this.slice(0,i),this.slice(i)];
}

很完美,现在可以在任意的数组上调用这个方法了。但当多个库以不兼容的方式给同一个原型打猴子补丁时,另外的库使用同一个方法名给Array.prototype打猴子补丁。

Array.prototype.split=function(){
var i=Math.floor(this.length);
return [this.slice(0,i),this.slice(i)];
}

问题

现在,任一对数组split方法的使用都大约有50%的机会被破坏,这取决于它们期望这两个方法哪一个被调用。
至少,任一修改其享原型的程序库都应当清晰地记录其修改。这至少能给使用者在关于不同库之间潜在的冲突提供足够的警告。但是,两个以冲突的方式给原型打猴子补丁的程序库不能在同一个程序中使用。

替代的方法

一种替代的方法是,如果库仅仅是将给原型打猴子补丁作为一种便利,那么可以将这些修改置于一个函数中,用户可以选择调用或忽略。

function addArrayMethods(){
Array.prototype.split=funciton(i){
return [this.slice(0,i),this.slice(i)]
}
}

这种方法只有在程序库提供了addArrayMethods函数时才能工作,而实际上并不依赖于Array.prototype.split函数。

ployfill

尽管猴子补丁很危险,但有一种告别可靠而且有价值的使用场景:ployfill。js程序和库经常部署在多个平台,这些平台实现了多少个标准API可能是有区别的。缺失的方法的行为是广泛支持的标准所定义的,而且许多程序和库可能依赖这些方法。由于它们的行为是标准化的,因此实现这些方法并不会造成与库之间不兼容性的类似的风险。事实上,多个库都可以给同一个标准方法提供实现(假设是被正确实现),因为它们都实现了相同的标准API。
你可以通过使用带有测试条件的守护猴子补丁来安全地弥补这些平台的差距。

if(typeof Array.prototype.map!=="function"){
Array.prototype.map=function(f,thisArg){
var res=[];
for(var i=0,n=this.length;i < n;i++){
res[i]=f.call(thisArg,this[i],i);
}
return res;
}
}

提示

  • 避免使用轻率的猴子补丁

  • 记录程序库所执行的所有猴子补丁

  • 考虑通过将修改置于一个导出函数中,使猴子补丁成为可选的

  • 使用猴子补丁为缺失的标准API提供polyfills

[Effective JavaScript 笔记]第42条:避免使用轻率的猴子补丁的更多相关文章

  1. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  2. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  3. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  4. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  5. [Effective JavaScript 笔记]第50条:迭代方法优于循环

    "懒"程序员才是好程序员.复制和粘贴样板代码,一但代码有错误,或代码功能修改,那么程序在修改的时候,程序员需要找到所有相同功能的代码一处处进行修改.这会使人重复发明轮子,而且在别人 ...

  6. [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑

    构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...

  7. [Effective JavaScript 笔记]第64条:对异步循环使用递归

    假设需要有这样一个函数,接收一个URL的数组并尝试依次下载每个文件直到有一个文件被成功下载.如果API是同步的,使用循环很简单实现. function downloadOneSync(urls){ f ...

  8. [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合

    对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...

  9. [Effective JavaScript 笔记]第45条:使用hasOwnProperty方法以避免原型污染

    之前的43条,44条讨论了属性的枚举,但都没有彻底地解决属性查找中原型污染的问题.看下面关于字典的一些操作 'zhangsan' in dict; dict.zhangsan; dict.zhangs ...

随机推荐

  1. 使用OneNote的COM组件,实现OCR功能。

    背景 在业务系统开发的过程中,很多情况下会去识别图片中的相关信息,并且把信息录入到系统中.现在希望通过自动化的方式录入,就有了以下的工作.在对比了几个OCR软件在中文识别方面的准确率后,决定使用微软的 ...

  2. VS一般设置(字体,背景色)

    字体 打开工具=>环境=>字体和颜色,字体:Consolas,大小:13 背景色 缩进设置 工具=>文本编辑器=>纯文本=>制表符=>保留制表符

  3. hello,world!

    这可以算是我的第一篇博客了吧?真正意义上的开始... 我于2016年6月毕业于山东英才学院信工学院计算机管理系,至今已有近半年.几经周转,总算是准备稳定下来了.于是,当初的博客想法提上了日程. 本人工 ...

  4. angularJS中-$route路由-$http(ajax)的使用

    后台请求使用的是nodeJS驱动(后面帖代码),很简单的RESTFUL, 页面使用的是bottstarp3.0(懒人神器); 第一个例子: 在本地架设NODEJS, angular的所有请求都是请求本 ...

  5. OC基础--OC中的类方法和对象方法

    PS:个人感觉跟C#的静态方法和非静态方法有点类似,仅仅是有点类似.明杰老师说过不要总跟之前学过的语言做比较,但是个人觉得,比较一下可以加深印象吧.重点是自己真的能够区分开! 一.OC中的对象方法 1 ...

  6. Java-set

    set public interface Set<E> extends Collection<E> 使用集合汇总 package 集合类.Set类; /** * Set不允许重 ...

  7. Yii2的view需要链接跳转

    添加 use yii\helpers\Url; view中的连接 <?= Url::toRoute('post/index');?>//post为你的当前控制器名,index为view模版

  8. 【Matplotlib】 增加图例

    相关文档: Legend guide legend() command Legend API 控制图例入口 无参调用 legend() 会自动获取图例 handles 以及相关的 labels.其对应 ...

  9. Spring JdbcTemplate 的使用与学习

    JDBCTemplate 是SPRING 框架自带的一种对sql 语句查询的封装 ,封装非常完善,虽然与Hibernate比起来有一点麻烦,但是学号JDBCTemplate可以让我们用Spirngmv ...

  10. php版本的discuzX3.2部署的问题收集

    1.登陆后台老是自动退出是怎么回事? 解决方法:用ftp上線下載文件下在跟目錄/config/config_global.php把$_config['admincp']['checkip']  = 1 ...