JS核心知識點梳理——上下文、做用域、閉包、this(下)

clipboard.png

引言

前面兩篇文章介紹了上下文、做用域、閉包、this。這裏我精心挑選了一些特別經典的面試題(不按期更新,跪求收藏)。相信經過這些題目能讓你徹底通關JS三座大三中的之一。javascript

閉包組:

這類題目仍是挺簡單的,我總結了幾個要注意的地方
1.有沒有閉包
2.若是有閉包,看建立了幾個閉包。換句話說,是在一個閉包內直接操做仍是操做完一個閉包,再建立一個新的閉包繼續操做
3.注意數據的歸屬,即數據存放在哪一個上下文環境java

一、

var n=0;
    function a(){
        var n=10;
        function b(){
            n++;
            console.log(n);
        }
        b();
        return b;
    }
    var c=a();
    c();
    console.log(n);
//11 12 0

二、

var a=9; 
function fn(){ 
    a=0;       //若是這裏是var a = 0 ,答案是多少
    return function(b){ 
        return b+a++; 
    }    
}
var f=fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);

// 5 5 6 2
// 若是是var a = 5 5 6 9

三、

var ary=[1,2,3,4];
function fn(ary){
    ary[0]=0;    
    ary=[0];    
    ary[0]=100;    
    return ary; 
}
var res=fn(ary);    
console.log(ary);    
console.log(res);
// [0,2,3,4] [100]

四、

function fn(i) {
    return function (n) {
        console.log(n + (i++));
    }
}
var f = fn(10);
f(20);
fn(20)(40);
fn(30)(50);
f(30);

//30 60 80 41

五、

var i = 10;
function fn() {
    return function (n) {
        console.log(n + (++i));
    }
}
var f = fn();
f(20);
fn()(20);
fn()(30);
f(30);
//31 32 43 44

六、如下代碼的功能是要實現爲5個input按鈕循環綁定click點擊事件,綁定完成後點擊一、二、三、四、5五個按鈕分別會alert輸出0、一、二、三、4五個字符。(騰訊)

請問以下代碼是否能實現?
若是不能實現那麼如今的效果是什麼樣的?
應該作怎樣的修改才能達到咱們想要的效果,並說明原理?es6

<div id="btnBox">
    <input type="button" value="button_1" />
    <input type="button" value="button_2" />
    <input type="button" value="button_3" />
    <input type="button" value="button_4" />
    <input type="button" value="button_5" />
</div>
<script type="text/javascript">
    var btnBox=document.getElementById('btnBox'),
    inputs=btnBox.getElementsByTagName('input');
    var l=inputs.length;
    for(var i=0;i<l;i++){
        inputs[i].onclick=function(){
            alert(i);
        }
    }
</script>

1.不能實現
2.由於js沒有塊做用域,因此公用的外層做用域的i,當點擊觸發函數的時候 ,應當注意外層的i是5了,因此所有打印5沒毛病
3.
解決思路1:沒有塊做用域我就用es6的let造成塊做用域面試

for(let i=0;i<l;i++){
     inputs[i].onclick=function(){
             alert(i);
     }
}

解決思路2:每次綁定的時候i其實都是正確的,我能不能用另一個變量將每次的i存起來呢?閉包

//這樣行嗎?
for(var i=0;i<l;i++){
        inputs[i].onclick=function(){
            var num = i  
            alert(num);
        }
    }
//這樣仍是不行,由於回調函數定義的時候並不會執行,因此當var num = i  執行的時候i已經等於5了

那麼我應該讓回調函數定義的時候裏面的代碼能當即執行,接收到參數0,1,2,3,4函數

for(var i=0;i<l;i++){
        inputs[i].onclick=(function(){
            var num = i  
            alert(num);
        })(i)
    }
//這樣也有問題i傳遞進去了,可是裏面核心代碼定義也執行了,我想讓它點擊的時候再執行
for(var i=0;i<l;i++){
        inputs[i].onclick=(function(){
            var num = i
            return function (e) { //注意這個時候e是啥,是點擊的事件
                console.log(num)
            }
        })(i)
    } //這樣就沒毛病了,返回一個方法,不會當即執行,i傳進去了,給了num,因爲有閉包,又不會被銷燬

還能怎麼優化?既然i能傳進去,我爲啥還要而外用個變量保存呢?優化

for(var i=0;i<l;i++){
        inputs[i].onclick=(function(x){//x是形參,因爲閉包存在,上下文不銷燬
            return function () { 
                console.log(x)
            }
        })(i)
    }

this組:

這類題目嚴格按上篇文章的分析思路,不復雜,就是麻煩一點。不要在腦子裏想,每步的結果用紙和筆演算下this

一、

var num = 10;
var obj = {num: 20};
obj.fn = (function (num) {
    this.num = num * 3;
    num++;
    return function (n) {
        this.num += n;
        num++;
        console.log(num);
    }
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num);
//22 23 65 30
相關文章
相關標籤/搜索