javascript理解

近期在阅读alloyteam的《JavaScript设计模式与开发实践》,学习了其中一些编程的相关和代码组织的方式

hosting机制

相关知识点

  • 函数的形式分为函数表达式和函数的声明,使用回调函数进行传参使用的是函数表达式
  • 变量的声明和函数的声明会被提升,不同的是函数的定义会和声明一起提升
  • 变量的赋值语句并不会随之提升

变量提升

1
2
3
4
b();
function b () {
console.log(233);
}

此代码能够正常运行, 因为定义也跟着提升

1
2
3
4
5
console.log(game);
var game = function play() {
console.log(233);
}
game();

赋值语句当中的是函数表达式,并不会被提升,同时定义的函数标识符play只能够在函数内部引用,在外边是无法找到的。同时提升的只有变量的声明,所以是undefined;

特殊情况
函数和变量在同一个作用域下,变量提升当中如果存在相同的名称,则函数名会覆盖变量名,但是各自的初始化赋值就是严格按照顺序的。

立即执行函数(IIFE)

相关知识点

  • 可以在函数的function前面加上!+ -()这样的符号,将函数标识为立即执行函数
  • 主要的作用是创建函数的私有作用域,防止作用域之间变量的相互污染
  • 将一个立即执行函数赋值给一个变量,变量的值是函数的返回值,在代码运行当中确定
  • 同样立即执行函数的函数名也只能在内部函数当中引用
1
2
3
4
5
6
7
8
var a = function() {
return 233;
};
var b = (function() {
return 233;
})()
console.log(a);
console.log(b);

可以看出a的类型是一个函数,b的类型是立即执行函数的返回值,就是一个数

函数闭包

相关知识点

  • JavaScript是函数作用域,在函数外部无法访问函数内部的变量、
  • 闭包将函数内部的变量传递到外面,让外部作用域可以访问函数内部的变量
  • 只要存在引用函数内部变量的可能,JavaScript都会在内存中保存这个变量,直到最后一个引用解除,JavaScript的垃圾收集器才会释放相应的内存空间
1
2
3
4
5
6
7
8
9
10
11
function outer() {
var a = 0;
function inner() {
return ++a;
}
return inner;
}
var b = outer();
console.log(b());
console.log(b());
console.log(b());

这段代码当中,首先在函数内部定义一个局部变量,然后再定义一个局部的函数,函数引用了这个变量,并把变量返回,注意我们在外层函数返回的是一个函数,因此b实际上是内层函数,b()才是这个返回值,也就是引用的局部变量。

立即执行函数与闭包

使用立即函数,能够使得代码更加简洁,同时防止作用域之间的相互污染

1
2
3
4
5
6
var b = (function() {
var a = 0;
return function() {
return ++a;
}
})()

其实外部函数的作用是创建一个函数作用域让外部无法访问内部定义的变量,起到封装的作用,因此我们可以使用立即执行函数转化成函数表达式,而不是函数的声明。而且这样定义,b直接就是内部函数的值,而不是外部函数(如果直接 var b = function…)

对比下面代码

1
2
3
4
5
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}

函数执行异步调用,当执行这个回调函数的时候,往外部作用域找,找的是已经执行好的i

1
2
3
4
5
for (var i = 0; i < 3; i++) {
setTimeout((function() {
console.log(i);
})(i), 0);
}

这个时候我们就应该在函数执行的时候动态的创建一个函数作用域去保存状态,把i当做局部变量传进去