談談我遇到的前端的一些神奇面試題


感謝大家批注指正,我不想誤導大家,我只是說我遇到過類似的題目,然后這里分析分析這些題目,並沒有說我們平時要這樣去寫代碼。js這門語言很靈活,有很多奇葩(坑),如果你不知道,哪天你無意間調到坑里去了你還不知道,有經驗的人應該都踩過無數js的坑。

去面試的時候有一些公司會給出面試題叫你做,前端的話一般有輸出結果的題,叫你寫出題目的輸出結果。我遇到過幾次,可是每次都感覺自己迷迷糊糊的,現在看來還是自己基礎不夠好導致了的。閑來沒事,總結總結,大神們,莫拍磚,我只是個前端小菜鳥。

先來看一組題目,如果你們全部答對,那直接看最底部的一題。 

//1、-------------------------------------------------------------------------------------
a()
var a = c = function() {
    console.log(2)
}
a()

function a() {
    console.log(1)
}
a();
(function(b) {
    b(), c()
    var b = c = function a() {
        console.log(3)
    }
    b()
})(a)
c()

//2、-------------------------------------------------------------------------------------


var A = function() {}
A.prototype.n = 1;

var b = new A()

A.prototype = {
    n: 2,
    m: 3
}

var c = new A()
console.log(b.n, b.m, c.n, c.m)

//3、-------------------------------------------------------------------------------------
(function f() {
    function f() {
        return 1;
    }
    return f();

    function f() {
        return 2;
    }
})();

//4、-------------------------------------------------------------------------------------
if (!(a in window)) {
    var a = 1;
}
console.log(a)

//5、-------------------------------------------------------------------------------------
function a() {}
var a;
console.log(typeof a)

//6、-------------------------------------------------------------------------------------
(function(b) {
    console.log(b)
    var b = c = 2
    console.log(b)
})(1)

//7、-------------------------------------------------------------------------------------
(function(b) {
    console.log(b)
    var b = c = 2
    console.log(b)

    function b() {}
    console.log(b)
})(1)

//8、-------------------------------------------------------------------------------------
var a = 10;

function fn() {
    console.log(1)
    var a = 100;
    console.log(a)
}
fn();

//9、-------------------------------------------------------------------------------------
var a = 1

function c(a, b) {
    console.log(a)
    a = 2
    console.log(a)
}
c()

 

以上題目考的知識點相對單一,無非就是預編譯和作用域,還沒牽扯太多東西。

研究以上題目我總結幾點

js對:var 后面的變量、函數參數、函數進行預編譯

來看看一些測試例子

只是var聲明的變量相關

var 聲明的變量a,就是顯示聲明的, 被預解析,賦值為undefined,既是常說變量提升。你在一個作用域任何一個地方聲明變量,都會被提升到作用域開始(接受意見意見加上)。

console.log(a)//undefined
var a=1;
console.log(a)//1

以上代碼約等於

var a = undefined
console.log(a) //undefined
a = 1;
console.log(a) //1

再看以下代碼,script標簽

<script>
    console.log(typeof a)//undefined
    var a='littlebear';
    console.log(a)//littlebear 
</script>
<script>
    console.log(typeof a)//string
    var a=1;
    console.log(a)//1
</script>

感覺以上代碼輸出正在,第二個script標簽里面的a 是string類型,是第一個script標簽先預編譯。第二個<script>標簽里的a但會往上查找。

在看下面這個

<script>
    console.log(typeof a)//undefined
    console.log(a)//報錯,遇到<script>標簽對時,會先對這一塊進行預解析,下面沒預解析,所以找不到聲明過的a,於是報錯了
</script>
<script>
    console.log(typeof a)//undefined
    var a=1;
    console.log(a)//1
</script>

第一個script標簽里的a,undefined,直接輸出啊,立馬報錯。因為在第一個script標簽的時候沒有發現a聲明過,沒聲明直接使用就會報錯。 第二個script標簽里面的輸出是我們預料之中的

得出一個結論:js的預編譯,是從有順序的,根據script標簽的順序從上到下執行的

 var聲明的變量和函數在一起的時候

<script>
     console.log(a)//function a(){}
     var a=1;
     console.log(a)//1
     function a(){}
     console.log(a)//1
</script>

第一個輸出的是function a(){},為什么會是這樣!! 我感覺是先預編譯變量,先給a賦值undefined,后來預編譯函數,函數a覆蓋了之前的變量a的默認值; 然后代碼順序執行到a=1;,這個時候賦值表達式給a賦值為1,所以后面輸出都是1。

var 聲明的變量和函數參數在一起的時候

<script>
    var a=10;
    function fn(a,b){
        console.log(a)//undefined      a會預編譯,此時輸出a,當前作用域能夠找到a,值是undefined。 所以不會向外搜索,也就不會是外部的10
        var a=10;
        console.log(a)//10
    }
    fn();
