前端面試題集錦(Javascript篇)

請(qǐng)描述一下 JavaScript 事件冒泡機(jī)制?
JS事件捕獲與冒泡原型圖

當(dāng)頁(yè)面中某個(gè)元素的事件被觸發(fā)以后,比如點(diǎn)擊了頁(yè)面中的某個(gè)按鈕,
就觸發(fā)了當(dāng)前按鈕的點(diǎn)擊事件,但是 JavaScript 并不是簡(jiǎn)單就直接觸發(fā)該元素的相應(yīng)事件,
而是會(huì)首先從 DOM 樹的最頂層(window)依次的去觸發(fā)目標(biāo)(被直接點(diǎn)擊的)元素所有父級(jí)的同類事件,
直到觸發(fā)到目標(biāo)元素,然后又會(huì)再一次的從目標(biāo)元素開始觸發(fā)其所有父級(jí)的所有同類事件直到window,
也就是同類型事件的目標(biāo)元素與 window 之間觸發(fā)一個(gè)來(lái)回,
window 到目標(biāo)的觸發(fā)階段,我們稱為捕獲階段,
目標(biāo)觸發(fā)事件的時(shí)候我們稱為目標(biāo)階段,
而最后目標(biāo)到 window 的觸發(fā)階段,我們稱為冒泡階段。
這種機(jī)制我們稱為事件流(event flow),冒泡機(jī)制其實(shí)就是事件流機(jī)制中的冒泡階段規(guī)則。

出處:https://www.w3.org/TR/2016/WD-uievents-20160804/ 中的
3.1. Event dispatch and DOM event flow


JavaScript 的事件流模型都有什么?

分析:
事件流模型這個(gè)知識(shí)點(diǎn)在妙味中級(jí)階段 event 事件章節(jié)就有詳細(xì)講解,如果已經(jīng)忘記的朋友,再去看看這個(gè)階段的視頻吧。 題外話:一般純理論的知識(shí)點(diǎn)學(xué)起來(lái)枯燥(妙味實(shí)體班的學(xué)員也是如此),但理論的好處在于當(dāng)遇到問(wèn)題時(shí),能迅速判斷出錯(cuò)的原理所在,從而可以準(zhǔn)確迅速的查找問(wèn)題并精準(zhǔn)修復(fù),可以讓冗余代碼簡(jiǎn)化到最低、可以不再出了錯(cuò)以后像撞大運(yùn)般的采用 “試來(lái)試去大法” 來(lái)修復(fù)~

事件流描述的是從頁(yè)面中接收事件的順序。 DOM 結(jié)構(gòu)是樹形結(jié)構(gòu),當(dāng)頁(yè)面中的某一個(gè)元素觸發(fā)了某個(gè)一個(gè)事件,事件會(huì)從最頂層的 window 對(duì)象開始,向下傳播到目標(biāo)元素,途徑的祖先節(jié)點(diǎn)都會(huì)觸發(fā)對(duì)應(yīng)的事件,如果當(dāng)前節(jié)點(diǎn)的該事件綁定了事件處理函數(shù)的話,則會(huì)執(zhí)行該函數(shù)當(dāng)事件達(dá)到目標(biāo)元素并執(zhí)行綁定函數(shù)(如果有綁定的話)后,事件又會(huì)向上傳播到 window 元素,途徑的祖先節(jié)點(diǎn)都會(huì)觸發(fā)對(duì)應(yīng)的事件(如果綁定事件處理函數(shù)的話)

事件流包含三個(gè)階段:

  • 事件捕捉階段:事件開始由頂層對(duì)象觸發(fā),然后逐級(jí)向下傳播,直到目標(biāo)的元素;
  • 處于目標(biāo)階段:處在綁定事件的元素上;
  • 事件冒泡階段:事件由具體的元素先接收,然后逐級(jí)向上傳播,直到不具體的元素;

什么是閉包(closure),為什么要用它?

閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),通過(guò)另一個(gè)函數(shù)訪問(wèn)這個(gè)函數(shù)的局部變量,利用閉包可以突破作用鏈域,將函數(shù)內(nèi)部的變量和方法傳遞到外部。
閉包的特性

  1. 函數(shù)內(nèi)再嵌套函數(shù)
  2. 內(nèi)部函數(shù)可以引用外層的參數(shù)和變量
  3. 參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收

BOM 對(duì)象有哪些,列舉 window 對(duì)象?
  • window 對(duì)象,是 JS 的最頂層對(duì)象,其他的 BOM 對(duì)象都是 window 對(duì)象的屬性;
  • location 對(duì)象,瀏覽器當(dāng)前URL信息;
  • navigator 對(duì)象,瀏覽器本身信息;
  • screen 對(duì)象,客戶端屏幕信息;
  • history 對(duì)象,瀏覽器訪問(wèn)歷史信息;

new操作符具體干了什么呢?
  1. 創(chuàng)建一個(gè)空對(duì)象,并且 this 變量引用該對(duì)象,同時(shí)還繼承了該函數(shù)的原型。
  1. 屬性和方法被加入到 this 引用的對(duì)象中。
  2. 新創(chuàng)建的對(duì)象由 this 所引用,并且最后隱式的返回 this 。

