JavaSript作用域和闭包

执行上下文

在一段<script>或函数中。
先 全局:变量定义,函数申明
在 函数:变量定义,函数声明,this,argumnets

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(a)       //undefined
var a =100; //函数申明

fn('xiaohong') //xiaoming 20
function fn(name){ //函数表达式

console.log(this); //打印window
console.log(argumnets); //打印当前函数的name

age = 20 ;
console.log(name,age); //xiaohong,20
var age; //在JS中可以先赋值后定义
}

this

this 在不同函数中的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//构造函数
function Foo(name){
this.name = name
}
var f = new Foo('zhangsan')
console.log(f); //'zhangsan'

//对象属性
var obj = {
name:'A',
printName: function(){
console.log(this.name);
}
}
obj.printName(); //'A'

//普通函数
function fn(){
console.log(this); //this === window
}
fn();

//call apply bing
function fn1(name){
alert(name);
console.log(this);
}
fn1.call({x:100},'zhangsan',20); //call会把{x:100}传递给this

var fn2 = function(name,age){
alert(name);
console.log(this);
}.bind({x:200}) //bind会把{x:200}传递给this
fn2('zhangsan',20);

this 要在执行时才能确认值,定义是无法确认

1
2
3
4
5
6
7
8
9
10
11
var a = {
name:'A',
fn:function(){
console.log(this.name)
}
}

a.fn() //this === a
a.fn.call({name:'B'}) //this ==={name:'B'}
var fu1 = a.fn;
fn1(); //this === window

作用域

每个函数都有自己的一个”区域”运行。如下栗子:

1
2
3
4
5
6
7
8
9
10
11
12
var a= 100;
function fn(){
var b= 200;
function fn2(){
var c = 300;
console.log(a); //100
console.log(b); //200
console.log(c); //300
}
console.log(c); //错误,在fn()函数中就不能访问fn2()的值。
}
fn();

闭包

闭包:封装变量,收敛权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function foo(id){
var _list= [];
console.log(_list);
return function(id){
if(_list.indexOf(id) >=0){
return false;
}else{
_list.push(id)
return _list;
}
}
}
var fn = foo();
console.log(fn(10))
console.log(fn(10))
console.log(fn(20))

//在 fn 函数外面,根本不可能改掉_list

栗子

创建10个<a>标签,点击弹出数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
var i;
for(i=0;i<10;i++){
(function (i){ //函数作用域 匿名闭包函数。
var a = document.createElement('a')
a.innerHTML = i +'<br>'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i) //自由变量回去父作用域获取值
})
document.body.appendChild(a)
})(i)
//使用了闭包之后,我们会把循环中每一次i值的状态都保存下来。
}

匿名闭包函数作用:

减少了全局变量的个数,可以有效减少命名冲突
包在里面的变量对于外面来说是不可见的,他们的作用域近局限在匿名函数的函数体内
这种方式可以保存闭包外面的变量的状态,