上一篇博客介绍了如何使用构造函数在私有作用域中定义私有变量和私有函数,缺点就是:构造函数针对每个实例都会创建相同的一组方法,而使用静态私有变量可以避免这个问题
利用静态私有变量 在私有作用域中定义私有变量和私有函数 的基本套路:
(function() { // 私有变量和函数 var privateVariable = 1; function privateFunction() { return; } // 构造函数 MyObject = function() {}; MyObject.prototype.publicMethod = function() { privateVariable++; return privateFunction; } })
这个模式创建了一个私有块级作用域,定义了私有变量和函数。MyOject构造函数使用用函数表达式定义,没有使用函数声明(function name( ){ ... } 这种 ),因为函数声明只能声明局部函数。MyObject为全局变量,公有方法定义在MyObject的原型上,这样每次创建新的对象,不会创建同样的公有方法。
注意:为什么MyObject为全局变量???
初始化未经声明的变量,总是会创建一个全局变量。MyObject没有使用var关键字声明,因此MyObject是全局变量,在私有作用域之外仍可以访问
下面用一个例子来说明:
(function() { var name = ""; Person = function(value) { name = value; }; Person.prototype.getName = function() { return name; }; Person.prototype.setName = function(value) { name = value; }; })(); var person1 = new Person("Nicholas"); alert(person1.getName()); //"Nicholas" person1.setName("Greg"); alert(person1.getName()); //"Greg"var person2 = new Person("Michael"); alert(person1.getName()); //"Michael" alert(person2.getName()); //"Michael"
私有作用域代码执行流程:
私有作用域代码(匿名函数)执行前,先创建一个对应的执行函数(图中为匿名函数执行环境),然后复制作用链域,创建一个函数的活动对象(图中为匿名函数活动对象),并将其推入作用链域,因此图中 作用链域(调用)有两层。
私有作用域代码(匿名函数)执行时:
var name
在匿名函数活动对象中定义 name 属性
Person = function( ) { …… }
在Global变量中定义 Person 构造函数
Person.prototype.getName = function( ) { …… }
Person.prototype.setName = function( ) { …… }
在Person.prototype中定义 getName、setName 函数
私有作用域代码(匿名函数)执行完:
匿名函数的执行环境销毁,作用链域(调用)销毁,为仍被引用没有被销毁,如图:
创建对象的流程:
new Person( …… ) 前:
创建Person( ) 执行环境,从Person [[ scope ]] 复制作用链域,并创建 Person() 活动对象,并推入作用链域,所以作用链域有三层
执行 Person() 构造函数的代码:
将value复制给name,Person() 活动对象并没有变量name,从作用链域往上搜索,在匿名函数活动对象中找到name并修改。
构造函数执行完毕:
返回创建的Person对象
Person() 执行环境被销毁,作用链域(调用)被销毁,Person() 活动对象被销毁
静态私有变量与构造函数在私有作用域中定义私有变量和私有函数的对比:
私有变量是否共享:
静态私有变量的方法,私有变量是共享的
构造函数的方法,私有变量是相互独立的
原因:
两者的私有变量都是定义在其活动对象中的,但其创建时间不同:
静态私有变量的方法,其活动对象在私有作用域代码执行中创建的,之后new对象不再创建
构造函数的方法,其活动对象是在new对象时创建,每次new对象都会创建一个新的
——————————————————————————————————————————————————
其他系列文章:
利用构造函数在私有作用域中定义私有变量和私有函数
javascript在私有作用域中定义私有变量和私有函数 (1)