"==" 和 "===" 有什么不同?
  1. 相同的是:== 和 === 都是比較等值比較運(yùn)算符,返回的布爾類型的比較結(jié)果。
  1. 不同的是:
    • == 是等值比較運(yùn)算符,使用的是 抽象等值 比較算法。
      === 是嚴(yán)格等值比較運(yùn)算符,使用的 嚴(yán)格等值 比較算法。
    • == 運(yùn)算符在比較值的時(shí)候,會(huì)根據(jù)兩者類型是否相同而做不同的處理,
      在兩者不同類型的時(shí)候,會(huì)轉(zhuǎn)換類型后進(jìn)行比較:
      基本類型會(huì)轉(zhuǎn)成數(shù)字,引用類型會(huì)轉(zhuǎn)成對(duì)象原始值,然后再進(jìn)行比較。
      而 === 首先也會(huì)判斷類型是否一致,不同的是如果類型不一致則直接返回 false。

資料參考:


如何判斷一個(gè)對(duì)象是否屬于某個(gè)類?

使用instanceof


Javascript中,有一個(gè)函數(shù),執(zhí)行時(shí)對(duì)象查找時(shí),永遠(yuǎn)不會(huì)去查找原型,這個(gè)函數(shù)是?

hasOwnProperty

+ hasOwnProperty函數(shù)方法是返回一個(gè)布爾值,
+ 指出一個(gè)對(duì)象是否具有指定名稱的屬性。
+ 此方法無(wú)法檢查該對(duì)象的原型鏈中是否具有該屬性;
+ 該屬性必須是對(duì)象本身的一個(gè)成員。
+如果 object 具有指定名稱的屬性,那么JavaScript中hasOwnProperty函數(shù)方法返回 true,反之則返回 false。

------
##### window.foo || (window.foo = "bar"); 返回值是什么?
>參考答案:
"bar"

>分析:
|| 又稱為短路或,短路:如果左側(cè)為真,則不再進(jìn)行右側(cè)運(yùn)算,同時(shí)返回左側(cè)表達(dá)式運(yùn)算結(jié)果。
如果左側(cè)為假則執(zhí)行右側(cè)表達(dá)式運(yùn)算,并返回右側(cè)計(jì)算結(jié)果。
上面window.foo是不存在的,所有結(jié)果為undefined,轉(zhuǎn)成boolean就是false,
那么就會(huì)運(yùn)算 window.foo = "bar",
把 "bar" 賦值給 window.foo 的同時(shí),
返回值也是 "foo",所以打印返回結(jié)果是 "bar"

------------------------------------------------------------------------------------------------
##### JavaScript 的 typeof 返回哪些數(shù)據(jù)類型?

> + **基礎(chǔ)類型**包括:Number、String、Boolean、Null、Undefined、Symbol(該類型位 ES2015 中新增類型)
+ **引用類型**包括:Object typeof 運(yùn)算符把類型信息以字符串形式返回,需要注意的是 typeof 返回的類型和 JavaScript 定義的類型有細(xì)微的差異。 typeof 返回七種可能的值:“number”、“string”、“boolean”、“object”、"symbol"、“function”和“undefined”。

------------------------------------------------------------------------------------------------
##### 請(qǐng)寫出以下運(yùn)算結(jié)果:

alert(typeof null); // object
alert(typeof undefined); // undefined
alert(typeof NaN); // number
alert(NaN == undefined); // false
alert(NaN == NaN); // false

var str = "123abc";
alert(typeof str++); // number
alert(str); // NaN

------------------------------------------------------------------------------------------------
##### null 和 undefined 的區(qū)別?
>+  ** null**表示空值,轉(zhuǎn)為數(shù)值時(shí)為0;
+ **undefined**表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒有定義。
+ 變量被聲明了,但沒有賦值時(shí),就等于undefined。
+ 對(duì)象沒有賦值的屬性,該屬性的值為undefined。
+ 函數(shù)沒有返回值時(shí),默認(rèn)返回undefined。

------------------------------------------------------------------------------------------------
##### 例舉至少 3 種強(qiáng)制類型轉(zhuǎn)換和 2 種隱式類型轉(zhuǎn)換?
> 1. 強(qiáng)制類型轉(zhuǎn)換: 明確調(diào)用內(nèi)置函數(shù),強(qiáng)制把一種類型的值轉(zhuǎn)換為另一種類型。強(qiáng)制類型轉(zhuǎn)換主要有:Boolean、Number、String、parseInt、parseFloat

>2. 隱式類型轉(zhuǎn)換: 在使用算術(shù)運(yùn)算符時(shí),運(yùn)算符兩邊的數(shù)據(jù)類型可以是任意的,比如,一個(gè)字符串可以和數(shù)字相加。之所以不同的數(shù)據(jù)類型之間可以做運(yùn)算,是因?yàn)?JavaScript 引擎在運(yùn)算之前會(huì)悄悄的把他們進(jìn)行了隱式類型轉(zhuǎn)換。隱式類型轉(zhuǎn)換主要有:+、–、==、!

------------------------------------------------------------------------------------------------
#####  $(".foo div#bar:eq(0)") 請(qǐng)優(yōu)化這段 JQuery 選擇器?

>參考答案:

> ```
$("#bar:eq(0)")

分析:
因?yàn)橛?id 選擇器,所以前面的 .foo div 是沒有必要的。


請(qǐng)解釋 JQuery 中 .end() 的用途?

參考答案:

返回當(dāng)前jq對(duì)象的上級(jí)jq對(duì)象

分析:

  1. 當(dāng)我們通過(guò)$()會(huì)得到一個(gè)對(duì)象
```

