最近在学习JavaScript基础,在学习到面向对象编程时,学习到在JavaScript中实现模块化的方法,其中一个重要的点是如何封装私有变量。
实现封装私有变量的方法主要是:
- 使用构造函数
function StringBuilder() {
var buffer = []; this.add = function (str) {
buffer.push(str);
}; this.toString = function () {
return buffer.join('');
};
}
// 上面这种做法有个缺点,就是每生成一个新的实例,其中的方法就会生成一个新的实例,造成内存浪费,因此做如下改进
function StringBuilder() {
this._buffer = [];
} StringBuilder.prototype = {
constructor: StringBuilder,
add: function (str) {
this._buffer.push(str);
},
toString: function () {
return this._buffer.join('');
}
};
// 此时所有实例会共享这两个方法,不会重复生成
// 但是问题又来了,我们封装的私有变量变得不私有了,在外部可以直接修改_buffer,如
var sb = new StringBuilder();
sb._buffer = 'hello, sb'; - 使用立即执行函数
var module = (function() {
function StringBuilder() {
this._buffer = [];
} StringBuilder.prototype = {
constructor: StringBuilder,
add: function (str) {
this._buffer.push(str);
},
toString: function () {
return this._buffer.join('');
}
}; function createStringBuilder() {
var _sb = new StringBuilder();
return {
add: StringBuilder.prototype.add.bind(_sb),
toString: StringBuilder.prototype.toString.bind(_sb)
};
} return {
createStringBuilder: createStringBuilder
}; })(); console.log(module); // { createStringBuilder: [Function: createStringBuilder] }
var sb = module.createStringBuilder();
sb.add('hello');
sb.add('爱编程的小菜鸟');
console.log(sb.toString()); // hello爱编程的小菜鸟
在立即执行函数中,重点在于createStringBuilder这个函数,这个函数实现了内外对接的接口,对内保护了StringBuilder的私有成员,对外又能提供需要访问的接口,实现了真正的私有变量封装。下面我们用一个简单的例子对上面的三种方式进行对比:
// 构造函数,var1无法被外界修改,但是每生成一个实例,fn都会被拷贝
function Class1() {
var var1 = 10;
this.fn = function() {
console.log(var1);
var1 += 1;
};
}
var c10 = new Class1();
var c11 = new Class1();
console.log(c10.var1); // undefined,变量不可被访问
console.log(c10 === c11); // false
c10.fn(); //
c11.fn(); //
c10.fn(); //
c11.fn(); // // 改进一下
function Class2() {
this._var1 = 10;
} Class2.prototype = {
constructor: Class2,
fn: function() {
console.log(this._var1);
this._var1 += 1;
}
};
var c20 = new Class2();
var c21 = new Class2();
c20.fn(); //
c20.fn(); //
c21.fn(); //
c21.fn(); //
console.log(c20._var1); // 11,变量可被访问
console.log(c20.fn === c21.fn); // true // 为了解决上述问题
var m = (function() {
function Class3() {
this.var1 = 10
}
Class3.prototype = {
constructor: Class3,
fn: function() {
console.log(this.var1);
this.var1 += 1;
}
}; function createClass3() {
var c3 = new Class3();
return {
fn: Class3.prototype.fn.bind(c3)
};
} return {
createClass3: createClass3
}
})();
var c30 = new m.createClass3();
var c31 = new m.createClass3();
c30.fn(); //
c30.fn(); //
c31.fn(); //
c31.fn(); //