function aa(){
this.qqq = "qqqName";
www = "wwwName";
console.log(this.www);
}
_h = aa.prototype;
_h.bb = function(){
console.log(this.www);
console.log(this.qqq);
}
var cc = new aa();
cc.bb();
console.log(cc.qqq);
console.log(cc.www);
//输出
//undefined
//undefined
//qqqName
//qqqName
//undefined
上面代码中,_h.bb算是闭包吗?还是说只有在子函数里面return父函数的变量,这个子函数才算是闭包?但是我这里,this.qqq在最外面都是可以访问的啊,修改也是可以的啊,而www只能在aa()里访问,这样是不是比直接把bb()函数写在aa()函数里要好一点?毕竟变量的作用域在定义的时候就可以自由选择又能做到常在内存。
另外还有一种是把函数当做对象的其中一个key/value来使用,这样应该毫无疑问是闭包的做法了,但是我还是想知道我这种算不算闭包呀...
还是说我对闭包的理解错了?求解呀,弄不懂这个我js就进步不了了TAT
最后,闭包能解决什么样的实际问题?下面是我想到的几个可能的答案
1.在主函数内的变量可以随便起名字,不用怕外面有重名的?
2.在需要实例化多个对象(就像上面var cc = new aa();
)的时候,这些对象里的同名变量不会互相影响,并且可以独立工作?比如
var cc = new aa();
var dd = new aa();
cc.qqq = "ooooooooo";
console.log(dd.qqq)//=>qqqName
console.log(cc.qqq)//=>ooooooooo
3.当要保存一个变量,而且要在以后再用的时候,比如保存一个audio对象,需要暂停的时候再回来找它,但是又不想声明全局变量,因为在任何地方都能直接读取也不好。额,这个其实就是答案1的详细版...
閉包 (電腦科學) - 維基百科,自由的百科全書
簡單地說,閉包就是變量作用域生命的延伸。
Javascript 中的閉包就是如此。
例如:
即便
generator
的作用域已經結束,變量a
仍舊可以通過函數b
訪問,這是閉包的典型運用。題主就混淆了這兩個概念。
_h.bb
是一個匿名函數,但這個匿名函數並沒有用到閉包的性質。題主的代碼應該寫成這樣:
此時,
aa.a()
是 instance level 函數,aa.b()
等價於Aa.prototype.b.call(aa)
是 prototype level 函數。而
a
可以看作是一個私有屬性,_b
是一個公共屬性。而性能問題的擔憂是樓主對現代 Javascript 引擎的不理解。
aa.b()
的性能不如aa.a()
。首先是由於需要遍歷原型鏈,其次是
b
額外訪問了一次aa
的屬性。再者即便閉包是 instance level 函數,它也是「閉包在執行時可以有多個例項,不同的參照環境和相同的函式組合可以產生不同的例項」中的例項,也就是實例,函數本身並不需要單獨佔用額外內存。
prototype 版本在 jsperf 完勝 closure 版本。http://jsperf.com/clos-vs-proto之前的分析忘記了創建閉包的性能開銷。不過如果對象只有一個實例,單純訪問屬性的速度,closure 還是略微快一點的。http://jsperf.com/prototype-vs-closure-single-object
如 Humphry 所說,
aa.b()
與aa.a()
的比較實際上是比较原型链寻址 vs 作用域链寻址而 http://jsperf.com/clos-vs-proto 比較的主要是創建對象的速度。
最後回答題主的三個問題。
這三個問題實際上是同一個問題,就是變量的作用域問題。
另外樓主混淆了
屬性
和變量
。屬性是屬於對象實例的,變量是屬於閉包的。
全局變量比較特殊,因爲它也可以通過
window.a
訪問,這是 js 設計的一個失誤?因爲 你可以delete
通過window.a
聲明的a
,不可以delete
通過var a
聲明的window.a
。