前端試題本(Javascript篇)

JS1. 下面這個JS程序的輸出是什麼:
JS2.下面的JS程序輸出是什麼:
JS3.頁面有一個按鈕button id爲 button1,經過原生的js如何禁用?
JS4.頁面有一個按鈕button id爲 button1,經過原生的js 設置背景色爲紅色?
JS5.處理a.html文件時,如下哪行僞代碼可能致使內存越界或者拋出異常()
JS6.下面的代碼結果是
JS7.下面的代碼結果是
JS8.考察this(測試環境是瀏覽器,Node環境中全局對象有所不一樣)
JS九、var和函數的聲明提早
JS10.給基本類型數據添加屬性,不報錯,但取值時是undefined
JS十一、判斷一個字符串中出現次數最多的字符,並統計次數
JS12.經典閉包-實現一段腳本,使得點擊對應連接alert出相應的編號
JS13.事件處理程序中的this
JS14.請編寫一個JavaScript函數 parseQueryString,它的用途是把URL參數解析爲一個對象,如: var url =「http://witmax.cn/index.php?key0=0&key1=1&key2=2″
JS1五、下面兩個函數的返回值是同樣的嗎?爲何?
JS1六、下面的代碼會輸出什麼?爲何?
JS1七、解釋下面代碼的輸出
JS1八、給你一個 DOM 元素,建立一個能訪問該元素全部子元素的函數,而且要將每一個子元素傳遞給指定的回調函數。
JS19下面表達式的結果是:
JS20下列表達式的值
JS21下列表達式的值
JS22.寫出下面的輸出結果
JS23.Javascript做用鏈域?
JS24.new操做符具體幹了什麼呢?
JS25.用js實現千位分隔符?(來源:前端農民工,提示:正則+replace)
JS26.編寫一個JavaScript函數,輸入指定類型的選擇器(僅需支持id,class,tagName三種簡單CSS選擇器,無需兼容組合選擇器)能夠返回匹配的DOM節點,需考慮瀏覽器兼容性和性能。
JS27.實現一個函數clone,能夠對JavaScript中的5種主要的數據類型(包括Number、String、Object、Array、Boolean)進行值複製。
JS28.請評價如下代碼並給出改進意見
JS29.直接在對象的原型上添加方法是否安全?尤爲是在Object對象上。
JS30..在Javascript中什麼是僞數組?如何將僞數組轉化爲標準數組?
JS31.對做用域上下文和this的理解,看下列代碼:
JS32.原生JS的window.onload與Jquery的$(document).ready(function(){})有什麼不一樣?如何用原生JS實現Jq的ready方法?
JS32.(設計題)想實現一個對頁面某個節點的拖曳?如何作?(使用原生JS)
JS33.說出如下函數的做用是?空白區域應該填寫什麼?
JS34.看下面的代碼?問a怎麼變,匿名函數裏的this是什麼?怎麼改變裏面的this?匿名函數不能傳參怎麼改變obj.a的值?
JS35.移除數組中的元素
JS36.進制轉換
JS37.關於console.log的小題

JS1. 下面這個JS程序的輸出是什麼:

 
 
 
 
function Foo() { var i = 0; return function() { console.log(i++); } }var f1 = Foo(), f2 = Foo(); f1(); f1(); f2();

解析: 輸出爲:0,1,0 Foo函數返回一個匿名函數,這個匿名函數對Foo的內部變量 i 存在引用,因此只要指向匿名函數的變量不釋放(如 f1),i 的值就一直存在。故每次執行 f1() 都會增長 i 的值。而 f1,f2 指向的是兩個不一樣閉包,因此二者執行時互不影響。javascript


JS2.下面的JS程序輸出是什麼:

 
 
 
 
(function() { var a = b = 5; })(); console.log(b); console.log(a);

上面的輸出結果是:5,undefined 注意連續賦值,b其實是全局變量,若是啓用了嚴格模式,代碼就會引起ReferenceError的錯誤:B沒有定義(b is not defined)。請記住,嚴格模式,則須要明確指定,才能實現全局變量聲明。好比,你應該寫:php

 
 
 
 
