您的位置:首页 > Web前端 > JavaScript

JS——作用域 && 闭包

2017-09-20 10:02 155 查看

执行上下文

范围

一段
<script>
或者一个函数

全局(一段
<script>
)执行顺序

变量定义

函数声明

函数执行顺序

变量定义

函数声明

设定this

传入参数

consloe.log(a);    // undefined
var a = 100;

fn("Tim Chen");    // Tim Chen 20
function fn(name){
age = 20;
console.log(name,age);
var age;
}


第一个例子里执行顺序

var a = undefined;
console.log(a);
a = 20 ;


a还没有赋值,便已经打印了。所以最终结果是undefined。

第二个例子里执行顺序

function fn(name){
var age = undefined;
age = 20;
console.log(name,age);
};
fn("Tim Chen");


函数内部先声明变量,传入参数,然后对变量进行赋值,打印。

函数已经声明了,所以调用是可以执行的。

this

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

var a = {
name: "A",
fn: function(){
console.log(this.name);
}
}

a.fn();  // this === a

a.fn.call({name: "B"});  // this === {name : "B"}

var fn1 = a.fn;
fn1();  // this === window


构造函数使用

function Foo(name){
this.name = name;
}

var f = new Foo("Tim Chen");


对象属性使用

var a = {
name: "A",
fn: function(){
console.log(this.name);
}
}

a.fn();


普通函数使用

此时打印出来的结果是window

function fn(){
consoloe.log(this);
}
fn();


call/apply/bind使用

call()

此时打印出来的this === {x: 100}

function fn(name){
alert(name);
consoloe.log(this);
}
fn.call({x:100},"Tim Chen");


bind()

bind()只能是函数表达式用

var fn = function(name,age){
alert(name);
console.log(this);
}.bind({y:200});

fn("Tim Chen","22");


作用域

es5及以前,无块级作用域。

只有函数和全局作用域。

无块级作用域怎么理解?

所谓的块级作用域,就是说{}括号里自成一体,括号外访问不了括号内的变量、参数。

if(true){
var str = "成功读取";
}

console.log(str);    // 成功读取


上面的代码,从{}外面依然可以访问到里面的str变量。

函数和全局作用域

var a =100;

function fn(){
var a = 200;
console.log("fn",a);    //打印出来是函数内的变量a
}

console.log("global",a);    //打印出来是全局变量a
fn();


作用域链

如果函数调用了,当前作用域没有定义的变量(自由变量),它会去父级作用域找。父级也没有,就继续网上找。

这就叫作用域链。

注意,这个父级作用域指的是函数在定义时的父级,而不是执行时的父级

var a = 100;

function fn (){
var b = 200;

console.log(a);  //
}
fn();


闭包

function F1(){
var a = 100;

//返回值是一个函数
return function(){
console.log(a);
}
}

//fn1 得到一个函数
var fn1 = F1();
var a = 200;
fn1();


fn1执行的时候,其实就是执行console.log(a)。

上面的作用域链提到过,作用域调用自由变量的时候,会去它定义时的父级作用域寻找。在这个例子里,父级就是 F1函数。

所以最终执行的结果是100

使用场景

函数作为返回值(上面的例子)

函数作为参数传递

请看代码

function F1(){
var a = 100;

return function(){
console.log(a);
}
}

var fn1 = F1();
function F2(fn){
var a = 200;
fn();
}

F2(fn1);


还是那句话,自由变量会去它定义时的父级作用域寻找。

而不是调用时的作用域!!!

所以最终执行的结果是100

闭包在实际开发中的应用

封装变量,限制权限。

function isFirstLoad(){
var _list = [];
return function (id){
if(_list.indexOf(id)>=0){
return false;
}else{
_list.push(id);
return true;
}
}
}

//调用
var firstLoad = isFirstLoad();
firstLoad(10);  //true
firstLoad(10);  //false
firstLoad(20);  //true


例题讲解

1. 变量提升的理解(执行上下文)

变量定义

函数声明

2. 创建10个标签,点击弹出相应序号

错误写法:

var i , a;
for(i = 0; i < 10; i++){
a.document.createElement("a");
a.innerHTML = i +"<br />";
a.addEventListener("click",function(e){
e.preventDefault();
alert(i);   //这里的i是自由变量
})
document.body.appendChild(a);
}


在上面的代码中,因为不知道什么时候才发生click事件,早就循环完毕,此时i已经是10了。

正确写法

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);   //这里的i是自由变量
})
document.body.appendChild(a);
}(i);
}


在for循环里面,包裹着一个子调用函数,把i传进去作为参数。

每次循环,i的值都不一样。最后达到预期效果。

3. 如何理解作用域

自由变量

作用域链,即自由变量的查找

闭包的两个场景
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: