前端面試那些坑之JavaScript(一)

JavaScript

1、介紹js的基本數(shù)據(jù)類(lèi)型。

Undefined、Null、Boolean、Number、String、

ECMAScript 2015新增:Symbol(創(chuàng)建后獨(dú)一無(wú)二且不可變的數(shù)據(jù)類(lèi)型)

2、介紹js有哪些內(nèi)置對(duì)象?

Object是JavaScript中所有對(duì)象的父對(duì)象

數(shù)據(jù)封裝類(lèi)對(duì)象:Object、Array、Boolean、Number和String

其他對(duì)象:Function、Arguments、Math、Date、RegExp、Error

3、說(shuō)幾條寫(xiě)JavaScript的基本規(guī)范?

(1)不要在同一行聲明多個(gè)變量。

(2)請(qǐng)使用===/!==來(lái)比較true/false或者數(shù)值

(3)使用對(duì)象字面量替代new Array這種形式

(4)不要使用全局函數(shù)。

(5)Switch語(yǔ)句必須帶有default分支

(6)函數(shù)不應(yīng)該有時(shí)候有返回值,有時(shí)候沒(méi)有返回值。

(7)For循環(huán)必須使用大括號(hào)

(8)If語(yǔ)句必須使用大括號(hào)

(9)for-in循環(huán)中的變量應(yīng)該使用var關(guān)鍵字明確限定作用域,從而避免作用域污染。

4、JavaScript原型,原型鏈?有什么特點(diǎn)?

每個(gè)對(duì)象都會(huì)在其內(nèi)部初始化一個(gè)屬性,就是prototype(原型),當(dāng)我們?cè)L問(wèn)一個(gè)對(duì)象的屬性時(shí),

如果這個(gè)對(duì)象內(nèi)部不存在這個(gè)屬性,那么他就會(huì)去prototype里找這個(gè)屬性,這個(gè)prototype又會(huì)有自己的prototype,

于是就這樣一直找下去,也就是我們平時(shí)所說(shuō)的原型鏈的概念。

關(guān)系:instance.constructor.prototype = instance.__proto__

特點(diǎn):

JavaScript對(duì)象是通過(guò)引用來(lái)傳遞的,我們創(chuàng)建的每個(gè)新對(duì)象實(shí)體中并沒(méi)有一份屬于自己的原型副本。當(dāng)我們修改原型時(shí),與之相關(guān)的對(duì)象也會(huì)繼承這一改變。

當(dāng)我們需要一個(gè)屬性的時(shí),Javascript引擎會(huì)先看當(dāng)前對(duì)象中是否有這個(gè)屬性,如果沒(méi)有的話,

就會(huì)查找他的Prototype對(duì)象是否有這個(gè)屬性,如此遞推下去,一直檢索到Object內(nèi)建對(duì)象。

function Func(){}

Func.prototype.name = "Sean";

Func.prototype.getInfo = function() {

return this.name;

}

var person = new Func();//現(xiàn)在可以參考var person = Object.create(oldObject);

console.log(person.getInfo());//它擁有了Func的屬性和方法

//"Sean"

console.log(Func.prototype);

// Func {name="Sean", getInfo=function()}

5、JavaScript有幾種類(lèi)型的值?,你能畫(huà)一下他們的內(nèi)存圖嗎?

棧:原始數(shù)據(jù)類(lèi)型(Undefined,Null,Boolean,Number、String)

堆:引用數(shù)據(jù)類(lèi)型(對(duì)象、數(shù)組和函數(shù))

兩種類(lèi)型的區(qū)別是:存儲(chǔ)位置不同;

原始數(shù)據(jù)類(lèi)型直接存儲(chǔ)在棧(stack)中的簡(jiǎn)單數(shù)據(jù)段,占據(jù)空間小、大小固定,屬于被頻繁使用數(shù)據(jù),所以放入棧中存儲(chǔ);

引用數(shù)據(jù)類(lèi)型存儲(chǔ)在堆(heap)中的對(duì)象,占據(jù)空間大、大小不固定。如果存儲(chǔ)在棧中,將會(huì)影響程序運(yùn)行的性能;引用數(shù)據(jù)類(lèi)型在棧中存儲(chǔ)了指針,該指針指向堆中該實(shí)體的起始地址。當(dāng)解釋器尋找引用值時(shí),會(huì)首先檢索其在棧中的地址,取得地址后從堆中獲得實(shí)體


JavaScript有幾種類(lèi)型的值

6、如何將字符串轉(zhuǎn)化為數(shù)字,例如'12.3b'?

* parseFloat('12.3b');

*正則表達(dá)式,'12.3b'.match(/(\d)+(\.)?(\d)+/g)[0]* 1,但是這個(gè)不太靠譜,提供一種思路而已。

7、如何將浮點(diǎn)數(shù)點(diǎn)左邊的數(shù)每三位添加一個(gè)逗號(hào),如12000000.11轉(zhuǎn)化為『12,000,000.11』?