$jq1 = $('#div1');


>2. jq對(duì)象下有一系列的方法,有的方法會(huì)返回一個(gè)新的對(duì)象
// 通過(guò)$jq1的find返回了一個(gè)新的jquery對(duì)象

var $jq2 = $jq1.find('p');


>3. 這個(gè)時(shí)候在$jq2下面有一個(gè)屬性 prevObject,該屬性保存的就是 $jq1,通過(guò)比較 $jq2.prevObject == $jq1,會(huì)發(fā)現(xiàn)返回true。

>4. 通過(guò) prevObject 屬性會(huì)產(chǎn)生一個(gè)類似原型鏈的引用,
而 .end() 方法就是返回就是當(dāng)前 JQ 對(duì)象的 prevObject 對(duì)象,
也就是當(dāng)我們 $jq2.end() 的時(shí)候,返回的就是上層的 $jq1。

------------------------------------------------------------------------------------------------
##### 注冊(cè)賬號(hào)要求以字母開頭,可以包含字母、數(shù)字、下劃線,請(qǐng)寫出驗(yàn)證該賬號(hào)的正則表達(dá)式?
>參考答案:

/^[a-zA-Z]\w+$/


------------------------------------------------------------------------------------------------
##### 請(qǐng)列舉三種減低頁(yè)面加載時(shí)間的方法。(加載時(shí)間指感知的時(shí)間或者實(shí)際加載時(shí)間)
>參考答案:

>1. 減少實(shí)際加載時(shí)間
    1.  減少 http 請(qǐng)求(合并文件、合并圖片)
    2.  壓縮 JavaScript、CSS 代碼
    3.  啟用服務(wù)器壓縮傳輸(如 gzip)
    
>2. 減少感知時(shí)間
    1. script 外部腳本加載放到 html 最后進(jìn)行
    2. 按需加載資源(如:只加載當(dāng)前能看到的區(qū)域的圖片)

------------------------------------------------------------------------------------------------
##### "I'm lasagna hog".split("").reverse().jion(""); 語(yǔ)句的返回值是什么?

>參考答案:

goh angasal m'I


>分析:

>1. split(""),拆分字符串,得到數(shù)組:

["I", "'", "m", " ", "l", "a", "s", "a", "g", "n", "a", " ", "h", "o", "g"]

>2. 對(duì)數(shù)組使用.reverse(),翻轉(zhuǎn)數(shù)組,得到:

["g", "o", "h", " ", "a", "n", "g", "a", "s", "a", "l", " ", "m", "'", "I"]

>3. 最后使用join(""),把數(shù)組再次拼接成字符串,得到字符串:

goh angasal m'I


------------------------------------------------------------------------------------------------
#####  $(function(){console.log(1)}); 和 window.onload = function(){console.log(2)};執(zhí)行結(jié)果?詳細(xì)說(shuō)明原因?
>參考答案:

>先輸出2,再輸出1


>分析:

>這里重點(diǎn)是:JQ 的 $(function(){}) 和 window.onload = function(){},并不等同

>1. **window.onload **是頁(yè)面資源加載完成后觸發(fā)的事件,
比如頁(yè)面中有圖片需要加載,那么onload是等圖片加載完成以后才觸發(fā)的。

>2. **$(function) **監(jiān)聽的是 DOMContentLoaded 事件,而該事件只需要把 HTML 結(jié)構(gòu)加載完成就會(huì)觸發(fā)
(一般我們js操作的就是頁(yè)面元素,所以只需要等結(jié)構(gòu)加載完成能操作頁(yè)面元素就可以了)
所以該事件會(huì)比 onload 事件要先觸發(fā),所以 2 先執(zhí)行。

------------------------------------------------------------------------------------------------
##### 請(qǐng)指出 JQuery中 ".bind()"、".live()" 和 "delegate()" 的區(qū)別?

>參考答案:

>1. bind:把函數(shù)直接綁定到指定元素的指定事件上。
>2. live:把函數(shù)綁定到document上,接收選擇器和事件類型作為參數(shù),當(dāng)觸發(fā)一個(gè)元素的事件的時(shí)候,會(huì)利用事件冒泡到document上這一特性,判斷事件目標(biāo)元素和綁定參數(shù)中的選擇器是否匹配,如果匹配則執(zhí)行綁定函數(shù)的執(zhí)行。
3. delegate:和live有點(diǎn)類似,但是可以指定綁定元素,而不是document,其他和live一致,但是比live更加靈活。

------------------------------------------------------------------------------------------------
#####  請(qǐng)使用標(biāo)準(zhǔn)的 JSON 格式封裝一組學(xué)生信息數(shù)據(jù),內(nèi)容包括:姓名、性別、住址(包括城市、街道、門牌號(hào)、地鐵線)

[
{
"name": "北京妙味",
"gender": "男",
"address": {
"city": "北京",
"street": "西二旗輝煌國(guó)際"
"RoomNo": "6樓319室",
"subwayLine": "13"
}
},
{
"name": "上海妙味",
"gender": "男",
"address": {
"city": "上海",
"street": "閔行區(qū)新龍路七寶寶龍城"
"RoomNo": "T4樓9層902室",
"subwayLine": "9"
}
}
]


