No.41、将原型视为实现细节

Tips:

  1. 对象是接口,原型是实现
  2. 避免检查你无法控制的对象的原型结构
  3. 避免检查实现在你无法控制的对象内部的属性

我们可以获取对象的属性值和调用其方法,这些操作都不是特别在意属性存储在原型继承结构的哪个位置。只要其属性值保存很定,那么这些操作的行为也不变。简言之,原型是一种对象行为的实现细节。

正是由于以上的特性,所以如果修改了实现细节,那么依赖于这些对象的使用者就会被破坏,而且还很难诊断这类bug。所以一般来说,对于使用者,最好不要干涉那些属性。

No.42、避免使用轻率的猴子补丁

Tips:

  1. 避免使用轻率的猴子补丁
  2. 记录程序库所执行的所有猴子补丁
  3. 考虑通过将修改设置于一个导出函数中,使猴子补丁成为可选的
  4. 使用猴子补丁为缺失的标准API提供polyfills

何为猴子补丁?

由于对象共享原型,因为每一个对象都可以增加、删除或修改原型的属性。这个有争议的实践通常被称为猴子补丁。

猴子补丁的吸引力在于它的强大,如果数组缺少一个有用的方法,那么我们可以自己扩展它。但是在多个库同时对数组进行不兼容扩展时,问题就来了,有可能调用方法之后的结果和预期不一致。

危险的猴子补丁有一个特别可靠而且有价值的使用场景:polyfill。补齐标准所支持的方法。

No.43、使用Object的直接实例构造轻量级的字典

Tips:

  1. 使用对象字面量构建轻量级字典
  2. 轻量级字典应该是Object.prototype的直接子类,以使for...in循环免受原型污染

JavaScript对象的核心是一个字符串属性名称与属性值的映射表。

var dict = {
key1: 'value1',
key2: 'value2'
};
for(var key in dict){
console.log('key='+ key + ',value=' + dict[key]);
}

在使用for...in时,要小心原型污染。

function Dict(){
Dict.prototype.count = function(){
var c = 0;
for(var p in this){
c++;
}
return c;
}
} var dict = new Dict();
dict.name = 'jay';
console.log(dict.count()); //结果是2,因为for...in会枚举出所有的属性,包括原型上的。

所有人都不应当增加属性到Object.prototype上,因为这样做可能会污染for...in循环,那么我们通过使用Object的直接实例,可以将风险仅仅局限于Object.prototype。

No.44、使用null原型以防止原型污染

Tips:

  1. 在ES5中,使用Object.create(null)创建的自由原型的空对象是不太容易被污染的
  2. 在一些较老的环境中,考虑使用{proto: null}
  3. 要注意__proto__既不标准,也不是完全可移植的,并且可能会在未来的JavaScript环境中去除
  4. 绝不要使用__proto__名作为字典的key,因为一些环境将其作为特殊的属性对待

对构造函数的原型属性设置null或者是undefined是无效的:

function Dict(){

}
Dict.prototype = null;
var dict = new Dict();
console.log(Object.getPrototypeOf(dict) === null); // false
console.log(Object.getPrototypeOf(dict) === Object.prototype); //true

在ES5中,提供了标准方法来创建一个没有原型的对象:

var dict = Object.create(null);
console.log(Object.getPrototypeOf(dict) === null); // true

在不支持Object.create函数的旧的JS环境中,可以使用如下方式创建没有原型的对象:

var dict = {__proto__: null}
console.log(Object.getPrototypeOf(dict) === null); // true

注意:在支持Object.create函数的环境中,尽可能的坚持使用标准的Object.create函数

No.45、使用hasOwnProperty方法来避免原型污染

Tips:

  1. 使用hasOwnProperty方法避免原型污染
  2. 使用词法作用域和call方法避免覆盖hasOwnProperty方法
  3. 考虑在封装hasOwnProperty测试样板代码的类中实现字典操作
  4. 使用字典类避免将__proto__作为key来使用

即使是一个空的对象字面量也继承了Object.prototype的大量属性:

var dict = {}
console.log('a' in dict); // false
console.log('toString' in dict); // true
console.log('valueOf' in dict); // true

不过,Object.prototype提供了方法来测试字典条目:

var dict = {}
console.log(dict.hasOwnProperty('a')); // false
console.log(dict.hasOwnProperty('toString')); // false
console.log(dict.hasOwnProperty('valueOf')); // false

但是,如果在字典中存储一个同为“hasOwnProperty”的属性,那么:

var dict = {
hasOwnProperty: null
}
console.log(dict.hasOwnProperty('a')); // TypeError

最安全的方法则是使用call:

var dict = {
hasOwnProperty: null
}
console.log({}.hasOwnProperty.call(dict, 'hasOwnProperty')); // true、

