es6有閉包嗎

2022-11-21 22:01:32

es6有閉包。在es6中,在一個函數內部建立另一個函數,把內嵌的函數稱為閉包,它可以存取外部函數的區域性變數;簡單來說,閉包指有權存取另一個函數作用域中變數的函數。閉包的主要作用:延伸了變數的作用範圍。由於閉包會使得函數中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。

前端(vue)入門到精通課程:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

一、變數作用域

變數根據作用域的不同分為兩種:全域性變數和區域性變數。

  • 函數內部可以使用全域性變數。

  • 函數外部不可以使用區域性變數。

  • 當函數執行完畢,本作用域內的區域性變數會銷燬。

二、什麼是閉包?

在es6中,閉包(closure)指有權存取另一個函數作用域中變數的函數。簡單理解:一個作用域可以存取另外一個函數內部的區域性變數。

閉包:在一個函數內部建立另一個函數,把內嵌的函數稱為閉包,它可以存取外部函數的區域性變數

	// fun 這個函數作用域 存取了另外一個函數 fn 裡面的區域性變數 num
    function fn(){
        let num = 10
        function fun(){
            console.log(num)
        }
        fun()
    }
    fn() //10
登入後複製

閉包的主要作用:延伸了變數的作用範圍。

	// fn 外面的作用域可以存取fn 內部的區域性變數
    function fn(){
        let num = 10
        // 方法一: 先定義再返回函數
        function fun(){
            console.log(num)
        }
        return fun //返回 fun函數
    }
    let f = fn()
    f() //10
登入後複製
	// fn 外面的作用域可以存取fn 內部的區域性變數
    function fn(){
        let num = 10
        // 方法二: 直接返回函數
        return function(){
            console.log(num)
        }
    }
    let f = fn()
    f() //10
登入後複製

三、閉包的使用場景

(1)用來返回值

//以閉包的形式將 name 返回
function fun(){
    let name = 'woniu'

    //定義閉包
    return function f1(){
        return name
    }
}

let ft = fun() //因為fun函數的返回值是f1函數,ft實質是一個函數

let na = ft()  //呼叫ft函數,實際呼叫的就是f1函數
console.log(na); //woniu
登入後複製

(2)函數賦值:在函數內部定義函數表示式

var f2
function fn(){
    let name = '曹操'
    f2 = function(){ //閉包,將外部函數的name變數作為閉包的返回值
        return name
    }
}
fn() //必須先呼叫fn函數,否則f2不是一個函數
console.log(f2());  //曹操
登入後複製

(3)把閉包作為函數的引數

function fn(){
    let name = '蝸牛學苑'

    //定義閉包
    return function callback(){
        return name
    }
}

let f1 = fn() //將fn函數的返回值callback賦給f1
function f2(temp){
    console.log(temp()) //輸出temp函數的返回值,實際呼叫了閉包callback
}
//呼叫f2函數:將f1作為實參傳遞給temp
f2(f1)
登入後複製

(4)立即執行函數中使用閉包

//立即執行函數
(function(){
    let name = '蝸牛學苑'
    let f1 = function(){
        return name
    }

    fn2(f1) //呼叫fn2函數,將閉包f1作為實參傳遞給fn2函數
})()

function fn2(temp){  //temp是一個形參,接收f1
    console.log(temp()); //對temp的呼叫,實際呼叫的是閉包f1
}
登入後複製

(5)迴圈賦值

(function(){
    for (let i = 1; i <= 10; i++) {
        (
            function(j){
                setTimeout(function(){
                    console.log(j);
                },j*1000)
            }
        )(i)
    }
})()
登入後複製

(6)將閉包封裝到物件中

function fun(){
    let name = '蝸牛學苑'
    setName = function(na){ //setName是閉包,用來設定外部函數的變數值
        name = na
    }
    getName = function(){ //getName是閉包,用來返回外部函數的變數值
        return name 
    }

    //外部fun函數的返回值,將閉包封裝到物件中返回
    return {
        setUserName:setName,
        getUserName:getName
    }
}
let obj =fun() //將fun函數返回值(物件)賦給obj
console.log('使用者名稱:',obj.getUserName()) //蝸牛學苑
obj.setUserName('石油學苑')
console.log('使用者名稱:',obj.getUserName()) //石油學苑
登入後複製

(7)通過閉包實現迭代

let arr = ['aa','bb','cc']
function fn(temp){ //外部函數的返回值是閉包
    let i = 0
    //定義閉包:迭代獲取陣列元素並返回
    return function(){
        return temp[i++] || '陣列已經遍歷結束'
    }
}

let f1 = fn(arr)
console.log(f1()) //aa
console.log(f1()) //bb
console.log(f1()) //cc
console.log(f1()) //陣列已經遍歷結束
登入後複製

(8)、首次區分(相同的引數,函數不會重複執行)

var fn = (function(){
    var arr = [] //用來快取的陣列
    return function(val){
        if(arr.indexOf(val) == -1){ //快取中沒有則表示需要執行
            arr.push(val) //將引數push到快取陣列中
            console.log('函數被執行了',arr);  //這裡寫想要執行的函數
        } else {
            console.log('此次函數不需要執行');
        }
        console.log('函數呼叫完列印一下,方便檢視快取的陣列:',arr);
    }
})()

fn(10)
fn(10)
fn(1000)
fn(20)
fn(1000)
登入後複製

注意

(1)搞清除誰是閉包函數

(2)分清楚閉包的返回值、外部函數的返回值

四、閉包總結

  • 閉包是什麼:閉包是一個函數(一個作用域可以存取另外一個函數的區域性變數)。

  • 閉包的作用是什麼:延伸變數的作用範圍。

沒有產生閉包,因為並沒有區域性變數,所以存取到的是全域性變數 The Window

let name = 'The Window'
    let object = {
        name: 'My Object',
        getNameFunc(){
            return function(){
                return this.name
            }
        }
    }
    let f = object.getNameFunc()
    console.log(f()) //The Window
登入後複製

產生了閉包:因為 this 在函數內部被賦值給了 that,指向的是 object 這個物件。

	let name = 'The Window'
    let object = {
        name: 'My Object',
        getNameFunc(){
            let that = this
            return function(){
               return that.name
            }
        }
    }
    let f = object.getNameFunc()
    console.log(f()) //My Object
登入後複製

使用閉包的注意點

1)由於閉包會使得函數中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函數之前,將不使用的區域性變數全部刪除。

2)閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變數的值。

【推薦學習:】

以上就是es6有閉包嗎的詳細內容,更多請關注TW511.COM其它相關文章!