Effective JavaScript Item 47 绝不要向Object.prototype中添加可列举的(Enumerable)属性

本系列作为Effective JavaScript的读书笔记。

如果你的代码中依赖于for..in循环来遍历Object类型中的属性的话,不要向Object.prototype中添加任何可列举的属性。

但是在对JavaScript执行环境进行增强的时候,往往都需要向Object.prototype对象添加新的属性或者方法。比如可以添加一个方法用于得到某个对象中的所有的属性名:

Object.prototype.allKeys = function() {
	var result = [];
	for (var key in this) {
		result.push(key);
	}
	return result;
};

但是结果是下面这个样子的:

({ a: 1, b: 2, c: 3}).allKeys(); // ["allKeys", "a", "b","c"]

一个可行的解决方案是使用函数而不是在Object.prototype上定义新的方法:

function allKeys(obj) {
	var result = [];
	for (var key in obj) {
		result.push(key);
	}
	return result;
}

但是如果你确实需要向Object.prototype上添加新的属性,同时也不希望该属性在for..in循环中被遍历到,那么可以利用ES5环境提供的Object.defineProject方法:

Object.defineProperty(Object.prototype, "allKeys", {
	value: function() {
		var result = [];
		for (var key in this) {
			result.push(key);
		}
		return result;
	},
	writable: true,
	enumerable: false,
	configurable: true
});

以上代码的关键部分就是将enumerable属性设置为false。这样的话,在for..in循环中就无法遍历该属性了。

总结:

  1. 避免向Object.prototype中添加任何属性。
  2. 如果确实有必要向Object.prototype中添加方法属性,可以考虑使用独立函数替代。
  3. 使用Object.defineProperty来添加可以不被for..in循环遍历到的属性。

时间: 2024-10-17 03:01:19

Effective JavaScript Item 47 绝不要向Object.prototype中添加可列举的(Enumerable)属性的相关文章

[Effective JavaScript 笔记]第47条:绝不要在Object.prototype中增加可枚举的属性

之前的几条都不断地重复着for...in循环,它便利好用,但又容易被原型污染.for...in循环最常见的用法是枚举字典中的元素.这里就是从侧面提出不要在共享的Object.prototype中增加可枚举的属性.这就导致,我们在开发的时候,不能在Object.prototype中添加有用的方法.如,我们想增加一个产生对象属性名数组的allKeys方法将会怎么样? Object.prototype.allKeys=function(){ var res=[]; for(var key in thi

Effective JavaScript Item 39 绝不要重用父类型中的属性名

本系列作为Effective JavaScript的读书笔记. 如果需要向Item 38中的Actor对象添加一个ID信息: function Actor(scene, x, y) { this.scene = scene; this.x = x; this.y = y; this.id = ++Actor.nextID; scene.register(this); } Actor.nextID = 0; 同时,也需要向Actor的子类型Alien中添加ID信息: function Alien(

Effective JavaScript Item 32 绝不要修改__proto__

本系列作为Effective JavaScript的读书笔记. 和Object.getPrototypeOf相比,__proto__的特殊之处还体现在它能够修改一个对象的原型继承链.因为它是一个属性,除了执行获取它的操作外,还能够对它进行设置. 但是,绝不要修改__proto__.原因如下: 首先,最显而易见的原因就是便携性.因为不是所有的JavaScript执行环境都支持这一属性,所以使用了__proto__之后,代码就不能在那些不支持__proto__的环境中运行了. 其次,是性能上的考虑.

Effective C++ Item 47 请使用 traits classes 表现类型信息

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:Traits classes 使得"类型相关信息"在编译期可用.它们以 templates 和 "templates 特化"完成实现 示例: template<...> class deque{ public: class iterator{ public: typedef random_access_iterator_tag iterato

Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__

本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的__proto__属性来达到相同的目的. 由于并非全部的环境都提供了这个__proto__属性,且每一个环境的实现方式各不同样,因此一些结果可能不一致: // 在某些环境中 var empty = Object.create(null); // object with no prototype "__

Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合

本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 但是在使用for..in循环对Object中的属性进行遍历的时候,确实是需要依赖于某种顺序的.正因为ECMAScript没有对这个顺序进行明确地规范,所以每个JavaScript执行引擎都能够根据自身的特点进行实现,那么在不同的执行环境中就不能保证for..in循环的行为一致性了. 比如,以下代码在调用report方法时的结果就是不确定的

Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数

作为这一系列Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中.都会有场景(Scene)这一概念.在一个场景中会包括一个对象集合,这些对象被称为角色(Actor). 而每一个角色依据其类型会有一个图像用来表示,同一时候场景也须要保存一个底层图形展示对象的引用,被称为上下文(Context): function Scene(context, width, height, images) { this.context = context; this.width =

Effective JavaScript Item 38 在子类构造函数中调用父类构造函数

本系列作为Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中,都会有场景(Scene)这一概念.在一个场景中会包含一个对象集合,这些对象被称为角色(Actor).而每个角色根据其类型会有一个图像用来表示,同时场景也需要保存一个底层图形展示对象的引用,被称为上下文(Context): function Scene(context, width, height, images) { this.context = context; this.width = width

Effective JavaScript Item 11 掌握闭包

本系列作为Effective JavaScript的读书笔记. 掌握闭包,需要知道以下几个关键点: JavaScript允许在当前的function中访问该function外部的变量. function makeSandwich() { var magicIngredient = "peanut butter"; function make(filling) { return magicIngredient + " and " + filling; } return