javascript 中构造函数的私有变量在原型链定义函数可以共用
此篇博文其实是上一篇的一个小细节,单独拿出来说一下,否则上一篇叉开的分支太多,太乱.
因为上一篇和大家分享了node.js 中使用util.inherits实现继承 我们单独给出一个小demo ,_base.js 父类继承了 events.EventEmitter 类.
var events=require('events'); var util=require('util'); function _base(){ this.emitter=new events.EventEmitter(this); }; util.inherits(_base,events.EventEmitter); //继承 _base.prototype.onEvent=function(eventName,callback){ this.emitter.on(eventName,callback); } _base.prototype.emitEvent=function(eventName,arg){ this.emitter.emit(eventName,arg); } module.exports=_base;
回顾一下代码,首先在构造函数中定义了一个私有变量 ,this.emitter
接着你可能注意到 onEvent ,emitEvent 方法中都使用了这个私有变量.
为什么可以这样?
因为javascript中唯一有私有作用域的就是函数, 按理说, _base() 函数中定义的私有变量只能在此函数或者他的嵌套函数里使用.
退一万步讲,javascript中神通广大的闭包之所以神通,就是因为它能把函数的私有作用域带出来,让那些不能访问函数内部私有变量的作用域访问到函数的属性或方法.
OMG,我们在这里竟然把一个私有变量随便在几个方法中用来用去,根本没有考虑过闭包的感受.....
那是我们用错了吗? NO! 这样使用是ok的,下面我们来慢慢分析.
上面之所以这样用是有几个前提的:
(1)此私有变量被定义在构造函数中.
(2)直接使用此私有变量的函数全部是原型对象上定义的属性.
(3)这种语境只可能出现在未来( 就是 var base=new _base() 时)
下面来解释:
(1)javascript中任何函数你都可以当做构造函数,它没有特殊的关键词等.
有人有疑问了,那你为什么把 _base() 叫做构造函数, 只是因为我在 model 层中的 blogInfo 实体类中引用了 _base.js 文件,然后用 _base() 函数new 了一个对象,(你说你根本看不到什么 model 层,麻烦你看我上一篇博客)
因为此 _base() 被后面用来 new 对象,所以我们可以肯定它就是一个构造函数.
(2)貌似只能用肉眼看了
_base.prototype.onEvent = function (){......}
这样的定义就是标准的在原型对象上定义的属性(这明明就是个方法啊,怎么能成为属性? 叫啥都可以,确切讲是一个匿名函数赋值给了圆形对象的一个属性)
(3)为什么只会出现在未来?
那我们就来看看现在行不行!
本人本地用 JS Runner 来演示,所以关于node.js里的语法就不支持了.所以做了如下改动.
function _base(){ this.blogName='一介布衣'; }; _base.prototype.getName=function(){ console.log(this.blogName); } _base.prototype.setName=function(){ this.blogName='一介布衣Blog'; }
上面代码中的2个方法直接调用了构造函数 _base() 中的私有变量 this.blogName
我们直接调用看看是什么结果:
console.log('------',_base.prototype); //我们打印看下 _base 的原型指向谁 _base.prototype.getName(); //然后直接调用getName 方法,看看能否输出 _base() 函数定义的私有变量
运行结果:
我们可以看到 _base.prototype 打印出来是
[object Object]
然后我们直接调用 getName() 方法,打印出了 undefined ,说明this.blogName 根本不可用.
那我们用 _base() 实例化一个对象再来试一试吧.
var base=new _base(); base.getName();
得到的结果是:
[object Object] 一介布衣
大家看到了, 实例化以后,调用 getName() 函数返回了 构造函数的定义的私有变量.this.blogName
构造函数实例化的时候调用 Object.create(superCtor,prototype,{.....})
superCtor 就是原型对象,相当于 _base.prototype
所以生成的新对象 base 本身就包括属性 blogName 和 方法 ,getName ,setName .所以你现在知道为啥 这2个方法可以用blogName 这个变量了吧,因为他们在一个作用域,并且是快快乐乐的一家人.