</script>

 

上面一種情況比較好理解,下面這種情況比較容易讓人混淆。

<script>
    function fn(a,b){
        console.log(a)//容易上當
        var a=10;
        console.log(a)//10
    }
    fn('容易上當');
</script>

函數有兩個參數a和b,內部有聲明了啊。調用fn的時候傳入了一個字符串。 看看內部的輸出,顯示輸出:容易上當,再是輸出10。這是為啥呢

預編譯階段會預編譯,var后面的變量,函數參數、函數。調用fn的時候傳入的參數a,b。 a和b會預編譯賦值undefined,調用發你,傳入'容易上當',a就被賦值為容易上當了。函數里面變量a的默認值就是參數a的值了,開始輸出a,也就是參數a值。后來遇到賦值表達式a=10,此時a就變成10了。

看下面這段代碼就想對簡單了

<script>
    var a=10;
    function fn(a,b){
        console.log(a)//undefined  這里不是10喲。 當前作用域能夠找到a的
        a=10;
        console.log(a)//10
    }
    fn();
</script>

函數,函數參數,var聲明的變量在一起的時候

<script>
    var a=10;
    function fn(a,b){
        console.log(a)//function a(){}   這里輸出function a(){}, 不是參數a的值,哈哈
        var a=10;
        console.log(a)//10
        function a(){}
        console.log(a)//10
    }
    fn(15);
</script>

fn里面有參數a,也有變量a,也有函數a,這種迷惑性更高。其實當你知道三者先后順序之后就不迷惑了

經過測試,我發現:參數a會覆蓋預編譯變量a的默認值,如果有函數,函數會覆蓋參數a的值,這個就是先后順序而已。

函數形參聲明--->函數聲明---->變量聲明  

來看一個綜合一點的,找找感覺

<script>
    a();//1
    var a = c = function() {
        console.log(2)
    };
    a();//2

    function a() {
        console.log(1)
    }
    a();//2
    (function(b) {
        b();//2    其實就是外部的a
        c();//2     c為什么是2? 也許有人以為這里會報錯,其實不會。 原因就在於var b=c=xxx。  c相當於沒有加var 不會預編譯,這里c直接查找到外部作用域的c
        var b = c = function a() {
            console.log(3)
        }
        b()//3
    })(a);//走到這里 a已經被賦值表達式重新賦值
    c();//3 由於沒加var 的原因 c已經被立即執行函數內部的賦值表達式改變了值 這里是3
</script>

 return 和函數、var聲明的變量在一起的時候

 由於預編譯,后面的a覆蓋了前面的a,所以return a的值 其實就是預編譯之后a的值,預編譯之后a的值就是第二個a。

<script>
    function fn(){
        function a(){console.log(1)}
        return a;
        function a(){console.log(2)}
    }
    fn()();//2
</script>

在看這個,也是一個容易坑人的題目

<script>
    var a=10;
    function fn(){
        //預編譯a 賦值undefined,內部作用域存在a這個變量,所以這里 !a 就是  !undefined,就是true,進入函數a=20;
        //但是后面的a怎么就是20呢,js沒有塊級作用域!! 不要小看js各種細節,夠折騰的
        if (!a) {
            var a=20
        }
        console.log(a)//  這里是20 ,
    }
    fn()
</script>

看起勁了,收不到了,再來一個

<script>
    //a in window ==>true 、 !true ===》false
    if (!(a in window)) {
        var a = 1;
    }
    console.log(a)// undefined
</script>

說了這么多,其實就是圍繞着js預編譯函數,var 聲明的變量就是顯示聲明的,會有變量提示、函數參數,搞懂先后順序,以后遇到類似的題目基本都是沒問題。

還有很多很多關於輸出結果的,基本圍繞着js的預編譯,作用域,函數上下文對象,以及這門語言的一些特性來展開的。多看看《Javascript語言精髓與編程實踐》 《Javascript高級程序設計第三版》加強基礎,題目萬變不離其中,都是考那些知識點。

接受大家的批評,我是菜鳥,不想誤人子弟。在一個作用域內變量的聲明順序,函數形參聲明--->函數聲明---->變量聲明 聲明是有先后順序的。任何一種聲明,如果在前面出現,都不會再次聲明。

 

再來一個 高級的,很多人都見過,但是我估計第一次能夠全部答對的人應該很少,即使答對,但是全部知道為什么的更少!

<script>
    var a = 10;
    var foo = {
        a: 20,
        bar: function () {
            var a = 30;
            return this.a;
        }
    };

    console.log(
        foo.bar(),             // 1.
        (foo.bar)(),           // 2.
        (foo.bar = foo.bar)(), // 3.
        (foo.bar, foo.bar)()   // 4.
        );
</script>

 本文地址http://www.cnblogs.com/Bond/p/4218639.html 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM