JavaScript-總結(jié)篇之作用域和閉包

  • 說一下對變量提升的理解
  • 說明this幾種不同的使用場景
  • 創(chuàng)建10個<a>標(biāo)簽,點擊的時候彈出來對應(yīng)的序號
  • 如何理解作用域
  • 實際開發(fā)中閉包的應(yīng)用

執(zhí)行上下文

//Demo
console.log(a)  //undefined
var a = 100

fn('greentea')  //'greentea'  20
function fn(name){
  age = 20
  console.log(name,age)
  var age
}
  • 范圍:一段<script>或者一個函數(shù)
  • 全局:變量定義,函數(shù)聲明
  • 函數(shù):變量定義,函數(shù)聲明,this,arguments

執(zhí)行上下文,也就是將變量定義和函數(shù)聲明在代碼執(zhí)行前就提前的拿出來,定義的定義,聲明的聲明,但是變量因為沒賦值,所以a是undefined.fn函數(shù)已經(jīng)聲明過了,因此可以盡管去執(zhí)行它.在它的函數(shù)中,也會執(zhí)行上下文,同理,唯一注意的是,函數(shù)中的參數(shù)也相當(dāng)于定義.

關(guān)于函數(shù)聲明和函數(shù)表達式

fn()
function fn(){

}
fn1()   //報錯
var fn1 = function (){

}

兩者最大的區(qū)別是函數(shù)表達式相當(dāng)于變量定義,因此fn1 = undefined,在執(zhí)行fn1()時,肯定會報錯.

this

要在執(zhí)行時才能確認值,定義時無法確認

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

this的幾種情況

  • 作為構(gòu)造函數(shù)執(zhí)行
  • 作為對象屬性執(zhí)行
  • 作為普通函數(shù)執(zhí)行
  • call apply bind
call apply bind的區(qū)別
function fn1(name,age){
    alert(name)
    console.log(this)   
}
fn1.call({x:100},'zhangsan',20)
fn1.apply({x:100},['zhangsan',20])

var fn2 = function (name,age){
    console.log(this)
}.bind({y:200})
fn2('greentea',20)

this在函數(shù)中時,指向的是window,但是,當(dāng)用call,apply,bind以后,傳入的對象是this.

作用域和作用域鏈

首先,明確一點,JS無塊級作用域

var a = 100
function fn(){
    var b = 200

    //當(dāng)前作用域沒有定義的變量,即'自由變量'
    console.log(a)
    console.log(b)
}
fn()

作用域鏈的概念就是當(dāng)前作用域下沒有這個變量或函數(shù)的時候,那么它會向它的父級作用域查找,如果沒有會向父級的父級的作用域找....還有重要的一點就是,函數(shù)的父級作用域是在這個函數(shù)定義的時候,這個函數(shù)的父級作用域就已經(jīng)確定了,而不是在這個函數(shù)執(zhí)行的時候確定的.

閉包

function F1(){
    var a = 100
    //返回一個函數(shù)(函數(shù)作為返回值)
    return function(){
        console.log(a)
    }
}
//f1得到一個函數(shù)
var f1 = F1()
var a = 200
f1()    //100

在這段代碼中,最后的結(jié)果是100,f1執(zhí)行的函數(shù)是在F1中返回的匿名函數(shù),這個匿名函數(shù)是在F1定義的,因此這個匿名函數(shù)的變量應(yīng)該從它定義的父級中去找.

閉包的使用場景:
1.函數(shù)作為返回值
2.函數(shù)作為參數(shù)傳遞

function F1(){
    var a = 100
    //返回一個函數(shù)(函數(shù)作為返回值)
    return function(){
        console.log(a)
    }
}
//f1得到一個函數(shù)
var f1 = F1()
function F2(fn){
    var a = 200
    fn()
}
F2(f1)     //和上面同理,關(guān)鍵是找對了函數(shù)定義時的父級作用域

下面是一個例子

//舉一個錯誤的例子
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)
    })
    document.body.appendChild(a)
}
//正確的例子
var i,a
for (i = 0; i < 10; i++) {
    (function(i){
        a = document.createElement('a')
        a.innerHTML = i + '<br>'
        a.addEventListener('click',function(e){
            e.preventDefault()
            alert(i)
        })
        document.body.appendChild(a)
    })(i)
}

關(guān)于閉包的一個應(yīng)用例子

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
firstload(20)   //false

你在isFirstLoad函數(shù)外,不能修改掉_list的值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容