function commafy(num){

return num && num

.toString()

.replace(/(\d)(?=(\d{3})+\.)/g, function($1, $2){

return $2 + ',';

});

}

8、如何實(shí)現(xiàn)數(shù)組的隨機(jī)排序?

方法一:```javascriptvar arr = [1,2,3,4,5,6,7,8,9,10]; function randSort1(arr){ for(var i = 0,len =arr.length;i < len; i++ ){ var rand = parseInt(Math.random()*len); var temp= arr[rand]; arr[rand] = arr[i]; arr[i] = temp; } return arr; } console.log(randSort1(arr));

```

方法二:

```javascript

var arr = [1,2,3,4,5,6,7,8,9,10];

function randSort2(arr){

var mixedArray = [];

while(arr.length > 0){

var randomIndex =parseInt(Math.random()*arr.length);

mixedArray.push(arr[randomIndex]);

arr.splice(randomIndex, 1);

}

return mixedArray;

}

console.log(randSort2(arr));

```

方法三:

```javascript

var arr = [1,2,3,4,5,6,7,8,9,10];

arr.sort(function(){

return Math.random() - 0.5;

})

console.log(arr);

```

9、Javascript如何實(shí)現(xiàn)繼承?

(1)構(gòu)造繼承

(2)原型繼承

(3)實(shí)例繼承

(4)拷貝繼承

原型prototype機(jī)制或apply和call方法去實(shí)現(xiàn)較簡(jiǎn)單,建議使用構(gòu)造函數(shù)與原型混合方式。

```javascript

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);//得到被繼承的屬性

```

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

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

(1)對(duì)象字面量的方式

person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};

(2)用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();

(3)用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方法

(4)用工廠方式來(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();

(5)用原型方式來(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();

(6)用混合方式來(lái)創(chuàng)建

function Car(name,price){

this.name=name;

this.price=price;

}

Car.prototype.sell=function(){

alert("我是"+this.name+",我現(xiàn)在賣(mài)"+this.price+"萬(wàn)元");

}

var camry =new Car("凱美瑞",27);

camry.sell();

11、Javascript作用鏈域?

全局函數(shù)無(wú)法查看局部函數(shù)的內(nèi)部細(xì)節(jié),但局部函數(shù)可以查看其上層的函數(shù)細(xì)節(jié),直至全局細(xì)節(jié)。

當(dāng)需要從局部函數(shù)查找某一屬性或方法時(shí),如果當(dāng)前作用域沒(méi)有找到,就會(huì)上溯到上層作用域查找,

直至全局函數(shù),這種組織形式就是作用域鏈。

12、談?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;

13、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 +')');

14、什么是window對(duì)象?什么是document對(duì)象?

window對(duì)象是指瀏覽器打開(kāi)的窗口。

document對(duì)象是Documentd對(duì)象(HTML文檔對(duì)象)的一個(gè)只讀引用,window對(duì)象的一個(gè)屬性。

15、null,undefined的區(qū)別?

null表示一個(gè)對(duì)象是“沒(méi)有值”的值,也就是值為“空”;

undefined表示一個(gè)變量聲明了沒(méi)有初始化(賦值);

undefined不是一個(gè)有效的JSON,而null是;

undefined的類(lèi)型(typeof)是undefined;

null的類(lèi)型(typeof)是object;

Javascript將未賦值的變量默認(rèn)值設(shè)為undefined;

Javascript從來(lái)不會(huì)將變量設(shè)為null。它是用來(lái)讓程序員表明某個(gè)用var聲明的變量時(shí)沒(méi)有值的。

typeof undefined

//"undefined"

undefined :是一個(gè)表示"無(wú)"的原始值或者說(shuō)表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒(méi)有定義。當(dāng)嘗試讀取時(shí)會(huì)返回undefined;

例如變量被聲明了,但沒(méi)有賦值時(shí),就等于undefined

typeof null

//"object"

null :是一個(gè)對(duì)象(空對(duì)象,沒(méi)有任何屬性和方法);

例如作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對(duì)象;

注意:

在驗(yàn)證null時(shí),一定要使用===,因?yàn)?=無(wú)法分別null和undefined

null == undefined // true

null=== undefined // false

再來(lái)一個(gè)例子:

null

Q:有張三這個(gè)人么?

A:有!

Q:張三有房子么?

A:沒(méi)有!

undefined

Q:有張三這個(gè)人么?

A:有!

Q:張三有多少歲?

A:不知道(沒(méi)有被告訴)

16、寫(xiě)一個(gè)通用的事件偵聽(tīng)器函數(shù)。

// event(事件)工具集,來(lái)源:github.com/markyun

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ù):操作的元素,事件名稱(chēng),事件處理程序

addEvent : function(element, type, handler) {

if (element.addEventListener) {

//事件類(lèi)型、需要執(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;

}

};