最后,我们来看一个复杂的但更安全的字典类:

function Dict(elements){
this.elements = elements || {};
this.hasSpecialProto = false;
this.specialProto = undefined;
} Dict.prototype.has = function(key){
if(key === '__proto__'){
return this.hasSpecialProto;
}
return {}.hasOwnProperty.call(this.elements, key);
}; Dict.prototype.get = function(key){
if(key === '__proto__'){
return this.specialProto;
}
return this.has(key) ? this.elements[key] : undefined;
}; Dict.prototype.set = function(key, value){
if(key === '__proto__'){
this.hasSpecialProto = true;
this.specialProto = value;
}else{
this.elements[key] = value;
}
}; Dict.prototype.remove = function(key){
if(key === '__proto__'){
this.hasSpecialProto = false;
this.specialProto = undefined;
}else{
delete this.elements[key];
}
}; // 测试代码
var dict = new Dict();
console.log(dict.has('__proto__')); // false

*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}

h3 {
font-size: 18px;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

编写高质量JS代码的68个有效方法(九)的更多相关文章

  1. 编写高质量JS代码的68个有效方法(八)

    [20141227]编写高质量JS代码的68个有效方法(八) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  2. 编写高质量JS代码的68个有效方法(七)

    [20141220]编写高质量JS代码的68个有效方法(七) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  3. 编写高质量JS代码的68个有效方法(六)

    [20141213]编写高质量JS代码的68个有效方法(六) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  4. 编写高质量JS代码的68个有效方法(四)

    [20141129]编写高质量JS代码的68个有效方法(四) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  5. 编写高质量JS代码的68个有效方法(三)

    [20141030]编写高质量JS代码的68个有效方法(三) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  6. 编写高质量JS代码的68个有效方法(二)

    [20141011]编写高质量JS代码的68个有效方法(二) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  7. JavaScript手札:《编写高质量JS代码的68个有效方法》(一)(1~5)

    编写高质量JS代码的68个有效方法(一) *:first-child { margin-top: 0 !important; } body>*:last-child { margin-botto ...

  8. 编写高质量JS代码的68个有效方法(十三)

    No.61.不要阻塞I/O事件队列 Tips: 异步API使用回调函数来延缓处理代价高昂的操作以避免阻塞主应用程序 JavaScript并发的接收事件,但会使用一个事件队列按序地处理事件处理程序 在应 ...

  9. 编写高质量JS代码的68个有效方法(十)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  10. 编写高质量JS代码的68个有效方法(十一)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

随机推荐

  1. hdu 2955 01背包

    http://acm.hdu.edu.cn/showproblem.php?pid=2955 如果认为:1-P是背包的容量,n是物品的个数,sum是所有物品的总价值,条件就是装入背包的物品的体积和不能 ...

  2. curl常用操作

    1.cURL介绍 cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP.FTP.TELNET等.最爽的是,PHP也支持 cURL 库.本文将介绍 cURL 的一些高级特性 ...

  3. SQL Server如何提高数据库备份的速度

    对于一个数据库完整备份来说,备份的速度很大程度上取决于下面两个因素:读磁盘数据.日志文件的吞吐量,写磁盘数据文件的吞吐量. 下图是备份过程中磁盘的变化情况: 读吞吐量 读吞吐量的大小取决于磁盘读取数据 ...

  4. Socket原理与编程基础(转)

    一.Socket简介 Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换. 几个定义: (1)IP地址:即依照TCP/IP协议分配给本地主机的 ...

  5. Java和Android文件操作

    File这是文件基类,抽象地代表一个文件实体,它有四个不同的构造方法: File(File dir, String name)  File(String path)   File(String dir ...

  6. Ques核心思想——CSS Namespace

    Facebook’s challenges are applicable to any very complex websites with many developers. Or any situa ...

  7. android开发出现No Launcher activity found!解决方案

    在AndroidManifest.xml中的中少了这段代码 <activity android:name=".MainActivity" android:label=&quo ...

  8. 百度Web富文本编辑器ueditor在ASP.NET MVC3项目中的使用说明

    ====================================================================== [百度Web富文本编辑器ueditor在ASP.NET M ...

  9. 深入剖析 redis AOF 持久化策略

    本篇主要讲的是 AOF 持久化,了解 AOF 的数据组织方式和运作机制.redis 主要在 aof.c 中实现 AOF 的操作. 数据结构 rio redis AOF 持久化同样借助了 struct ...

  10. Navi.Soft30.框架.WebMVC.开发手册

    1概述 1.1应用场景 互联网高速发展,互联网软件也随之越来越多,Web程序越来越被广泛使用.它部署简单,维护方便,深得众多软件公司使用 Bootstrap前端框架,是最近非常流行的框架之一.它简洁, ...