闭包的实现原理,其实是利用了作用域链的特性,我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。
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]();
}
输出结果为10 10 10 10 10 10 10 10 10 10
arr[i] = function () {
document.write(i + " ");
}这个for循环中的语句前面arr[i]是赋值,等号后面的是函数引用,前面与等号后面的函数语句没有关系,只有等到for循环结束时,函数才会执行,而此时执行的是arr[10]
10个函数都与函数test形成闭包,被保存到外部,10个函数共用一个执行器上下文AO,每次i++都会改变AO中的值,所以在索取值的时候是10
function test() {
var arr = [];
for(var i = 0;i < 10; i ++) {
(function (j) {
arr[j] = function () {
document.write(j + " ");
}
} (i))
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++) {
myArr[j]();
}
输出结果为0 1 2 3 4 5 6 7 8 9
使用立即执行函数,10个立即执行函数都会生成10个值被保存到外部,每个立即执行函数都是挨个对应的
立即执行函数只要读到它就会立即被执行
闭包:函数嵌套,把里面的函数保存到外部,就会形成闭包
function a() {
function b() {
var bbb = 234;
document.write(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
输出结果为123;
这里因为有return b,所以函数b只有被定义,没有执行就被保存到全局
var demo;
function test() {
var abc = 100;
function a() {
console.log(abc);
}
demo = a;
}
test();
demo();
这种方法也可以实现内部函数保存到外部形成闭包
用闭包做缓存:
function test() {
var food = "apple";
var obj = {
eatFood : function () {
if(food != "") {
console.log("I am eating" + food);
food = "";
}else{
console.log("There is nothing! empty!")
}
},
pushFood : function (myFood) {
food = myFood;
}
}
return obj;
}
var person = test();
person.eatFood();
person.eatFood();
person.pushFood('banana');
person.eatFood();
输出结果为:
I am eating apple
There is nothing! empty!
I am eating banana
eg:
<ul>
<li>a</li>
<li>a</li>
<li>a</li>
<li>a</li>
</ul>
使用原生js,给每个li元素绑定一个click事件,输出他们的顺序
function test() {
var liCollection = document.getElementsByTagName('li');
for(var i = 0; i < liCollection.length; i++) {
liCollection[i].onclick = function() {
console.log(i);
}
}
}
test();
点击结果都为4,还是形成闭包的问题
解决:利用立即执行函数解决
function test() {
var liCollection = document.getElementsByTagName('li');
for(var i = 0; i < liCollection.length; i++) {
(function (j) {
liCollection[j].onclick = function() {
console.log(j);
}
}(i))
}
}
test();
eg:
写一个方法,求一个字符串的字节长度。(提示:字符串有一个方法charCodeAt();一个中文占两个字节,一个英文占一个字节)
定义和用法
charCodeAt()方法可返回指定位置的字符的Unicode编码.这个返回值是0-65535之间的整数。(当返回值是<=255时,为英文,当返回值>255时为中文)
语法:
stringObject.charCodeAt(index)
function retByteslen(target) {
var count = 0;
for(var i = 0; i < target.length; i++) {
if(target.charCodeAt(i) <= 255) {
count ++;
}else if(target.charCodeAt(i) > 255) {
count += 2;
}
}
console.log(count);
}
运行程序:retByteslen('');
简化代码:
function retByteslen(target) {
var count = target.length;
for(var i = 0; i < target.length; i++) {
if(target.charCodeAt(i) > 255) {
count ++;
}
}
console.log(count);
}
,运算符:var a = (2,3),逗号运算符会先计算两边的等式,然后把后边的结果赋值给a
eg:1.写出下面程序的执行结果
var f = (
function f() {
return "1";
},
function g() {
return 2;
}
)();
typeof f;
输出结果为number,因为有逗号运算符,所以把后边表达式的值赋值给f,所以为number
2.写出下面程序的执行结果:
var x = 1;
if(function f() {}) {
x += typeof f;
}
console.log(x);
输出结果为:1undefined
if中的function函数被当成表达式后就不是函数定义了,f将消失,所以typeof对于未定义的值为undefined,为字符串类型