------------------------------------------------------------------------------------------------
#####  客戶查詢手機(jī)消費(fèi)清單要求:
實(shí)現(xiàn) A、B、C 三個(gè)異步接口,A 接口需傳參 user_name、mobi(用戶姓名和手機(jī)號(hào)碼),請(qǐng)求成功返回該用戶此手機(jī)號(hào)碼的消費(fèi)清單信息,user_name 可通過(guò)接口 B 獲取,mobi 可通過(guò)接口 C 獲取,請(qǐng)使用 JQuery 寫出具體的實(shí)現(xiàn)方法?

```javascript

function getUserName() {
    return $.ajax('/get_user_name.php');
}
function getMobi() {
    return $.ajax('/get_mobi.php');
}

$.when(getUserName(), getMobi()).then(function(data1, data2) {
    $.ajax({
        url: 'getConsumerList.php',
        data: {
            user_name: data1[0],
            mobi: data2[0],
        }
    }).success(function(consumerList) {
        //consumerList
    });
}, function() {
    console.log('獲取用戶名或手機(jī)號(hào)未成功');
});

請(qǐng)簡(jiǎn)述 AJAX 及基本步驟?
  • 初始化ajax對(duì)象
  • 連接地址,準(zhǔn)備數(shù)據(jù)
  • 發(fā)送請(qǐng)求
  • 接收數(shù)據(jù)(正在接收,尚未完成)
  • 接收數(shù)據(jù)完成
//初始化ajax對(duì)象
var xhr = new XMLHttpRequest();
//連接地址,準(zhǔn)備數(shù)據(jù)
xhr.open(“方式”,”地址”,是否為異步);
//接收數(shù)據(jù)完成觸發(fā)的事件
xhr.onload =function(){}
//發(fā)送數(shù)據(jù)
xhr.send();

js延遲加載的方式有哪些?

normaldefer和async、動(dòng)態(tài)創(chuàng)建DOM方式(用得最多)、按需異步載入js


同步和異步的區(qū)別?

概念1:同步異步可以說(shuō)是對(duì)被請(qǐng)求方來(lái)說(shuō)的,被請(qǐng)求者使用什么方式來(lái)告知處理結(jié)果。

  • 首先同步異步于阻塞非阻塞并沒有關(guān)系。同步異步主要是事情做完以后,如何進(jìn)行處理、或者說(shuō)關(guān)注的是一 種消息通信機(jī)制。
  • 同步的情況下,是由處理消息者自己去等待消息是否被觸發(fā);
  • 異步的情況下是由觸發(fā)機(jī)制來(lái)通知處理消息者;

概念2:同步可以是阻塞的也可以是非阻塞的,異步也是如此。

  • 阻塞非阻塞,主要是對(duì)于請(qǐng)求者而言的。
  • 阻塞:發(fā)出請(qǐng)求等待結(jié)果返回,然后再處理后續(xù)的事情;
  • 非阻塞:發(fā)出請(qǐng)求不等待結(jié)果返回,可以接著做后續(xù)的事情;

GET和POST的區(qū)別,何時(shí)使用POST?
  • GET:一般用于查詢數(shù)據(jù),使用URL傳遞參數(shù),由于瀏覽器對(duì)地址欄長(zhǎng)度有限制,所以對(duì)使用get方式所發(fā)送信息的數(shù)量有限制,同時(shí)瀏覽器會(huì)記錄(歷史記錄,緩存)中會(huì)保留請(qǐng)求地址的信息,包括地址后面的數(shù)據(jù)。get 只能發(fā)送普通格式(URL 編碼格式)的數(shù)據(jù)。
  • POST:一般用于向服務(wù)器發(fā)送數(shù)據(jù),對(duì)所發(fā)送的數(shù)據(jù)的大小理論上是沒有限制,瀏覽器會(huì)緩存記錄地址,但是不會(huì)記錄 post 提交的數(shù)據(jù)。post 可以發(fā)送純文本、URL編碼格式、二進(jìn)制格式的字符串,形式多樣。
  • 在以下情況中,請(qǐng)使用 POST 請(qǐng)求:
  1. 以提交為目的的請(qǐng)求(類似語(yǔ)義化,get 表示請(qǐng)求,post 表示提交);
  2. 發(fā)送私密類數(shù)據(jù)(用戶名、密碼)(因?yàn)闉g覽器緩存記錄特性);
  3. 向服務(wù)器發(fā)送大量數(shù)據(jù)(數(shù)據(jù)大小限制區(qū)別);
  4. 上傳文件圖片時(shí)(數(shù)據(jù)類型區(qū)別);

AJAX 的局限性?
  • AJAX 不支持瀏覽器 back 按鈕。
  • 安全問(wèn)題 AJAX 暴露了與服務(wù)器交互的細(xì)節(jié)。
  • 對(duì)搜索引擎的支持比較弱。不會(huì)執(zhí)行你的 JS 腳本,只會(huì)操作你的網(wǎng)頁(yè)源代碼;
  • 跨域請(qǐng)求有一定限制。解決方式:jsonp;

new 操作符具體干了什么呢?

當(dāng)使用 new 操作符調(diào)用構(gòu)造函數(shù),函數(shù)實(shí)際會(huì)經(jīng)歷如下步驟:

  • 創(chuàng)建一個(gè)新對(duì)象;
  • 把函數(shù)中上下文(作用域)對(duì)象this指向該對(duì)象;
  • 執(zhí)行代碼,通過(guò)this給新對(duì)象添加屬性或方法;
  • 返回對(duì)象;

JavaScript 原型,原型鏈 ? 有什么特點(diǎn)?
  • JavaScript 原型: 每創(chuàng)建一個(gè)函數(shù),函數(shù)上都有一個(gè)屬性為 prototype,它的值是一個(gè)對(duì)象。 這個(gè)對(duì)象的作用在于當(dāng)使用函數(shù)創(chuàng)建實(shí)例的時(shí)候,那么這些實(shí)例都會(huì)共享原型上的屬性和方法。
  • 原型鏈: 在 JavaScript 中,每個(gè)對(duì)象都有一個(gè)指向它的原型(prototype)對(duì)象的內(nèi)部鏈接(proto)。這個(gè)原型對(duì)象又有自己的原型,直到某個(gè)對(duì)象的原型為 null 為止(也就是不再有原型指向)。這種一級(jí)一級(jí)的鏈結(jié)構(gòu)就稱為原型鏈(prototype chain)。 當(dāng)查找一個(gè)對(duì)象的屬性時(shí),JavaScript 會(huì)向上遍歷原型鏈,直到找到給定名稱的屬性為止;到查找到達(dá)原型鏈的頂部(Object.prototype),仍然沒有找到指定的屬性,就會(huì)返回 undefined。

實(shí)現(xiàn)對(duì)數(shù)組進(jìn)行亂序
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var sign = 1; 
a.sort(function(a, b) {
    return Math.random() - 0.5
});

實(shí)現(xiàn)一個(gè)函數(shù) clone(),可以對(duì) JavaScript 中的5種主要的數(shù)據(jù)類型(包括 Number、String、Object、Array、Boolean)進(jìn)行值復(fù)制。

這道題考察了以下知識(shí)點(diǎn):

  • 使用 typeof 判斷值得類型;
  • 使用 toString 區(qū)分?jǐn)?shù)組和對(duì)象;
  • 遞歸函數(shù)的使用;
function clone(obj) {
    //判斷是對(duì)象,就進(jìn)行循環(huán)復(fù)制
    if (typeof obj === 'object' && typeof obj !== 'null') {
        // 區(qū)分是數(shù)組還是對(duì)象,創(chuàng)建空的數(shù)組或?qū)ο?        var o = Object.prototype.toString.call(obj).slice(8, -1) === "Array" ? [] : {};
        for (var k in obj) {
            // 如果屬性對(duì)應(yīng)的值為對(duì)象,則遞歸復(fù)制
            if(typeof obj[k] === 'object' && typeof obj[k] !== 'null'){
                o[k] = clone(obj[k])
            }else{
                o[k] = obj[k];
            }
        }
    }else{ //不為對(duì)象,直接把值返回
        return obj;
    }
    return o;
}

判斷代碼輸出結(jié)果
var test = 2;
console.log("test is a Number--" + (test.constructor == Number));  //true
function test1() {};
var t1 = new test1();
var test2 = "37degree";

console.info("typeof test--" + typeof test); //number
console.info("typeof test1--" + typeof test1);  //function
console.info("typeof t1--" + typeof t1);  //object
console.info("t1 instanceof test1--" + (t1 instanceof Object));   //true
console.info("test instanceof Array--" + (test instanceof Array));  //false

首先涉及到 JS 預(yù)解析的概念,這里的 變量申明 和 函數(shù)申明 都會(huì)被預(yù)解析處理,知道這個(gè)以后,那么下面一個(gè)一個(gè)來(lái)分析:

  • 第一個(gè):
    因?yàn)?test = 2 先執(zhí)行了,所以這里 test 的值已經(jīng)是一個(gè)數(shù)字了,那么 test.constructr 就是 Number,所以下面這個(gè)打印 true;
    console.log("test is a Number--" + (test.constructr == Number))
  • 第二個(gè):
    原因同上,需要注意 typeof 得到的結(jié)果 number 的 n 是小寫的!
  • 第三個(gè):
    test1 是一個(gè)函數(shù),typeof 值為 function;
  • 第四個(gè):
    通過(guò) new 得到的結(jié)果一定是一個(gè) Object,所以 t1 的 typeof 結(jié)果為 object;
  • 第五個(gè):
    這個(gè)題有點(diǎn)誤導(dǎo)人的,首先出題人寫的是 instanceof test1,但真正計(jì)算的卻是 instanceof Object,請(qǐng)注意它們的差異!不過(guò)不影響結(jié)果的,結(jié)果都是 true;
  • 第六個(gè):
    test 是一個(gè)數(shù)字,所以他的構(gòu)造函數(shù)應(yīng)是 Number,而不是 Array,所以結(jié)果為 false;

解釋 call 與 apply 的區(qū)別,并寫出下面代碼輸出的結(jié)果:
function add(a, b) {
    alert(a + b);
}
function sub(a, b) {
    alert(a - b);
}
add.call(sub, 3, 1)  //結(jié)果為 4
  • call 和 apply 都是函數(shù)下的一個(gè)靜態(tài)方法,可以通過(guò)函數(shù) .call() 或 函數(shù) .apply() 的方式來(lái)間接調(diào)用該函數(shù),通過(guò) call 或 apply 執(zhí)行時(shí)候的第一個(gè)參數(shù)改變?cè)摵瘮?shù)執(zhí)行過(guò)程中的上下文對(duì)象(this),如果第一個(gè)參數(shù)不存在或者設(shè)置成 null/undefined,那么該函數(shù)執(zhí)行過(guò)程中的上下文對(duì)象指向全局上下文對(duì)象,在 JavaScript 中指向了 window 對(duì)象。
  • 不同之處在于后續(xù)參數(shù)上,call 第一個(gè)參數(shù)以后的參數(shù)值將被一一對(duì)應(yīng)的賦值給源函數(shù)的形參,而 apply 則是傳入一個(gè)數(shù)組,間接傳給函數(shù)的 arguments 對(duì)象。

研究下面 JS 代碼是否有問(wèn)題,有問(wèn)題請(qǐng)描述問(wèn)題并解決,沒有問(wèn)題請(qǐng)回答最終結(jié)果。

代碼一:

var a = 10;
sayHi();
function sayHi() {
    a = a + 10;
    console.log(a);
    return a;
}
console.info(a);
console.info(sayHi() + 10);

代碼一分析:

//申明全局 a,值為 10
var a = 10;
sayHi();  //調(diào)用
function sayHi() {
    a = a + 10;  //這里的 a 是全局的 a,而不是局部的,所以執(zhí)行的結(jié)果是把全局 a 設(shè)置成了 20
    console.log(a);  //20
    return a;  //返回 20
}
console.info(a);  //全局 a 已經(jīng)是 20 了
console.info(sayHi() + 10);  //首先又一次執(zhí)行了 sayHi(),結(jié)果把 a 改成了 30,然后打印了一次 30,執(zhí)行完以后返回了 30,然后在加 10,打印結(jié)果 40

代碼二:

var a = 10;
sayHi();
function sayHi() {
    var a = a + 10;
    console.info(a);
    return a;
}
console.info(a);
console.info(sayHi() + 10);

代碼二分析:

//申明全局 a,值為 10
var a = 10;
//調(diào)用
sayHi();
function sayHi() {
    //注意這里有一個(gè) var,那么這里的 a 就是局部變量了,另外還是需要預(yù)解析一下,其實(shí)可以這么去看代碼:
    /*
    var a;  //申明未賦值,默認(rèn)值是 undefined
    a = a + 10;  // a = undefined + 10 結(jié)果是 NaN
    */
    var a = a + 10;
    console.info(a);  // NaN
    return a;  //返回 NaN
}
console.info(a);  //這個(gè)還是全局的 a,所以結(jié)果 10
console.info(sayHi() + 10); //依據(jù)上面的分析,這里的 sayHi 會(huì)打印一次 NaN,然后加 10,結(jié)果還是 NaN

代碼三:

function init() {
    var ps = document.getElementsByTagName("p");  //body內(nèi)有四個(gè)p標(biāo)簽
    for (var i=0; i<ps.length; i++) {
        ps[i].onclick = function() {
            console.info(i);
        }
    }
}

代碼三分析:

// 1. console.info(i); 的執(zhí)行是需要用戶點(diǎn)擊后執(zhí)行的,當(dāng)用戶點(diǎn)擊的時(shí)候,for 循環(huán)的執(zhí)行已經(jīng)結(jié)束,那么 i 的值已經(jīng)被設(shè)置成了 4,也就說(shuō)當(dāng)用戶去點(diǎn)擊的時(shí)候 i 的值已經(jīng)是 4 了;
// 2. 當(dāng) console.info(i); 執(zhí)行的時(shí)候,會(huì)根據(jù)作用域鏈去查找 i,這樣會(huì)找到 for 中定義的全局 i,這個(gè)時(shí)候不管點(diǎn)擊那個(gè) p 標(biāo)簽其實(shí)打印的都是全局 i 變量,所以結(jié)果都是統(tǒng)一的 4;

// 解決方案一:
function init() {
    var ps = document.getElementsByTagName("p");
    for (var i=0; i<ps.length; i++) {
        (function(n) {
            ps[n].onclick = function() {
                console.info(n);
            }
        })(i);
    }
}

// 解決方案二:
function init() {
    var ps = document.getElementsByTagName("p");
    for (let i=0; i<ps.length; i++) {
        ps[i].onclick = function() {
            console.info(i);
        }
    }
}

設(shè)計(jì)一個(gè)列表,包含:地域、人數(shù)、百分比、時(shí)間。請(qǐng)實(shí)現(xiàn)按照 人數(shù) 與 時(shí)間 的排序算法。
var data = [
    {
        area: '深圳',
        percentage: 15,
        number: 80,
        staytime: 2
    },
    {
        area: '北京',
        percentage: 30,
        number: 150,
        staytime: 4
    },
    {
        area: '廣州',
        percentage: 25,
        number: 60,
        staytime: 3
    },
    {
        area: '上海',
        percentage: 30,
        number: 100,
        staytime: 4
    }
];

/*
* 根據(jù)指定的字段和規(guī)則排序數(shù)據(jù)
* data Array 要排序的數(shù)據(jù)
* field string 排序依據(jù)的字段
* rule string 排序規(guī)則 DESC / ASC
* throw 
*       data is invalid : 要排序的數(shù)據(jù)不存在或類型不正確
*       field is invalid : 排序參考字段不存在
* return Array 排序后的數(shù)據(jù)
*/
function mySort(data, field, rule) {
    if (!(data instanceof Array)) {
        throw new TypeError('data is invalid');
    }
    if ( !(field in data[0]) ) {
        throw new RangeError('field is invalid');
    }
    if ( !rule || ['DESC','ASC'].indexOf( (rule = rule.toString().toUpperCase()) ) == -1 ) {
        rule = 'DESC';
    }
    
    data.sort(function(a, b) {
        var v = a[field] - b[field];
        return rule == 'ASC' ? v : -v;
    });
}

mySort(data, 'number', 'desc');
console.dir( data );

請(qǐng)列舉一些瀏覽器兼容性問(wèn)題?以及提高性能方面的方案

JS兼容問(wèn)題

  1. JSON 解析問(wèn)題:
    ecmascript5 通過(guò) JSON 對(duì)象進(jìn)行處理,ecmascript5 之前通過(guò) eval 進(jìn)行解析;
  1. 自定義屬性問(wèn)題:
    IE 下,可以使用獲取常規(guī)屬性的方法來(lái)獲取自定義屬性,也可以使用 getAttribute() 獲取自定義屬性;
    Firefox下,只能使用 getAttribute( )獲取自定義屬性。
    解決方法:
    統(tǒng)一通過(guò) getAttribute() 獲取自定義屬性,不過(guò)更推薦直接通過(guò) “點(diǎn)” 運(yùn)算符訪問(wèn)元素屬性。
  1. 事件對(duì)象兼容性問(wèn)題:
    非標(biāo)準(zhǔn) IE 和 chrome 下可以通過(guò)全局 event 對(duì)象來(lái)獲取,標(biāo)準(zhǔn)(包括標(biāo)準(zhǔn) IE,chrome 等)瀏覽器通過(guò)事件函數(shù)的第一個(gè)參數(shù)傳入。
  1. 事件源對(duì)象
    IE 下使用 event.srcElement,標(biāo)準(zhǔn)下使用 event.target 來(lái)獲取。
  1. 阻止事件冒泡
    通常可以通過(guò) event.cancelBubble = false 來(lái)阻止,但是標(biāo)準(zhǔn)推薦使用 event.stopPropagation() 方法來(lái)阻止;
  1. 事件默認(rèn)行為的阻止
    DOM1 事件綁定中(屬性 on... 的方式)可以通過(guò) return false 來(lái)阻止,但是在 DOM2 的事件綁定中(addEventListener)中,只能通過(guò) event.preventDefault() 方法來(lái)阻止。

其實(shí)還有很多……懶得寫了~~ ㄟ(▔,▔)ㄏ

**JS 優(yōu)化問(wèn)題 **

  1. 最小化 DOM 訪問(wèn)次數(shù),盡可能在 JS 端執(zhí)行;
  2. 如果需要多次訪問(wèn)某個(gè) DOM 節(jié)點(diǎn),請(qǐng)使用局部變量存儲(chǔ)對(duì)它的引用;
  3. 小心處理 HTML 集合,因?yàn)樗鼘?shí)時(shí)連系著底層的文檔,把集合的長(zhǎng)度緩存到一個(gè)變量中,并在迭代中使用它,如果需要經(jīng)常操作集合,建議把它拷貝到一個(gè)數(shù)組中;
  4. 如果可能的話,使用速度更快的 API,比如 querySelectorAll 和 firstElementChild;
  5. 要留意重繪和重排,批量修改樣式時(shí),“離線”操作 DOM 樹。使用緩存,并減少訪問(wèn)布局的次數(shù);
  6. 使用事件委托來(lái)減少事件處理器的數(shù)量;
  7. 避免多次訪問(wèn)對(duì)象成員或函數(shù)中的全局變量,盡量將它們賦值給局部變量以緩存;
  8. 能用 CSS 解決的問(wèn)題,盡量不用 JS 去解決;

寫一個(gè)通用的事件偵聽器函數(shù)?
markyun.Event = { // 頁(yè)面加載完成后 
    readyEvent: function(fn) {
        if (fn == null) {
            fn = document;
        }
        var oldonload = window.onload;
        if (typeof window.onload != 'function') {
            window.onload = fn;
        } else {
            window.onload = function() {
                oldonload();
                fn();
            };
        }
    },
    // 視能力分別使用dom0||dom2||IE方式 來(lái)綁定事件 
    // 參數(shù): 操作的元素,事件名稱 ,事件處理程序 
    addEvent: function(element, type, handler) {
        if (element.addEventListener) {
            //事件類型、需要執(zhí)行的函數(shù)、是否捕捉 
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent('on' + type, function() {
                handler.call(element);
            });
        } else {
            element['on' + type] = handler;
        }
    },
    // 移除事件 
    removeEvent: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.datachEvent) {
            element.detachEvent('on' + type, handler);
        } else {
            element['on' + type] = null;
        }
    },
    // 阻止事件 (主要是事件冒泡,因?yàn)镮E不支持事件捕獲) 
    stopPropagation: function(ev) {
        if (ev.stopPropagation) {
            ev.stopPropagation();
        } else {
            ev.cancelBubble = true;
        }
    },
    // 取消事件的默認(rèn)行為 
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    // 獲取事件目標(biāo) 
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    // 獲取event對(duì)象的引用,取到事件的所有信息,確保隨時(shí)能使用event; 
    getEvent: function(e) {
        var ev = e || window.event;
        if (!ev) {
            var c = this.getEvent.caller;
            while (c) {
                ev = c.arguments[0];
                if (ev && Event == ev.constructor) { break; }
                c = c.caller;
            }
        }
        return ev;
    }
};


eval是做什么的?
  • 它的功能是把對(duì)應(yīng)的字符串解析成JS代碼并運(yùn)行;
  • 應(yīng)該避免使用eval,不安全,非常耗性能(2次,一次解析成js語(yǔ)句,一次執(zhí)行)。
  • 由JSON字符串轉(zhuǎn)換為JSON對(duì)象的時(shí)候可以用eval,例如
var obj =eval('('+ str +')');

談?wù)凾his對(duì)象的理解。
  • this總是指向函數(shù)的直接調(diào)用者(而非間接調(diào)用者);
  • 如果有new關(guān)鍵字,this指向new出來(lái)的那個(gè)對(duì)象;
  • 在事件中,this指向觸發(fā)這個(gè)事件的對(duì)象,特殊的是,IE中的attachEvent中的this總是指向全局對(duì)象Window;

javascript創(chuàng)建對(duì)象的幾種方式?

javascript創(chuàng)建對(duì)象簡(jiǎn)單的說(shuō),無(wú)非就是使用內(nèi)置對(duì)象或各種自定義對(duì)象,當(dāng)然還可以用JSON;但寫法有很多種,也能混合使用。

  1. 對(duì)象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
  1. 用function來(lái)模擬無(wú)參的構(gòu)造函數(shù)
function Person() {}
var person = new Person(); //定義一個(gè)function,如果使用new"實(shí)例化",該function可以看作是一個(gè)Class person.name="Mark";
person.age = "25";
person.work = function() { 
      alert(person.name + " hello...");
}
person.work();
  1. **用function來(lái)模擬參構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)(用this關(guān)鍵字定義構(gòu)造的上下文屬性) **
function Pet(name, age, hobby) {
    this.name = name; //this作用域:當(dāng)前對(duì)象
    this.age = age;
    this.hobby = hobby;
    this.eat = function() {
        alert("我叫" + this.name + ",我喜歡" + this.hobby + ",是個(gè)程序員");
    };
}
var maidou = new Pet("麥兜", 25, "coding"); //實(shí)例化、創(chuàng)建對(duì)象 maidou.eat();//調(diào)用eat方法
  1. ** 用工廠方式來(lái)創(chuàng)建(內(nèi)置對(duì)象) **
var wcDog =new Object(); 
wcDog.name="旺財(cái)"; 
wcDog.age=3; 
wcDog.work=function(){
      alert("我是"+wcDog.name+",汪汪汪......");
 } 
wcDog.work();
  1. **用原型方式來(lái)創(chuàng)建 **
function Dog(){ } 
Dog.prototype.name="旺財(cái)";
Dog.prototype.eat=function(){
     alert(this.name+"是個(gè)吃貨");
 } 
var wangcai =new Dog(); 
wangcai.eat();
  1. **用混合方式來(lái)創(chuàng)建 **
function Car(name,price){
    this.name=name;
    this.price=price;
 } 
Car.prototype.sell=function(){
       alert("我是"+this.name+",我現(xiàn)在賣"+this.price+"萬(wàn)元");
 } 
var camry =new Car("凱美瑞",27); 
camry.sell();

Javascript如何實(shí)現(xiàn)繼承?
  1. 構(gòu)造繼承
  1. 原型繼承
  2. 實(shí)例繼承
  3. 拷貝繼承
//原型prototype機(jī)制或apply和call方法去實(shí)現(xiàn)較簡(jiǎn)單,建議使用構(gòu)造函數(shù)與原型混合方式。
function Parent(){ 
  this.name = 'wang'; 
} 
function Child(){ 
  this.age = 28; 
} 
Child.prototype = new Parent();//繼承了Parent,通過(guò)原型 
var demo = new Child(); 
alert(demo.age); 
alert(demo.name);//得到被繼承的屬性 }

持續(xù)更新........................

摘錄自 妙味課堂

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,634評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評(píng)論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,835評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,235評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,459評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,000評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,819評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,004評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,257評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評(píng)論 1 288
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,717評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,003評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 1.幾種基本數(shù)據(jù)類型?復(fù)雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結(jié)構(gòu)? 基本數(shù)據(jù)類型:Undefined、Nul...
    極樂(lè)君閱讀 5,555評(píng)論 0 106
  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    前端進(jìn)階之旅閱讀 114,526評(píng)論 24 450
  • 今天,終于發(fā)現(xiàn),如果在一起,今后我將永遠(yuǎn)活在回憶里。這并不是我想要的。你繼續(xù)逆反吧,因?yàn)椴幌喔傻娜耍幌喔傻氖拢?..
    高高的佳雨閱讀 118評(píng)論 0 0
  • 由“不同物種”構(gòu)成的人類社會(huì)的從林里,面對(duì)相同的事情,不同的物種釆用不同的策略,甚至完全相反的策略。以致于每個(gè)人的...
    _德成閱讀 405評(píng)論 2 3
  • 它矗立著,綠茵中撥開灌木叢的阻礙,我看見了它,就如同看見了第二個(gè)自己…… 看著自己成長(zhǎng)。 ...
    孫滸胡閱讀 351評(píng)論 0 0