(function() { 'use strict'; var a = window.b = 5; })(); console.log(b);

JS3.頁面有一個按鈕button id爲 button1,經過原生的js如何禁用?

A. document.getElementById("button1").readolny= true;
B. document.getElementById("button1").setAttribute(「readolny」,」true」);
C. document.getElementById("button1").disabled = true;
D. document.getElementById("button1").setAttribute(「disabled」,」true」);css

解析:這題的標準答案是C,毋庸置疑,答案D雖然也能達到預期的效果,可是實際上無論第二個參數爲何值都會值都會使按鈕處於禁用狀態,及時設置成布爾型的false.因此這個答案存在異議,不算是標準答案html


JS4.頁面有一個按鈕button id爲 button1,經過原生的js 設置背景色爲紅色?

A.document.getElementById('button1').style.backgroundColor="red";
B.document.getElementById('button1').style.backgroundcolor="red";
C.document.getElementById('button1').style.backGroundColor="red";
D.document.getElementById('button1').style.bgcolor="red";前端

解析:正確答案是A,js裏樣式設置直接把css寫法的的「-」去掉,再改寫爲駝峯寫法便可。java


JS5.處理a.html文件時,如下哪行僞代碼可能致使內存越界或者拋出異常()

 
 
 
 
int totalBlank = 0; int blankNum = 0; int taglen = page.taglst.size();A for(int i = 1; i < taglen-1; ++i) { //check blankB while(page.taglst[i] == "<br>" && i < taglen) {C ++totalBlank;D ++i; }E if(totalBlank > 10)F blankNum += totalBlank;G totalBlank = 0; }

注意:如下代碼中taglen是html文件中存在元素的個數,a.html中taglen的值是15,page.taglst[i]取的是a.html中的元素,例如page.taglst[1]的值是
a.html的文件以下:node

 
 
 
 
<!--這裏有一個空行--><html><title>test</title><body><div>aaaaaaa</div></body></html><br><br><br><br><br>

答案爲B,由於while(page.taglst[i] == "<br>" && i < taglen)這個判斷,先執行page.taglst[i] == "<br>"這個判斷,若是這個判斷返回值爲true,再執行i < taglen這個判斷。當i=taglen的時候,執行page.taglst[i] == "<br>"這個判斷就會越界,因此B處,最早出現越界面試


JS6.下面的代碼結果是

 
 
 
 
var f = function g(){ return 23; };typeof g();

答案:會發生錯誤ReferenceError: g is not defined
由於function g(){ return 23; }是函數表達式,事實上只有事一個名字,不是一個函數聲明,函數其實是綁定到變量f,不是g。正則表達式


JS7.下面的代碼結果是

 
 
 
 
var x = 1;if (function f(){} ){ x += typeof f;}console.log(x);//1undefined

這裏有個難點,if 中的 function f(){} 要如何處理?函數聲明的實際規則以下:函數聲明只能出如今程序或函數體內。從句法上講,它們 不能出如今Block(塊)({ … })中,例如不能出如今 if、while 或 for 語句中。由於 Block(塊) 中只能包含Statement語句, 而不能包含函數聲明這樣的源元素。另外一方面,仔細看一看規則也會發現,惟一可能讓表達式出如今Block(塊)中情形,就是讓它做爲表達式語句的一部分。可是,規範明確規定了表達式語句不能以關鍵字function開頭。而這實際上就是說,函數表達式一樣也不能出如今Statement語句或Block(塊)中(由於Block(塊)就是由Statement語句構成的)。關於這題的結果的內在原理並非很懂,彷彿if語句不存在直接執行了裏面的語句,又或者由於沒法解釋就把括號內的一坨直接當成了字符串爲真,f仍是沒有定義。chrome


JS8.考察this(測試環境是瀏覽器,Node環境中全局對象有所不一樣)

 
 
 
 
var length = 10;function fn() { console.log(this.length);}var obj = { length: 5, method: function(fn) { fn(); arguments[0](); }};obj.method(fn, 1);

正確結果是輸出:10 2

解析:牢記->JavaScript中函數調用一共有四種方式:方法調用模式、函數調用模式、構造器調用模式、apply/call調用模式.第一次調用fn()時是普通函數調用模式this指向全局window。咱們知道取對象屬於除了點操做符還能夠用中括號,因此第二次執行時至關於arguments調用方法,this指向arguments,而這裏傳了兩個參數,故輸出arguments長度爲2。


JS九、var和函數的聲明提早

 
 
 
 
function fn(a) { console.log(a); var a = 2; function a() {} console.log(a); }fn(1);輸出:function a() {} 2 //chrome測試

咱們知道var和function是會提早聲明的,並且函數聲明是優先於var聲明的(若是同時存在的話),這裏的優於能夠理解爲晚於變量聲明後(先提高變量再緊跟着函數聲明,函數聲明提高至關於整個函數塊包括代碼一塊兒移動到前面了),若是函數名和變量名相同,函數聲明就能覆蓋變量聲明,因此提早聲明後輸出的a是個function,而後代碼往下執行a進行從新賦值了,故第二次輸出是2。即便把第一句和第二句交換一下輸出結果不變


JS10.給基本類型數據添加屬性,不報錯,但取值時是undefined

 
 
 
 
var a = 10;a.pro = 10;console.log(a.pro + a);var s = 'hello';s.pro = 'world';console.log(s.pro + s);

答案:NaN undefinedhello

解析:給基本類型數據加屬性不報錯,可是引用的話返undefined,undefined+10返回NaN,這裏運用的規則是:對於加性操做符,若是一個操做數是樹值,另外一個操做數是undefined、null、布爾值時,則先調用Number()將非樹值轉換成數值,undefined會轉化成NaN,null轉換成0,布爾值轉化成1或者0.而undefined和字符串相加時轉變成了字符串,因此結果是undefiendhello


JS十一、判斷一個字符串中出現次數最多的字符,並統計次數

  • hash table方式:
 
 
 
 
var s = 'aaabbbcccaaabbbaaa';var obj = {};var maxn = -1;var letter;for(var i = 0; i < s.length; i++) { if(obj[s[i]]) { obj[s[i]]++; if(obj[s[i]] > maxn) { maxn = obj[s[i]]; letter = s[i]; } } else { obj[s[i]] = 1; if(obj[s[i]] > maxn) { maxn = obj[s[i]]; letter = s[i]; } }}alert(letter + ': ' + maxn);
  • 正則方式:
 
 
 
 
var s = 'aaabbbcccaaabbbaaabbbbbbbbbb';var a = s.split('');a.sort();s = a.join('');var pattern = /(\w)\1*/g;var ans = s.match(pattern);ans.sort(function(a, b) { return a.length < b.length;});;console.log(ans[0][0] + ': ' + ans[0].length);

JS12.經典閉包-實現一段腳本,使得點擊對應連接alert出相應的編號

  • dom污染法:
    <!-- 實現一段腳本,使得點擊對應連接alert出相應的編號 -->
 
 
 
 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><body> <a href='#'> 第一個連接 </a> </br> <a href='#'> 第二個連接 </a> </br> <a href='#'> 第三個連接 </a> </br> <a href='#'> 第四個連接 </a> </br> <script type="text/javascript"> var lis = document.links; for(var i = 0, length = lis.length; i < length; i++) { lis[i].index = i+1; lis[i].onclick = function() { alert(this.index); }; } </script></body>
  • 閉包:
    <!-- 實現一段腳本,使得點擊對應連接alert出相應的編號 -->
 
 
 
 
meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><body> <a href='#'> 第一個連接 </a> </br> <a href='#'> 第二個連接 </a> </br> <a href='#'> 第三個連接 </a> </br> <a href='#'> 第四個連接 </a> </br> <script type="text/javascript"> var lis = document.links; for(var i = 0, length = lis.length; i < length; i++) { (function(i) { lis[i].onclick = function() { alert(i + 1); }; })(i); } </script></body>

JS13.事件處理程序中的this

 
 
 
 
function JSClass() { this.m_Text = 'division element'; this.m_Element = document.createElement('div'); this.m_Element.innerHTML = this.m_Text; this.m_Element.addEventListener('click', this.func); // this.m_Element.onclick = this.func;}JSClass.prototype.Render = function() { document.body.appendChild(this.m_Element);}JSClass.prototype.func = function() { alert(this.m_Text);};var jc = new JSClass();jc.Render(); // add divjc.func(); // 輸出 division element

click添加的div元素division element會輸出underfined,爲何?
答案:division element undefined

解析:第一次輸出很好理解,func()做爲對象的方法調用,因此輸出division element,點擊添加的元素時,this其實已經指向this.m_Element,也就是事件的目標元素(事件對象的currentTarget屬性值-或者說是註冊事件處理程序的元素),由於是this.m_Element調用的addEventListener函數,因此內部的this全指向它了,而這個元素並無m_Text屬性,因此輸出undefined。


JS14.請編寫一個JavaScript函數 parseQueryString,它的用途是把URL參數解析爲一個對象,如: var url =「http://witmax.cn/index.php?key0=0&key1=1&key2=2

 
 
 
 
function parseQueryString(url) { var obj = {}; var a = url.split('?'); if(a.length === 1) return obj; var b = a[1].split('&'); for(var i = 0, length = b.length; i < length; i++) { var c = b[i].split('='); obj[c[0]] = c[1]; } return obj;} ``` 下面給出一個實際經常使用的更嚴謹的寫法(來自JavaScript高級程序設計): ```javascript function getQueryStringArgs() { //取得查詢字符串並去掉開頭的問號(這裏使用了BOM中的location對象) var qs=(location.search.length>0?location.search.substring(1):""), //保存數據的對象 args={}, //取得每一項 items=qs.length?qs.split('&'):[], item=null, name=null, value=null, i=0, len=items.length; for (i = 0; i <len; i++) { item=items[i].split("="); name=decodeURIComponent(item[0]); value=decodeURIComponent(item[1]); if (name.length) { args[name]=value; } } return args;}

還能夠藉助正則表達式

 
 
 
 
function getQueryObject(url) { url = url == null ? window.location.href : url; var search = url.substring(url.lastIndexOf("?") + 1); var obj = {}; var reg = /([^?&=]+)=([^?&=]*)/g; search.replace(reg, function (rs, $1, $2) { var name = decodeURIComponent($1); var val = decodeURIComponent($2); val = String(val); obj[name] = val; return rs; }); return obj;}

JS1五、下面兩個函數的返回值是同樣的嗎?爲何?

 
 
 
 
function foo1(){ return { bar: "hello" };}function foo2(){ return { bar: "hello" };}

在編程語言中,基本都是使用分號(;)將語句分隔開,這能夠增長代碼的可讀性和整潔性。而在JS中,如若語句各佔獨立一行,一般能夠省略語句間的分號(;),JS 解析器會根據可否正常編譯來決定是否自動填充分號:

 
 
 
 
var test = 1 + 2console.log(test); //3

在上述狀況下,爲了正確解析代碼,就不會自動填充分號了,可是對於 returnbreakcontinue 等語句,若是後面緊跟換行,解析器必定會自動在後面填充分號(;),因此上面的第二個函數就變成了這樣:

 
 
 
 
function foo2(){ return; { bar: "hello" };}

因此第二個函數是返回 undefined


JS1六、下面的代碼會輸出什麼?爲何?

 
 
 
 
var arr1 = "john".split('');var arr2 = arr1.reverse(); var arr3 = "jones".split(''); arr2.push(arr3);console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));

答案是array 1: length=5 last=j,o,n,e,s
array 2: length=5 last=j,o,n,e,s

解析:

  • 數組的reverse方法會將原數組反轉後返回,arr1指向反轉後的數組
  • JS中當從一個變量向另外一個變量複製引用類型的值時,會將存儲在變量對象中的值複製一份放到爲新變量分配的空間中。不一樣的是,這個值的副本其實是一個指針,而這個指針指向存儲在堆中的一個對象。複製操做結束後,兩個變量實際上將引用同一個對象。所以,改變其中一個變量,就會影響另外一個變量,以下圖所示:
    因此arr2和arr1實際上引用的是同一個對象。

JS1七、解釋下面代碼的輸出

 
 
 
 
var a={}, b={key:'b'}, c={key:'c'};a[b]=123;a[c]=456;console.log(a[b]);

輸出是 456,參考原文的解釋:

javascript中給對象添加和訪問屬性時會隱式的把屬性名轉換成字符串,由於b和c都是都是對象,轉換成字符串都是[object Object],所以兩次其實是設置了同一屬性a[[object Object]]


JS1八、給你一個 DOM 元素,建立一個能訪問該元素全部子元素的函數,而且要將每一個子元素傳遞給指定的回調函數。

函數接受兩個參數:

  • DOM
  • 指定的回調函數

原文利用 深度優先搜索(Depth-First-Search) 給了一個實現:

 
 
 
 
function Traverse(p_element,p_callback) { p_callback(p_element); var list = p_element.children; for (var i = 0; i < list.length; i++) { Traverse(list[i],p_callback); // recursive call }}

JS19下面表達式的結果是:

[1 < 2 < 3, 3 < 2 < 1]

這個題會讓人誤覺得是 2 > 1 && 2 < 3 其實不是的.
這個解題思路是

 
 
 
 
1 < 2 => true; true < 3 => 1 < 3 => true; 3 < 2 => false; false < 1 => 0 < 1 => true;

答案是 [true, true]


JS20下列表達式的值

 
 
 
 
var lowerCaseOnly = /^[a-z]+$/;console.log([lowerCaseOnly.test(null), lowerCaseOnly.test()])

執行時會使用toString方法將參數轉化成字符串「null」,"undefined",所以都返回true


JS21下列表達式的值

 
 
 
 
function captureOne(re, str) { var match = re.exec(str); return match && match[1];}var numRe = /num=(\d+)/ig, wordRe = /word=(\w+)/i, a1 = captureOne(numRe, "num=1"), a2 = captureOne(wordRe, "word=1"), a3 = captureOne(numRe, "NUM=2"), a4 = captureOne(wordRe, "WORD=2");[a1 === a2, a3 === a4]

由於第一個正則有一個 g 選項 它會‘記憶’他所匹配的內容, 等匹配後他會從上次匹配的索引繼續, 而第二個正則不會,因此 a1 = '1'; a2 = '1'; a3 = null; a4 = '2'


JS22.寫出下面的輸出結果

 
 
 
 
function Foo() { getName = function () { alert (1); }; return this;}Foo.getName = function () { alert (2);};Foo.prototype.getName = function () { alert (3);};var getName = function () { alert (4);};//聲明提高,可是賦值卻留在原地function getName() { alert (5);}//會總體提高//請寫出如下輸出結果:Foo.getName();//2getName();//4Foo().getName();//1getName();//1new Foo.getName();//2new Foo().getName();//3new new Foo().getName();//3

答案參考:一道常被人輕視的前端JS面試題


JS23.Javascript做用鏈域?

外部函數沒法查看內部函數的內部細節,但內部函數能夠查看其外層的函數細節,直至全局細節。當須要從局部函數查找某一屬性或方法時,若是當前做用域沒有找到,就會上溯到上層做用域查找,直至全局函數,這種組織形式就是做用域鏈。


JS24.new操做符具體幹了什麼呢?

一、建立一個空對象,而且 this 變量引用該對象,同時還繼承了該函數的原型。
二、屬性和方法被加入到 this 引用的對象中。
三、新建立的對象由 this 所引用,而且最後隱式的返回 this 。

 
 
 
 
var obj = {};obj.__proto__ = Base.prototype;Base.call(obj);

JS25.用js實現千位分隔符?(來源:前端農民工,提示:正則+replace)

 
 
 
 
function commafy(num) { num = num + ''; var reg = /(-?d+)(d{3})/; if(reg.test(num)){ num = num.replace(reg, '$1,$2'); } return num;}

JS26.編寫一個JavaScript函數,輸入指定類型的選擇器(僅需支持id,class,tagName三種簡單CSS選擇器,無需兼容組合選擇器)能夠返回匹配的DOM節點,需考慮瀏覽器兼容性和性能。

 
 
 
 
var $= function(selector) { var reg = /^([#\.])?(\w+)$/ig; var match = reg.exec(selector); var result = []; if (!match) {//若是沒有匹配 return; }else if (match[1]==="#") {//若是是ID return document.getElementById(match[2]); }else{//若是是類或者標籤選擇器 if (typeof document.querySelectorAll==='function') {//若是這個函數存在能夠直接處理類和標籤選擇器 return document.querySelectorAll(match[0]); }else{//若是上面牛逼的函數沒有,則要對類和標籤選擇器分別處理 if (match[1]) {//若是是類選擇器 return getElementsByClassName(match[2]);//自定義的類選擇函數 }else{ return getElementsByTagName(match[0]); } } }};/*自定義一個經過類名獲取元素的函數*/var getElementsByClassName=document.getElementsByClassName||function(className){ var tags=document.getElementsByTagName("*"); var result=[]; for (var i = 0,len=tags.length; i < len; i++) { if (tags[i].nodeType===1) { if (tags[i].className.split(/\s+/).indexOf(className)!==-1) {//由於可能存在多個類名以空格分隔,因此這樣處理一下比較符合要求 result.push(tags[i]); } } } return result;};

JS27.實現一個函數clone,能夠對JavaScript中的5種主要的數據類型(包括Number、String、Object、Array、Boolean)進行值複製。

 
 
 
 
/** * 對象克隆 * 支持基本數據類型及對象 * 遞歸方法 */function clone(obj) { var o; switch (typeof obj) { case "undefined": break; case "string": o = obj + ""; break; case "number": o = obj - 0; break; case "boolean": o = obj; break; case "object": // object 分爲兩種狀況 對象(Object)或數組(Array) if (obj === null) { o = null; } else { if (Object.prototype.toString.call(obj).indexOf("Array")! == -1) { o = []; for (var i = 0; i < obj.length; i++) { o.push(clone(obj[i])); } } else { o = {}; for (var k in obj) { o[k] = clone(obj[k]); } } } break; default: o = obj; break; } return o;}

JS28.請評價如下代碼並給出改進意見

 
 
 
 
if(window.addEventListener){ var addListener = function(el,type,listener,useCapture){ el.addEventListener(type,listener,useCapture); };}else if(document.all){ addListener = function(el,type,listener){ el.attachEvent("on"+type,function(){ listener.apply(el); }); } }

上述代碼的本意是定義一個跨瀏覽器兼容的事件監聽程序,主要有三個問題:一是addListener函數不該該在條件語句裏聲明和賦值,這樣作封裝性和移植性很很差;二是沒有考慮DOM0級的兼容性;三是使用的能力檢測不是很規範。改進以下:

 
 
 
 
var addListener=function(el,type,listener,useCapture){ if (el.addEventListener) { el.addEventListener(type,handle,useCapture); }else if(el.attachEvent){ el.attachEvent("on"+type,listener); }else{ el["on"+type]=listener; }}

JS29.直接在對象的原型上添加方法是否安全?尤爲是在Object對象上。

既然都這樣問了,確定是不安全的

  • 容易形成全局污染,和其餘庫衝突
  • 出了Bug不太好定位問題
  • 有可能出現代碼向上不兼容的狀況,好比定義了一個Object.prototype.clone。萬一ES七、ES8也定義了這個函數,那舊代碼不就會出現問題了嘛!
  • 在原型上添加方法會被全部實例共享
  • for…in..會列舉出添加在原型的方法

    應該根據實際狀況肯定是否能夠實施,或者在添加以前肯定是否該方法是否存在


JS30..在Javascript中什麼是僞數組?如何將僞數組轉化爲標準數組?

僞數組(類數組):沒法直接調用數組方法或指望length屬性有什麼特殊的行爲,但仍能夠對真正數組遍歷方法來遍歷它們。典型的是函數的argument參數,還有像調用getElementsByTagName,document.childNodes之類的,它們都返回NodeList對象都屬於僞數組。可使用Array.prototype.slice.call(fakeArray)將數組轉化爲真正的Array對象。要注意的是在IE8及之前,NodeList實現爲一個COM對象,要想將其轉換層數組,必須手動枚舉全部成員。下面的實現兼容性較強。

 
 
 
 
function converToArray(fakeArray){ var array = null; try{ array = Array.prototype.slice.call(fakeArray,0); }catch(ex){ array = new Array(); for( var i = 0 ,len = nodes.length; i < len ; i++ ) { array.push(fakeArray[i]) } } return array; }

JS31.對做用域上下文和this的理解,看下列代碼:

 
 
 
 
var User = { count: 1, getCount: function() { return this.count; }};console.log(User.getCount()); // what?var func = User.getCount;console.log(func()); // what?

問兩處 console 輸出什麼?爲何?
答案是 1 和 undefined。
func 是在 winodw 的上下文中被執行的,因此會訪問不到 count 屬性。那麼問題來了,如何確保Uesr老是能訪問到func的上下文,即正確返回1。答案:正確的方法是使用Function.prototype.bind。兼容各個瀏覽器完整代碼以下:

 
 
 
 
Function.prototype.bind = Function.prototype.bind || function(context) { var self = this; return function() { return self.apply(context, arguments); };} var func = User.getCount.bind(User);console.log(func())

JS32.原生JS的window.onload與Jquery的$(document).ready(function(){})有什麼不一樣?如何用原生JS實現Jq的ready方法?

  • window.onload()方法是必須等到頁面內包括圖片、CSS文件、JS文件等全部資源加載完畢後才能執行。
  • ( d o c u m e n t ) . r e a d y ( ) D O M w i n d o w . o n l o a d document.ready()能夠屢次調用,添加多個事件處理程序
 
 
 
 
document.ready=(function (){ var fns = []; //爲了支持多個事件處理函數,將添加的事件處理函數緩存在數組中 //執行全部緩存的事件處理函數 var run = function(){ for (var i = 0; i < fns.length; i++){ fns[i](); } } ; if (document.addEventListener) {//標準瀏覽器 document.addEventListener("DOMContentLoaded",function(){ // 註銷事件,避免反覆觸發 document.removeEventListener("DOMContentLoaded",arguments.callee,false); run();//執行函數 },false); }else if (document.attachEvent) {//IE瀏覽器 document.attachEvent('onreadystatechange',function(){ if (document.readyState=="interactive" || document.readyState=="complete") { document.detachEvent("onreadystatechange",arguments.callee); run(); } }); } //返回添加事件處理程序到緩存數組的函數,利用了閉包的特性 return function(fn){ fns.push(fn); } })(); //下面是測試代碼document.ready(function(){ alert("1");});document.ready(function(){ alert("2");});

參考:
Running code when the document is ready
《JavaScript高級程序設計-第三版》P390頁


JS32.(設計題)想實現一個對頁面某個節點的拖曳?如何作?(使用原生JS)

萬能的紅寶書《JavaScript高級程序設計》在第16章介紹了HTML5原生支持的拖放,在第22章也實現了不須要HTML5特性支持的拖放,咱們能夠直接參考。
若是瀏覽器支持HTML5,爲了使頁面元素具備拖放功能,只須要設置元素的draggable="true"便可。下面主要介紹在不支持HTML5狀況下的原生拖放。

  • 設置須要拖拽的節點絕對定位
  • 給須要拖拽的節點綁定mousedown, mousemove, mouseup事件
  • mousedown事件觸發後,開始拖拽
  • mousemove時,須要經過event.clientX和clientY獲取拖拽位置,並實時更新位置
  • mouseup時,拖拽結束
 
 
 
 
var DragDrop=function () { var dragging=null, diffx=0, diffy=0; function handleEvent(event){ event=event||window.event; var target=event.target||event.srcElement; switch(event.type){ case "mousedown": //若是該元素添加了draggable類,就認爲其能夠拖拽 if (target.className.indexOf("draggable")>-1) { dragging=target; diffx=event.clientX-target.offsetLeft; diffy=event.clientY-target.offsetTop; } break; case "mousemove": if (dragging!==null) { dragging.style.left=(event.clientX-diffx)+"px"; dragging.style.top=(event.clientY-diffy)+"px"; } break; case "mouseup": dragging=null; break; } } return{ enable:function(){//這裏偷懶未考慮事件監聽的兼容性 document.addEventListener("mousedown",handleEvent,false); document.addEventListener("mousemove",handleEvent,false); document.addEventListener("mouseup",handleEvent,false); }, disable:function(){ document.removeEventListener("mousedown",handleEvent,false); document.removeEventListener("mousemove",handleEvent,false); document.removeEventListener("mouseup",handleEvent,false); } }}();

JS33.說出如下函數的做用是?空白區域應該填寫什麼?

 
 
 
 
//define(function(window) { function fn(str) { this.str = str; } fn.prototype.format = function() { var arg = ______; return this.str.replace(_____, function(a, b) { return arg[b] || ""; }); } window.fn = fn;})(window);//use(function() { var t = new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>'); console.log(t.format('http://www.alibaba.com', 'Alibaba', 'Welcome'));})();

答案:訪函數的做用是使用format函數將函數的參數替換掉{0}這樣的內容,返回一個格式化後的結果:
第一個空是:arguments
第二個空是:/\{(\d+)\}/ig


JS34.看下面的代碼?問a怎麼變,匿名函數裏的this是什麼?怎麼改變裏面的this?匿名函數不能傳參怎麼改變obj.a的值?

 
 
 
 
var obj = { a : 1, func : function () { (function () { this.a = 2; }).call(this); } }; obj.func();

obj.a不變,匿名函數裏的this指向全局對象(window),至關於給window加了一個名爲a的屬性。
解決方案

  • 使用call或者apply方法
 
 
 
 
var obj = { a : 1, func : function () { (function () { this.a = 2; }).call(this); } }; obj.func(); console.log(obj.a);
  • 保存外部環境的上下文在內部使用
 
 
 
 
var obj = { a : 1, func : function () { var self=this; (function () { self.a = 2; })(); } }; obj.func(); console.log(obj.a);

JS35.移除數組中的元素

  • 返回新數組
 
 
 
 
function remove(arr, item) { return arr.filter(function(x) { return x !== item; }); }
 
 
 
 
function remove(arr, item) { var newArr = []; arr.forEach(function(e) { if(e !== item) { newArr.push(e); } }) return newArr; }
  • 直接在原數組上操做
 
 
 
 
function removeWithoutCopy(arr, item) { for(var i = 0; i < arr.length; i++) { if(item === arr[i]) { arr.splice(i, 1); i--; // for循環逆序的話,i--能夠省略 } } return arr;}
 
 
 
 
function removeWithoutCopy(arr, item) { var pos = arr.indexOf(item); while(pos !== -1) { arr.splice(pos, 1); pos = arr.indexOf(item); } return arr;}

JS36.進制轉換

十進制轉換成其餘進制

 
 
 
 
/** * [convert description] * @param {[number]} num [description] * @param {[number]} base [轉換後的基數] * @return {[type]} [description] */function convert(num, base) { return num.toString(base);}console.log(convert(16,2))//10000

其餘進制轉化成十進制

 
 
 
 
function convertFromD(num,base) { return parseInt(num,base);}console.log(convertFromD(11000,2))//24

JS37.關於console.log的小題

1.下面的表達式在瀏覽器中的結果是console仍是window

 
 
 
 
console.log.apply(console,this);

解析:筆試時竟然腦子短路判成了console,首先這裏傳入參數this時,這個this指向Window無疑,這裏的this是實參,在console.log函數中打印的就是這個Window,並無由於執行環境上下文是console而覆蓋參數。原本單獨執行console.log(),log方法就是做爲console對象的方法來調用,如今傳進去的環境仍是console.log,上面的語句實際上就是console.log(this)

2.輸出的字符串前統一加上(app) 這樣的字符串(考察arguments->args;apply)

 
 
 
 
function log(){ var args = Array.prototype.slice.call(arguments); args.unshift('(app)'); console.log.apply(console, args);};

參考:
(因爲不少題都是臨時收集,不少沒注意出處,請諒解)
你有必要知道的 25 個 JavaScript 面試題
javascript-puzzlers
BAT及各大互聯網公司2014前端筆試面試題–JavaScript篇



相關文章
相關標籤/搜索