Effective JavaScript Item 34 在prototype上保存方法

本系列作为EffectiveJavaScript的读书笔记。

不使用prototype进行JavaScript的编码是完全可行的,例如:

function User(name, passwordHash) {
	this.name = name;
	this.passwordHash = passwordHash;
	this.toString = function() {
		return "[User " + this.name + "]";
	};
	this.checkPassword = function(password) {
		return hash(password) === this.passwordHash;
	};
}

var u1 = new User(/* ... */);
var u2 = new User(/* ... */);
var u3 = new User(/* ... */);

当创建了多个User类型的实例时,就存在问题了:不仅是name和passwordHash属性在每个实例上都存在,toString和checkPassword方法在每个实例上都有一份拷贝。就像下图表示的那样:

但是,当toString和checkPassword被定义在prototype上时,上图就变成下面这个样子了:

toString和checkPassword方法现在定义在了User.prototype对象上,也就意味着这两个方法只存在一份拷贝,并被所有的User实例共享。

也许你会认为将方法作为拷贝放在每个实例上,会节省方法查询的时间。(当方法定义在prototype上时,首先会在实例本身上寻找方法,如果没有找到才会去prototype上继续找)

但是在现代的JavaScript执行引擎中,对方法的查询进行了大量优化,所以这个查询时间几乎是不需要考虑的,那么将方法放在prototype对象上就节省了很多内存。

总结:

  1. 将方法存放在实例上会导致每个实例都会拥有该方法的一份拷贝,导致内存的浪费。
  2. 优先将方法存放在prototype对象上。

时间: 2024-08-03 20:43:26

Effective JavaScript Item 34 在prototype上保存方法的相关文章

Effective JavaScript Item 36 实例状态只保存在实例对象上

本系列作为EffectiveJavaScript的读书笔记. 一个类型的prototype和该类型的实例之间是"一对多"的关系.那么,需要确保实例相关的数据不会被错误地保存在prototype之上.比如,对于一个实现了树结构的类型而言,将它的子节点保存在该类型的prototype上就是不正确的: function Tree(x) { this.value = x; } Tree.prototype = { children: [], // should be instance stat

Effective JavaScript Item 35 使用闭包来保存私有数据

本系列作为EffectiveJavaScript的读书笔记. JavaScript的对象系统从其语法上而言并不鼓舞使用信息隐藏(Information Hiding).由于当使用诸如this.name.this.passwordHash的时候,这些属性默认的訪问级别就是public的.在不论什么位置都可以通过obj.name,obj.passwordHash来对这些属性进行訪问. 在ES5环境中,也提供了一些方法来更方便的訪问一个对象上全部的属性,比方Object.keys(),Object.g

Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同

本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来访问prototype的方法.它们的命名方式很类似因此很容易带来困惑. 它们的使用方式如下: prototype: 一般用来为一个类型建立它的原型继承对象.比如C.prototype = xxx,这样就会让使用new C()得到的对象的原型对象为xxx.当然使用obj.prototype也能够得到obj的原型对象. getPropertyOf: Object

Effective C++ Item 34 区分接口继承与实现继承

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 关联条款 Item 36 接口继承和实现继承不同.在 public 继承下, derived classes 总是继承 base class 的接口 class Shape{ public: virtual void draw() const = 0; virtual void error(const std::string &msg); int objectID() const; //.

函数内的方法和prototype上的方法对比

函数内的方法: 使用函数内的方法我们可以访问到函数内部的私有变量,如果我们通过构造函数new出来的对象需要我们操作构造函数内部的私有变量的话, 我们这个时候就要考虑使用函数内的方法. prototype上的方法: 当我们需要通过一个函数创建大量的对象,并且这些对象还都有许多的方法的时候;这时我们就要考虑在函数的prototype上添加这些方法. 这种情况下我们代码的内存占用就比较小. 在实际的应用中,这两种方法往往是结合使用的;所以我们要首先了解我们需要的是什么,然后再去选择如何使用.

Effective JavaScript Item 51 在类数组对象上重用数组方法

Array.prototype对象上的标准方法被设计为也可以在其它对象上重用 - 即使不是继承自Array的对象.因此,在JavaScript中存折一些类数组对象(Array-like Objects). 一个典型的例子是函数的arguments对象,在Item 22中对它进行过介绍.该对象并不继承自Array.prototype,所以我们不能直接调用arguments.forEach来对其中的元素进行遍历.但是,我们可以通过首先得到forEach方法的对象,然后调用call方法(可以参考Ite

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

本系列作为Effective JavaScript的读书笔记. 如果你的代码中依赖于for..in循环来遍历Object类型中的属性的话,不要向Object.prototype中添加任何可列举的属性. 但是在对JavaScript执行环境进行增强的时候,往往都需要向Object.prototype对象添加新的属性或者方法.比如可以添加一个方法用于得到某个对象中的所有的属性名: Object.prototype.allKeys = function() { var result = []; for

Effective JavaScript Item 24 使用一个变量来保存arguments的引用

本系列作为Effective JavaScript的读书笔记. 假设需要一个API用来遍历若干元素,像下面这样: var it = values(1, 4, 1, 4, 2, 1, 3, 5, 6); it.next(); // 1 it.next(); // 4 it.next(); // 1 相应的实现可以是: function values() { var i = 0, n = arguments.length; return { hasNext: function() { return

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

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