前端面試中該問些什么?


3月份是找工作的高峰期,最近也面試了很多前端,然后本人也不是什么技術大牛,很多時候都不知道該從那些方面去考察一個人的技術水平,希望這篇文章能夠拋磚引玉,聽聽各位大神的意見,那么就來說說我面試前端主要問些什么吧。

首先,css和html的考察只要是簡歷上有幾個項目我都不會去多問,我個人偏好問的是js,那么就只能先對這語言的認識開始了。
 

一、JavaScript的對象。

JavaScript 中所有變量都是對象: 字符串、數值、數組、函數...,除了兩個例外 null 和  undefined。JavaScript 的對象只是帶有 屬性方法的特殊數據類型,
可以作為 哈希表使用,主要用來保存命名的鍵與值的對應關系。JavaScript 提供多個 內建對象,比如 String、Date、Array 等等。

此外,JavaScript 允許自定義對象,有兩種不同的方法:

  1. 定義並創建對象的實例
  2. 使用函數來定義對象,然后創建新的對象實例

1、創建直接的實例

person=new Object();
person.firstname="Bill";
person.lastname="Gates";
person.age=56;
person.eyecolor="blue";

這個例子創建了對象的一個新實例,並向其添加了四個屬性;此外,我們也可以通過對象字面量直接創建對象實例:person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};

2、使用對象構造器

使用函數來構造對象:

function person(firstname,lastname,age,eyecolor)
{
    this.firstname=firstname;
    this.lastname=lastname;
    this.age=age;
    this.eyecolor=eyecolor;
} 
參照來源: http://www.w3school.com.cn/js/js_objects.asp

 

二、JavaScript的面向對象。

  Javascript是一種基於對象(object-based)的語言,你遇到的所有東西幾乎都是對象。但是,它又不是一種真正的面向對象編程(OOP)語言,因為它的語法中沒有class(類)。JavaScript 不包含傳統的類繼承模型,而是使用 prototype 原型模型。雖然這經常被當作是 JavaScript 的缺點被提及,其實基於原型的繼承模型比傳統的類繼承還要強大。那么javascript是如何去實現繼承的呢?
 
比如,現在有一個"動物"對象的構造函數。
 
function Animal(){
  this.species = "動物";
}

還有一個"貓"對象的構造函數。

function Cat(name,color){
  this.name = name;
  this.color = color;
}

怎樣才能使"貓"繼承"動物"呢?

使用prototype屬性。

如果"貓"的prototype對象,指向一個Animal的實例,那么所有"貓"的實例,就能繼承Animal了。
  Cat.prototype = new Animal();
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動物

代碼的第一行,我們將Cat的prototype對象指向一個Animal的實例。

Cat.prototype = new Animal();

它相當於完全刪除了prototype 對象原先的值,然后賦予一個新值。但是,第二行又是什么意思呢?

Cat.prototype.constructor = Cat;

 原來,任何一個prototype對象都有一個constructor屬性,指向它的構造函數。如果沒有"Cat.prototype = new Animal();"這一行,Cat.prototype.constructor是指向Cat的;加了這一行以后Cat.prototype.constructor指向Animal。

alert(Cat.prototype.constructor == Animal); //true
更重要的是,每一個實例也有一個constructor屬性,默認調用prototype對象的constructor屬性。  
alert(cat1.constructor == Cat.prototype.constructor); // true
因此,在運行"Cat.prototype = new Animal();"這一行之后,cat1.constructor也指向Animal!  
alert(cat1.constructor == Animal); // true
這顯然會導致繼承鏈的紊亂(cat1明明是用構造函數Cat生成的),因此我們必須手動糾正,將Cat.prototype對象的constructor值改為Cat。這就是第二行的意思。
這是很重要的一點,編程時務必要遵守。下文都遵循這一點,即如果替換了prototype對象, 
o.prototype = {};

 

那么,下一步必然是為新的prototype對象加上constructor屬性,並將這個屬性指回原來的構造函數。
o.prototype.constructor = o;

這里還有另外一種方法,就是直接繼承prototype,這種方法是對第一種方法的改進。由於Animal對象中,不變的屬性都可以直接寫入Animal.prototype。所以,我們也可以讓Cat()跳過 Animal(),直接繼承Animal.prototype。

現在,我們先將Animal對象改寫:
function Animal(){ }
Animal.prototype.species = "動物";

然后,將Cat的prototype對象,然后指向Animal的prototype對象,這樣就完成了繼承。 

Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黃色");
alert(cat1.species); // 動物
與前一種方法相比,這樣做的優點是效率比較高(不用執行和建立Animal的實例了),比較省內存。缺點是 Cat.prototype和Animal.prototype現在指向了同一個對象,那么任何對Cat.prototype的修改,都會反映到Animal.prototype。
所以,上面這一段代碼其實是有問題的。請看第二行  
Cat.prototype.constructor = Cat;
這一句實際上把Animal.prototype對象的constructor屬性也改掉了!  
alert(Animal.prototype.constructor); // Cat
參照來源: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html  想要了解更多繼承實現的小伙伴可以看下這個博客
 

