例1:
function a(){
function b(){
var bbb = 234;
document.write(aaa);//123
}
var aaa = 123;
return b;//a执行完前b被保存出来了
}
var glob = 100;
var demo = a();
demo();
预编译:
a defined a.[[scope]] --> 0:GO{a:(function),glob:100,demo:(function)}
function a()开始运行:
a handle a.[[scope]] --> 0:aAO{b:(function),aaa:123}
1:GO的引用
return b后,b被定义:
b defined b.[[scope]] --> 0:aAO的引用
1:GO的引用
function a()执行完毕,aAO中引用清空,但其中的属性b的引用已被返回给demo
function b()开始运行:
b handle b.[[scope]] --> 0:bAO{bbb:234}
1:aAO的引用
2:GO的引用
例2:
function a(){
var num = 100;
function b(){
num ++;
console.log(num);
}
return b;
}
var demo = a();
demo();//101
demo();//102
预编译:
a defined a.[[scope]]--> 0:GO{a:(function),demo:(function)}
function a()开始执行:
a handle a.[[scope]]--> 0:aAO{num:100,b(function)}
1:GO的引用
return b,并将b赋值给demo
b defined b.[[scope]]--> 0:aAO的引用
1:GO的引用
function a()执行完毕,将aAO的引用清空,但b任存在
function b()开始执行(执行2次):
b defined b.[[scope]]--> 0:
1:aAO的引用
2:GO的引用
例3:
function test(){
var arr = [];
for(var i = 0; i< 10; i++){
arr[i] = function(){
document.write(i + " ");
}
}
return arr;
}
var myArr = test();
for(var j = 0; j< 10; j++){
myArr[j]();
}
test defined test.[[scope]]--> 0:GO{test:(function),myArr:(function)}
test doing test.[[scope]]--> 0:testAO{arr:[],i:0;myArr:(function)}
1:GO的引用
arr[0]:function(){document.write(i + " ")};
arr[1]:function(){document.write(i + " ")};
....
arr[8]:function(){document.write(i + " ")};
arr[9]:function(){document.write(i + " ")};
return arr;
arr[j] defined arr[j].[[scope]]->0:testAO{arr:[],i:10;myArr:(function)}
1:GO{test:(function),myArr:(function)}
arr[j] doing arr[j].[[scope]]-> 0:{}
1:testAO{arr:[],i:10;myArr:(function)}
2:GO{test:(function),myArr:(function)}
arr[0]:function(){document.write(10 + " ")};
arr[1]:function(){document.write(10 + " ")};
....
arr[8]:function(){document.write(10 + " ")};
arr[9]:function(){document.write(10 + " ")};
例3 - 2:
//用闭包解决闭包的问题
// 立即执行函数被销毁之前,其上下文已经被里面的函数保存,
// 而且里面的函数整体也被保存到立即函数之外
function test(){
var arr = [];
for(var i = 0; i< 10; i++){//运行10次立即执行函数
//立即执行函数——用完即销毁。
(function (j){//每个立即执行的函数都有一个对应的j
arr[j] = function(){
document.write(j + " ");
}
}(i));//i只有一个,但是j是随函数循环次数不断产生新的
}
return arr;
}
var myArr = test();
for(var j = 0; j< 10; j++){
myArr[j](j);
}
//0 1 2 3 4 5 6 7 8 9
例4:
// 使用原生js,addEventListener,给每个li元素绑定一个
// click事件,输出他们的顺序。
function test(){
var liGroup = document.getElementsByTagName('li');
for(var i = 0; i < liGroup.length; i++){
(function(j){
liGroup[j].onclick = function(){
console.log(j);
}
}(i))
}
}
test();
闭包的运用①——累加器(更加结构化、模块化)
function add(){
var count = 0;
function demo(){
count++;
console.log(count);
}
return demo;
}
var counter = add();
counter();//1
counter();//2
counter();//3
counter();//4
闭包的运用②——缓存(存储结构)
function test(){
var num = 100;
function a(){
num++;
console.log(num);
}
function b(){
num--;
console.log(num);
}
return [a,b];
}
var myArr = test();
myArr[0]();
myArr[1]();
test defined test.[[scope]]--> 0:GO{test:(function),myArr:(function)}
test handle test.[[scope]]--> 0:testAO{num:100,a:(function),b:(function)}
1:GO的引用
return [a,b]后,function a()和function b()被保存到myArr[]中
a defined a.[[scope]]--> 0:testAO的引用
1:GO的引用
a handle a.[[scope]]--> 0:aAO{}
1:testAO的引用num:101=100+1
2:GO的引用
b defined b.[[scope]]--> 0:testAO的引用
1:GO的引用
b handle b.[[scope]]--> 0:bAO{}
1:testAO的引用num:100=101-1
2:GO的引用
function eater(){
var food = "";
var obj = {
eat : function(){
console.log("i am eating " + food);
food = "";
},
push :function(myFood){
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater1.push("apple");
eater1.eat();
//i am eating apple
闭包的运用③——私有化
function Deng(name,wife){
this.name = name;
this.wife = wife;
var prepareWife = 'xiaozhang';
this.divorce = function(){//divorce在外部执行怎么能用内部变量呢?
this.wife = prepareWife;
}
}
var deng = new Deng('deng','xiaoliu')
//deng.divorce();形成闭包,方法在对象上,对象被返回了,方法也被返回了
//该方法存储了Deng函数的执行上下文,所以能够获取prepareWife这个变量
//所以形成了这种局面:deng对象不能访问prepareWife,但deng的方法可以访问
//这样的闭包相当于是一个隐藏的区域,形成自己的私有变量
//所以你想看到这个变量,必须要调用其方法,否则无法访问
//这样的变量就相当于被对象私有化了,只有对象调用方法才能看到,外部想通过对象是看不到的
例5:
- 求一个字符串的字节长度(提示:字符串有一个方法charCodeAt();一个中文占两个字节,一个英文占一个字节定义和用法)
版本1:
var str = window.prompt("input");
function retBytesLen(target){
var count = 0;
for(i = 0; i < str.length; i++){
if(str.charCodeAt(i) <= 255){
count += 1;
}else{
count += 2;
}
}
document.write(count);
}
retBytesLen(str);
版本2:
var str = window.prompt("input");
function retBytesLen(target){
var count = target.length;
for(i = 0; i < target.length; i++){
if(target.charCodeAt(i) > 255){
count ++;
}
}
document.write(count);
}
retBytesLen(str);
例6:,号操作符——返回最后的表达式结果
var f = (
function f(){
return "1";
},
function g(){
return 2;
}
)()
console.log(typeof(f));//number
var x = 1;
if(function f(){}){ //function f(){}在一个括号里就会变成立即执行函数,即这行运行完后,该函数就不存在
x += typeof f;//typeof 一个未定义的变量不会报错,而是返回"undefined"
//x = x + undefined -->NaN
//x = x + "undefined" -->1undefined
}
console.log(x);//1undefined
例7:私有化变量
function Person(name,age,sex){
var a = 0;
this.name = name;
this.age = age;
this.sex = sex;
function sss(){
a++;
document.write(a);
}
this.say = sss;
}
var oPerson = new Person();
oPerson.say();//1
oPerson.say();//2
var oPerson1 = new Person();
oPerson1.say();//1