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

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

JavaScript的对象系统从其语法上而言并不鼓舞使用信息隐藏(Information Hiding)。由于当使用诸如this.name。this.passwordHash的时候,这些属性默认的訪问级别就是public的。在不论什么位置都可以通过obj.name,obj.passwordHash来对这些属性进行訪问。

在ES5环境中,也提供了一些方法来更方便的訪问一个对象上全部的属性,比方Object.keys(),Object.getOwnPropertyNames()。所以,一些开发者使用一些规约来定义JavaScript对象的私有属性,比方最典型的是使用下划线作为属性的前缀来告诉其它开发者和用户这个属性是不应该被直接訪问的。

可是这样做,并不能从根本上解决这个问题。其它开发者和用户还是可以对带有下划线的属性进行直接訪问。

对于确实须要私有属性的场合,可以使用闭包进行实现。

从某种意义而言,在JavaScript中,闭包对于变量的訪问策略和对象的訪问策略是两个极端。闭包中的不论什么变量默认都是私有的,仅仅有在函数内部才干訪问这些变量。比方,能够将User类型实现例如以下:

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

此时,name和passwordHash都没有被保存为实例的属性。而是通过局部变量进行保存。然后依据闭包的訪问规则,实例上的方法能够对它们进行訪问,而在其他地方则不能。

使用这样的模式的一个缺点是,利用了局部变量的方法都须要被定义在实例本身上,不能讲这些方法定义在prototype对象上。

正如在Item34中讨论的那样,这样做的问题是会添加内存的消耗。可是在某些特别的场合下,即使将方法定义在实例上也是可行的。

总结:

  1. 闭包中定义的变量是私有的,仅仅能在闭包中被引用。
  2. 使用闭包来实现方法中的信息隐藏。
时间: 2024-12-22 23:03:30

Effective JavaScript Item 35 使用闭包来保存私有数据的相关文章

Effective JavaScript Item 11 掌握闭包

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

Effective JavaScript Item 27 使用闭包而不是字符串来封装代码

本系列作为Effective JavaScript的读书笔记. 对于代码封装,在JavaScript中有两种方式可以办到.第一种就是使用function,第二种则是利用eval()函数,传入到该函数的字符串参数可以是一段代码. 当对使用哪种方式犹豫不决时,使用function.因为使用字符串的一个重要缺点是,传入的字符串并不是一个闭包,而function则可以代表一个闭包.关于闭包的特点,在Item 11中进行了描述. 下面是一段使用字符串来封装代码的例子: function repeat(n,

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.checkP

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

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

Effective C++ Item 35 考虑 virtual 函数以外的实现

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.virtual 函数版本 class GameCharacter{ public: virtual int healthValue() const; //返回人物的健康指数, derived classes 可重新定义它 }; 2.使用 non-virtual interface 手法,那是 Template Method 设计模式的一种特殊形式. 让客户通过 public non-v

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 13 使用即时调用的函数表达式(IIFE)来创建局部域

本系列作为Effective JavaScript的读书笔记. 所谓的即时调用的函数表达式,这个翻译也许不太准确,它对应的英文原文是Immediately Invoked Function Expression (IIFE).下文也使用IIFE来表达这一概念. 首先看一个程序: function wrapElements(a) { var result = [], i, n; for (i = 0, n = a.length; i < n; i++) { result[i] = function

Effective JavaScript Item 37 认识this的隐式指向

本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔,所以在实现CSV Reader时,需要支持不同的分隔符.那么,很自然的一种实现就是将分隔符作为构造函数的参数. function CSVReader(separators) { this.separators = separators || [","]; this.regexp = new RegExp(this.separators.map(function(sep) { retu

Effective JavaScript Item 23 永远不要修改arguments对象

本系列作为Effective JavaScript的读书笔记. arguments对象只是一个类似数组的对象,但是它并没有数组对象提供的方法,比如shift,push等.因此调用诸如:arguments.shift(),arguments.push()是错误的. 在Item 20和Item 21中,知道了函数对象上存在call和apply方法,那么是不是可以利用它们来让arguments也能够利用数组的方法呢: function callMethod(obj, method) { var shi