三、上下文(this的理解)。

JavaScript 有一套完全不同於其它語言的對 this 的處理機制。在五種不同的情況下 ,this 指向的各不相同。

1、全局范圍內this;

當在全部范圍內使用 this,它將會指向全局對象。瀏覽器中運行的 JavaScript 腳本,這個全局對象是 window。

2、函數調用

foo();
這里 this 也會指向全局對象。
ES5 注意: 在嚴格模式下(strict mode),不存在全局變量。 這種情況下 this 將會是 undefined。

3、方法調用

test.foo();
這個例子中,this 指向 test 對象。

4、調用構造函數

new foo();
如果函數傾向於和 new 關鍵詞一塊使用,則我們稱這個函數是 構造函數。在函數內部,this 指向新創建的對象。

5、顯式的設置 this

function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // 數組將會被擴展,如下所示
foo.call(bar, 1, 2, 3); // 傳遞到foo的參數是:a = 1, b = 2, c = 3
當使用 Function.prototype 上的 call 或者 apply 方法時,函數內的 this 將會被 顯式設置為函數調用的第一個參數。
因此函數調用的規則在上例中已經不適用了,在foo 函數內 this 被設置成了 bar。
 
注意: 在對象的字面聲明語法中,this 不能用來指向對象本身。 因此 var obj = {me: this} 中的 me 不會指向 obj,因為 this 只可能出現在上述的五種情況中。 譯者注:這個例子中,如果是在瀏覽器中運行,obj.me 等於 window 對象。
 

四、閉包

“官方”的解釋是:閉包是一個擁有許多變量和綁定了這些變量的環境的表達式(通常是一個函數),因而這些變量也是該表達式的一部分。
相信很少有人能直接看懂這句話,因為他描述的太學術。其實這句話通俗的來說就是:JavaScript中所有的function都是一個閉包。不過一般來說,嵌套的function所產生的閉包更為強大,也是大部分時候我們所謂的“閉包”。看下面這段代碼:
function a() {
    var i = 0;
    function b() {
        alert(++i);
    }
    return b;
}
var c = a();
c();
這段代碼有兩個特點:
函數b嵌套在函數a內部;
函數a返回函數b。
引用關系如圖:
 
 
這樣在執行完var c=a()后,變量c實際上是指向了函數b,b中用到了變量i,再執行c()后就會彈出一個窗口顯示i的值(第一次為1)。這段代碼其實就創建了一個閉包,為什么?因為函數a外的變量c引用了函數a內的函數b,就是說:
當函數a的內部函數b被函數a外的一個變量引用的時候,就創建了一個我們通常所謂的“閉包”。
讓我們說的更透徹一些。所謂“閉包”,就是在構造函數體內定義另外的函數作為目標對象的方法函數,而這個對象的方法函數反過來引用外層外層函數體中 的臨時變量。這使得只要目標 對象在生存期內始終能保持其方法,就能間接保持原構造函數體當時用到的臨時變量值。盡管最開始的構造函數調用已經結束,臨時變量的名稱也都消失了,但在目 標對象的方法內卻始終能引用到該變量的值,而且該值只能通這種方法來訪問。即使再次調用相同的構造函數,但只會生成新對象和方法,新的臨時變量只是對應新 的值,和上次那次調用的是各自獨立的。
簡而言之,閉包的作用就是在a執行完並返回后,閉包使得Javascript的垃圾回收機制GC不會收回a所占用的資源,因為a的內部函數b的執行需要依賴a中的變量。、

閉包的應用場景

保護函數內的變量安全。以最開始的例子為例,函數a中i只有函數b才能訪問,而無法通過其他途徑訪問到,因此保護了i的安全性。
在內存中維持一個變量。依然如前例,由於閉包,函數a中i的一直存在於內存中,因此每次執行c(),都會給i自加1。
通過保護變量的安全實現JS私有屬性和私有方法(不能被外部訪問)推薦閱讀:http://javascript.crockford.com/private.html
私有屬性和方法在Constructor外是無法被訪問的 
function Constructor(...) {
    var that = this;
    var membername = value;
    function membername(...) {...}
}
以上3點是閉包最基本的應用場景,很多經典案例都源於此。
參照來源: http://blog.csdn.net/adeyi/article/details/8808046  要理解更多的小伙伴可以訪問該鏈接
 

五、Javascript模塊化開發的實現

var module1 = (function(){
  var _count = 0;
  var m1 = function(){
      //...
  };
  var m2 = function(){
      //...
  };
  return {
    m1 : m1,
    m2 : m2
  };
})();
 
暫時先寫到這里了,這也是我在前端技術水平方向上幾個比較關注的點,如果是你的話會從哪些方面去考察呢,或者是你在面試的過程中又遇到那些印象比較深刻的題目呢,有興趣的話大家一起討論討論。。。
 

 

 


免責聲明!

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



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