17、["1","2", "3"].map(parseInt)答案是多少?

parseInt()函數(shù)能解析一個(gè)字符串,并返回一個(gè)整數(shù),需要兩個(gè)參數(shù)(val, radix),

其中radix表示要解析的數(shù)字的基數(shù)?!驹撝到橛? ~ 36之間,并且字符串中的數(shù)字不能大于radix才能正確返回?cái)?shù)字結(jié)果值】;

但此處map傳了3個(gè)(element, index, array),我們重寫(xiě)parseInt函數(shù)測(cè)試一下是否符合上面的規(guī)則。

function parseInt(str, radix) {

return str+'-'+radix;

};

var a=["1", "2","3"];

a.map(parseInt);? // ["1-0", "2-1","3-2"]不能大于radix

因?yàn)槎M(jìn)制里面,沒(méi)有數(shù)字3,導(dǎo)致出現(xiàn)超范圍的radix賦值和不合法的進(jìn)制解析,才會(huì)返回NaN

所以["1", "2", "3"].map(parseInt)答案也就是:[1,NaN, NaN]

18、事件是?IE與火狐的事件機(jī)制有什么區(qū)別?如何阻止冒泡?

(1)我們?cè)诰W(wǎng)頁(yè)中的某個(gè)操作(有的操作對(duì)應(yīng)多個(gè)事件)。例如:當(dāng)我們點(diǎn)擊一個(gè)按鈕就會(huì)產(chǎn)生一個(gè)事件。是可以被JavaScript偵測(cè)到的行為。

(2)事件處理機(jī)制:IE是事件冒泡、Firefox同時(shí)支持兩種事件模型,也就是:捕獲型事件和冒泡型事件;

(3)ev.stopPropagation();(舊ie的方法ev.cancelBubble = true;)

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

閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù),創(chuàng)建閉包的最常見(jiàn)的方式就是在一個(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ī)制回收

//li節(jié)點(diǎn)的onclick事件都能正確的彈出當(dāng)前被點(diǎn)擊的li索引

    index = 0

    index = 1

    index = 2

    index = 3

    var nodes = document.getElementsByTagName("li");

    for(i = 0;i

    nodes[i].onclick = (function(i){

    return function() {

    console.log(i);

    } //不用閉包的話,值每次都是4

    })(i);

    }

    執(zhí)行say667()后,say667()閉包內(nèi)部變量會(huì)存在,而閉包內(nèi)部函數(shù)的內(nèi)部變量不會(huì)存在

    使得Javascript的垃圾回收機(jī)制GC不會(huì)收回say667()所占用的資源

    因?yàn)閟ay667()的內(nèi)部函數(shù)的執(zhí)行需要依賴(lài)say667()中的變量

    這是對(duì)閉包作用的非常直白的描述

    function say667() {

    // Local variable that ends up within closure

    var num = 666;

    var sayAlert = function() {

    alert(num);

    }

    num++;

    return sayAlert;

    }

    varsayAlert = say667();

    sayAlert()//執(zhí)行結(jié)果應(yīng)該彈出的667

    20、javascript代碼中的"usestrict";是什么意思?使用它區(qū)別是什么?

    use strict是一種ECMAscript 5添加的(嚴(yán)格)運(yùn)行模式,這種模式使得Javascript在更嚴(yán)格的條件下運(yùn)行,

    使JS編碼更加規(guī)范化的模式,消除Javascript語(yǔ)法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為。

    默認(rèn)支持的糟糕特性都會(huì)被禁用,比如不能用with,也不能在意外的情況下給全局變量賦值;

    全局變量的顯示聲明,函數(shù)必須聲明在頂層,不允許在非函數(shù)代碼塊內(nèi)聲明函數(shù),arguments.callee也不允許使用;

    消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全,限制函數(shù)中的arguments修改,嚴(yán)格模式下的eval函數(shù)的行為和非嚴(yán)格模式的也不相同;

    提高編譯器效率,增加運(yùn)行速度;

    為未來(lái)新版本的Javascript標(biāo)準(zhǔn)化做鋪墊。


    京程一燈,夢(mèng)起的地方,我們始終相信通過(guò)努力,可以改變自己的命運(yùn)。

    我們始終相信,通過(guò)堅(jiān)持不懈,可以為大家解決更多的前端技術(shù)問(wèn)題。

    我們始終相信,時(shí)間可以證明,我們可以為廣大IT從業(yè)者解決前端學(xué)習(xí)路線。

    HTML5,CSS3,Web前端,jquery,javascript,前端學(xué)習(xí)路線,各類(lèi)問(wèn)題,我們都可以為你解決。

    更多技術(shù)好文,前端問(wèn)題,面試技巧,請(qǐng)關(guān)注京程一燈(原一燈學(xué)堂)

    最后編輯于
    ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
    【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
    平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

    相關(guān)閱讀更多精彩內(nèi)容

    友情鏈接更多精彩內(nèi)容