前端面試之路二(javaScript基礎整理)

kinshan發表於2019-02-12

一、變數型別和計算

JS中使用typeof能得到哪些型別

變數型別
  • 值型別:變數本身就是含有賦予給它的數值的,它的變數本身及儲存的資料都儲存在棧的記憶體塊當中
  • 引用型別:引用型別當然是分配到堆上的物件或者資料變數,根據官方一點的解釋就是引用型別的變數只包括對其所表示的資料引用
    • 物件、陣列、函式
    • 無限擴充套件屬性,可能出現記憶體佔用比較大的情況
typeof abc      //"undefined"
typeof NaN      //"number"
typeof null     //"object"
typeof console.log //"function"
複製程式碼

typeof只能區分值型別,對引用型別無能為力,只能區分函式function
NaN表示特殊的非數字值,null是空指標,並沒有指向任何一個地址
typeof能區分的五種基本型別:stringbooleannumberundefinedsymbol和函式function

變數計算

可能發生強制型別轉換的情況:
  • 字串拼接
  • == 運算子
100  ==  '100'  //true
0    ==  ""     //true
null ==  undefined  //true
複製程式碼
  • if語句
    var c = '';
    if(c){
        //....
    }
複製程式碼
  • 邏輯運算
 console.log(10 && 0);       //0
 console.log('' || 'abc');   //'abc'
 console.log(!window.abc);   //true
複製程式碼

判斷一個變數會被當做true還是false 雙非判斷 var a = 100; console.log(!!a);

在js邏輯運算中,0、NaN、""、null、false、undefined都會判為false,其他都為true

 var add_level = (add_step == 5 && 1)||(add_step == 10 && 2)||(add_step == 12 && 4)||(add_step==15 && 5 )|| 0;
複製程式碼
 var add_level = {'5':1,'10':2,'15':5,'12':4}[add_step]||0; //更精簡
複製程式碼

何時使用 === 何時使用 ==

if(obj.a == null){
    //這裡相當於obj.a === null || obj.a === undefined,簡寫
    //這是jquery原始碼中推薦的寫法,除此之外其他全用 ===
    //主要是用於判斷這個屬性是否存在
}
複製程式碼
//判斷函式引數是否存在
function (a,b){
    if(a == null){
        ...
    }
}
複製程式碼
//這種寫法不能用
 if(xxx == null){
     //可能會報錯,這個引數未定義  not defined
 }
複製程式碼

JS變數按照儲存方式區分為哪些型別,並描述其特點

如何理解json

  • JSON是一個JS內建物件,常用兩個API
 JSON.stringify({a:10,b:20})
 JSON.parse('{"a":10,"b":20}')
複製程式碼
  • 同時也是一種資料格式

二、原型和原型鏈

原型規則

  • 所有的引用型別(陣列、函式、物件)都具有物件特性,即可自由擴充套件屬性
  • 所有的引用型別(陣列、物件、函式)有一個__proto__ 屬性,屬性值是一個普通的物件
  • 所有的函式都有一個prototype屬性,屬性值也是一個普通的物件
  • 所有的引用型別(陣列、物件、函式),__proto__屬性指向它的建構函式的prototype屬性
  • 當試圖得到一個物件的某個屬性時,如果這個物件本身沒有這個屬性,那麼回去他的__proto__(即它的建構函式的prototype中尋找)

原型鏈

前端面試之路二(javaScript基礎整理)

instanceof

instanceof:用於判斷引用型別屬於哪個建構函式的方法

f instanceof Foo的判斷邏輯是:

  • f的__proto__一層一層往上,能否對應到Foo.prototype
  • 再試著判斷f instance Object

如何準確判斷一個變數是否是陣列型別

var arr = [] arr instanceOf Array          //true

typeof arr        //object,typeof是無法判斷是否是陣列的

通用判斷方法:Object.prototype.toString.call(arr) === "[object Array]"

寫一個原型鏈繼承的例子

function Elem (id){ 
    this.elem = document.getElementById(id);
}
Elem.prototype.html = function(val){ 
    var elem = this.elem;
    if(val){ 
        elem.innerHtml = val;
        return this;   //鏈式操作
    }else{ 
        return elem.innerHtml; 
    }
} 

Elem.prototype.on = function(type,fn){
    var elem = this.elem
    elem.addEventListener(type,fn)
}

var div1 = new Elem('content_wrapper')
//div1.html('<p>ds<p>')
//div1.on('click',function(){
//	alert('clicked')
//	}
//)
div1.html('<p>放大放大放大發范德薩大點的我請薩</p>').on('click',function(){
	alert('clicked');
}).html('<p>javascript</p>')
複製程式碼

描述建立一個物件的過程

  • 新生成了一個物件
  • 連結到原型
  • 繫結 this
  • 返回新物件
function create() {
    let obj = new Object()
    let Con = [].shift.call(arguments)
    obj.__proto__ = Con.prototype
    let result = Con.apply(obj, arguments)
    return typeof result === 'object' ? result : obj
}
複製程式碼

zepto原始碼中如何使用原型鏈

三、作用域和閉包

題目

  • 說一下對變數提升的理解
  • 說明this幾種不同的使用場景
  • 建立10個 < a>標籤,點選的時候彈出對應的序號
  • 如何理解作用域
  • 實際開發中閉包的應用

執行上下文

  • 範圍:一段<script>或者一個函式
  • 全域性:變數定義、函式宣告、一段<script>
  • 函式:變數定義、函式宣告、this、arguments
console.log(a)    //undefined
var a = 100
fn('zhangsan')    //'zhangsan' 20
function fn(name){
	age = 20
	console.log(name,age)
	var age
}

複製程式碼
  • 函式宣告會被提出來,函式表示式會和變數一樣,以undefined佔位
  • 在函式執行之前,變數定義、函式宣告、thisarguments都要先提取出來

函式宣告函式表示式的區別

fn()                    //不會報錯
function fn(){
    //宣告
}
複製程式碼
fn()                    //Uncaught TypeError:fn1 is not a function 
var a = function(){
    //表示式
}
複製程式碼
  • 變數提升: var a ; undefined,並不知道是一個函式
  • 函式提升: 把函式宣告提前
fn('zhangsan')

function fn(name){
	//函式
	console.log(this)
	console.log(arguments)

	age = 20
	console.log(name,age)
	var age
	
	bar(100)
	function bar(num){
		console.log(num)
	}
}
複製程式碼

說明this幾種不同的使用場景

  • 作為建構函式執行
  • 作為物件屬性執行
  • 作為普通函式執行(window)
  • callapplybind
var a = {
	name : 'A',
	fn:function(){
		console.log(this.name)
	}
}

a.fn()                  //this  === a
a.fn.call({name:'B'})   //this  === {name:'B'}
var fn1 = a.fn
fn1()                   //this === window
複製程式碼

this要在執行的時候才能確認值

作用域

沒有塊級作用域

if(true){
	var name = 'zhangsan'
}
console.log(name)
複製程式碼

函式作用域和全域性作用域

var a = 100
function fn(){
	var a = 200
	console.log('fn',a)
}

console.log('global',a)

fn()

複製程式碼

作用域鏈

如何理解作用域:

  • 自由變數
  • 作用域鏈,即自由變數的查詢
  • 閉包的兩個場景
var a = 100
function fn(){
    var b = 200
    //當前作用域沒有定義的變數,即“自由變數”
    console.log(a)
    console.log(b)
}
fn()
複製程式碼

自由變數作用域鏈,一直往父級作用域找,一直找到全域性作用域

var a = 100
function F1(){
	var b = 200
	function F2(){
		var c = 300
		console.log(a)   //a是自由變數
		console.log(b)	 //b是自由變數
		console.log(c)
	}
	F2()
}
F1()
複製程式碼

閉包

作用域是定義時的作用域,而不是執行時的作用域

閉包的使用場景:

函式作為返回值

function F1(){
	var a = 100
	//返回一個函式(函式作為返回值)
	return function(){
		console.log(a)
	}
}

var f1 = F1()
var a = 200
f1()
複製程式碼

函式作為引數傳遞

function F1(){
	var a = 100
	return function(){
		console.log(a)   //自由變數,父作用域尋找
	}
}

var f1 = F1()

function F2(fn){
	var a = 200
	fn()
}

F2(f1)

複製程式碼

面試題

題目1、說一下對變數提升的理解

在某一作用域中,宣告變數的語句會預設解析為在該作用域的最開始就已經宣告瞭

題目2、說明this幾種不同的使用場景

blog.csdn.net/w_q_1025/ar…

題目3、建立10個 < a>標籤,點選的時候彈出對應的序號

錯誤寫法

var i,a
for(i = 0;i<10;i++){
	a = document.createElement('a')
	a.innerHTMl = i + '<br>'
	a.addEventListener('click',function(e){
		e.preentDefault()
		alert(i)
	})
	document.body.appendChild(a)
}
複製程式碼

正確寫法

var i,a
for(i = 0;i < 10;i++){
	(function(i){
		var a = document.createElement('a')
		a.innerHTML = i + '<br>'
		a.addEventListener('click',function(e){
			e.preventDefault()
			alert(i)		
		})
		document.body.appendChild(a)
	})(i)
}
複製程式碼

題目4、如何理解作用域

  • 自由變數
  • 作用域鏈,即自由變數的查詢
  • 閉包的兩個場景

題目5、實際開發中閉包的應用

//閉包實際應用中主要用於封裝變數,收斂許可權

function isFirstLoad(){ 
    var _list = []; 
    return function(id){
        if(_list.indexOf(id) >= 0){
            return false; 
        }else{ 
            _list.push(id);
            return true;
        } 
    }}
    var firstLoad = isFirstLoad();
    firstLoad(10);
複製程式碼

四、非同步和單執行緒

題目:

  • 同步和非同步的區別是什麼?分別舉一個同步和非同步的例子
  • 一個關於setTimeout的筆試題
  • 前端使用非同步的場景有哪些

知識點

  • 什麼是非同步(對比同步)
  • 前端使用非同步的場景
  • 非同步和單執行緒

什麼是非同步

是否阻塞程式的執行

何時需要非同步

在可能發生等待的情況

  • 定時任務:setTimeout,setTimeInterval
  • 網路請求:ajax請求,動態<img>載入
  • 事件繫結

等待過程中不能像alert一樣阻塞程式執行

因此所有的“等待的情況”都需要非同步

非同步和單執行緒

console.log(100)
setTimeout(function(){
	console.log(200)
},1000)
console.log(300)
複製程式碼
  • 執行第一行,列印100
  • 執行setTimeout後,傳入setTimeout的函式會被暫存起來,不會立即執行(單執行緒特點,不能同時幹兩件事)
  • 執行最後一行,列印300
  • 待所有程式執行完,處於空閒狀態時,會立馬看有沒有暫存起來的要執行
  • 發現暫存起來的setTimeout中的函式無需等待時間,就立即來過來執行

面試題

筆試題1: 同步和非同步的區別是什麼?分別舉一個同步和非同步的例子

同步會阻塞程式碼執行,而非同步不會

筆試題2:一個關於setTimeout的筆試題

console.log(1)

setTimeout(function(){
	console.log(2)
},0)

console.log(3)

setTimeout(function(){
	console.log(4)
},1000)

console.log(5)
複製程式碼

前端面試之路二(javaScript基礎整理)

筆試題3:前端使用非同步的場景有哪些

需要等待,因為js是單執行緒語言

五、常見物件

題目

  • 獲取2017-06-10格式的日期
  • 獲取隨機數,要求是長度一直的字串格式
  • 寫一個能遍歷物件和陣列的通用forEach函式

Date

Date.now() //獲取當前時間毫秒數
  
var dt = new Date()
dt.getTime()  		//獲取毫秒數
dt.getFullYear()  	//年
dt.getMonth()		//月(0-11)
dt.getDate()		//日(0-31)
dt.getHours()		//小時(0-23)
dt.getMinutes()		//分鐘(0-59)
dt.getSeconds()		//秒(0-59)
複製程式碼

Math

Math.random():可以用來清除快取

Array

  • forEach 遍歷所有資料
  • every 判斷所有元素是否都符合條件
  • some 判斷是否有至少一個元素符合條件
  • sort 排序
  • map 對元素重新組裝,生成新陣列>- 過濾符合條件的元素

array.forEach

arr.forEach( function(item,index){ 
    console.log(index,item); 
});
複製程式碼

array.every

var arr = [1,2,3,4,5];
var result = arr.every(function(index,item){
//用來判斷所有的陣列元素,都滿足一個條件 
    if(item<6) 
        return true
});
    console.log(result);
複製程式碼

array.some

var result = arr.some(function(index,item){ 
    if(item<5) 
        return true;
}); 
console.log(result);

複製程式碼

arry.sort

var arr2 = arr.sort(function(a,b){ 
    //從小到大排序 return a-b; 
    //從大到小排序 
    //return b-a;
})
複製程式碼

array.map

arr.map(function(item,index){
	return '<br>'+index+':'+item+'<br>'
})
複製程式碼

array.filter

var arr2 = arr.filter(function (item,index){ 
    //通過某一個條件過濾陣列 
    if(item >= 2) 
        return true
})
複製程式碼

物件API

var obj = {
	x:100,
	y:200,
	z:300
}

var key

for(key in obj){
	if(obj.hasOwnProperty(key)){
		console.log(key,obj[key])
	}
}
複製程式碼

面試題

解答1:獲取2016-06-10格式的日期

function formatDate(dt){
	if(!dt){
		dt = new Date()
	}

	var year  = dt.getFullYear()
	var month = dt.getMonth() + 1
	var date  = dt.getDate()

	if(month < 10){
		//強制型別轉換
		month = '0' + month 
	}

	if(date < 10){
		//強制型別轉換
		date = '0' + date
	}
	//強制型別轉換
	return year + '-' + month + '-' + date
}

var dt = new Date()
var formatDate = formatDate(dt)
console.log(formatDate)
複製程式碼

解答2:獲取隨機數,要求是長度一致的字串格式

var random = Math.random() + '0000000000';
var random = random.slice(0,10);
複製程式碼

解答3:寫一個能遍歷物件和陣列的通用forEach函式

function forEach(obj,fn){
	var key
	if(obj instanceof Array){
    	//準備判斷是不是陣列
    	obj.forEach(function(item,index){
    		fn(index,item)
    	})
	}else{
    	//不是陣列就是物件
    	for(key in obj){
    		fn(key,obj[k])
    	}
	}
}

複製程式碼

五、JS-Web-API:

知識點:

  • js基礎知識:ECMA262標準
  • JS-Web-API:W3C標準

W3C標準中關於JS的規定有:

  • DOM操作
  • BOM操作
  • 事件繫結
  • ajax請求(包括http協議)
  • 儲存

DOM操作

DOM的本質 DocumentObjectModel 瀏覽器把拿到的html程式碼,結構化一個瀏覽器能夠識別並且js可操作的一個模型而已

DOM的節點操作

  • 獲取DOM節點
  • Attribute 和 properity
  • attribute:是HTML標籤上的某個屬性,如id、class、value等以及自定義屬性,它的值只能是字串,關於這個屬性一共有三個相關的方法,setAttribute、getAttribute、removeAttribute; 注意:在使用setAttribute的時候,該函式一定接收兩個引數,setAttribute(attributeName,value),無論value的值是什麼型別都會編譯為字串型別。在html標籤中新增屬性,本質上是跟在標籤裡面寫屬性時一樣的,所以屬性值最終都會編譯為字串型別。
  • property:是js獲取的DOM物件上的屬性值,比如a,你可以將它看作為一個基本的js物件。這個節點包括很多property,比如value,className以及一些方法onclik等方法。 一個js物件有很多property,該集合名字為properties,properties裡面有其他property以及attributies,attributies裡面有很多attribute。 而常用的attribute,id、class、name等一般都會作為property附加到js物件上,可以和property一樣取值、賦值

DOM結構操作

面試題1:DOM是那種基本的資料結構?

面試題2:DOM操作的常用API有哪些?

  • 獲取DOM節點,以及節點的propertyAttribute
  • 獲取父節點,獲取子節點
  • 新增節點,刪除節點

面試題3:DOM節點的attr和property有何區別

property只是一個JS物件的屬性的修改
Attribute是對html標籤屬性的修改

BOM操作

問題:

  • 如何檢測瀏覽器的型別
  • 拆解URL各部分

知識點

  • navigator
  • screen
  • location
  • history

navigator & screen


//navigator
var ua = navigator.userAgent
var isChrome = ua.indexOf('chrome')
console.log(isChrome)

//screen
console.log(screen.width)
console.log(screen.height)

//location
console.log(location.href)
console.log(location.protocol)
console.log(location.pathname)
console.log(location.search)    //?之後的引數
console.log(location.hash)      //#號之後

//history
history.back()          
history.forward()
複製程式碼

六、事件

題目:

  • 編寫一個通用的事件監聽函式
  • 描述時間冒泡流程
  • 對於一個無限下拉載入圖片的頁面,如何給每個圖片繫結事件

知識點:

  • 通用事件繫結
  • 事件冒泡
  • 代理

知識點

通用事件繫結

var btn = document.getElementById('btn1')
btn.addEventListener('click', function(event) {
    console.log('clicked')
})

function bindEvent(elem, type, fn) {
    elem.addEventListener(type, fn)
}

var a = document.getElementById('link1')
bindEvent(a, 'click', function(e) {
    e.preventDefault(); //阻止預設行為
    alert('clicked')
})
複製程式碼

關於IE低版本的相容性

  • IE低版本使用attachEvent繫結事件,和W3C標準不一樣
  • IE低版本使用量已非常少,很多網站早已不支援
  • 建議對IE低版本的相容性:瞭解即可,無須深究
  • 如果遇到對IE低版本要求苛刻的面試,果斷放棄

事件冒泡

e.stopPropatation() //取消冒泡

代理

<div id="div1">
    <a href = "#">a1</a>
    <a href = "#">a2</a>
    <a href = "#">a3</a>
    <a href = "#">a4</a>
    <!--會隨時新增更多 a 標籤-->
</div>


var div1 = document.getElementById('div1')
div1.addEventListener('click',function(e){
    var target = e.target
    if(target.nodeName === 'A'){
        alert(target.innerHTMl)
    }
})
複製程式碼

完整寫法

function bindEvent(elem, type, selector, fn) {
    if (fn == null) {
        fn = selector
        selector = null
    }

    elem.addEventListener(type, function(e) {
        var target
        if (selector) {
            target = e.target
            if (target.matches(selector)) {
                fn.call(target, e)
            }
        } else {
            fn(e)
        }
    })
}

//使用代理
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'a', function(e) {
    console.log(this.innerHTML)
})

//不使用代理
var a = document.getElementById('a1')
bindEvent(div1, 'click', function(e) {
    console.log(a.innerHTML)
})
複製程式碼

面試題

面試題1:編寫一個通用的事件監聽函式

面試題2:描述事件冒泡流程

  • DOM樹形結構
  • 事件冒泡
  • 組織冒泡
  • 冒泡的應用

面試題3:對於一個無限下拉載入圖片的頁面,如何給每個圖片繫結事件

  • 使用代理
  • 知道代理的兩個優點

七、Ajax

題目:

  • 手動寫一個ajax,不依賴第三方庫
  • 跨域的幾種實現(原理)

知識點:

  • xmlHttpRequest
  • 狀態碼說明
  • 跨域

XMLHttpRequest

var xhr = new XMLHttpRequest()

xhr.open("GET","/api",false)

xhr.onreadystatechange = function(){
    //這裡的函式非同步執行,可參考之前JS基礎中的非同步模組
    if(xhr.readyState == 4){
        if(xhr.status == 200){
            alert(xhr.responseText)
        }
    }
}

xhr.send(null)
複製程式碼

IE相容性問題

  • IE低版本使用ActiveXObject,和W3C標準不一樣
  • IE低版本使用量已經非常少,很多網站早已不支援
  • 建議對IE低版本的相容性:瞭解即可,無需深究
  • 如果遇到對IE低版本要求苛刻的面試,果斷放棄

.

狀態碼說明

  • 0 - (未初始化)     還沒呼叫send()方法
  • 1 - (載入)            已調send() 方法,正在傳送請求
  • 2 - (載入完成)     send()方法執行完成,已經接收到全部相應內容
  • 3 - (互動)            正在解析響應內容
  • 4 - (完成)            響應內容解析完成,可以在客戶端呼叫了

.

status說明

  • 2XX - 表示成功處理請求。如200
  • 3XX - 需要重定向,瀏覽器直接跳轉
  • 4XX - 客戶端請求錯誤,如404
  • 5XX - 伺服器端錯誤

跨域

什麼是跨域

  • 瀏覽器有同源策略,不允許ajax訪問其他域的介面
  • 跨域條件:協議、域名、埠,有一個不同就算跨域

 

可以跨域的三個標籤

  • <img src=''>
  • <script src=''>
  • <link href=''>

 

三個標籤的場景

  • <img>用於打點統計,統計網站可能是其他域(而且沒有任何相容性問題)
  • <link> <script>可以使用CDN,CDN也是其他域
  • <script>可以用於JSONP

 

跨越注意的問題

  • 所有的跨域請求都必須經過資訊提供方允許
  • 如果未經允許即可獲取,那是瀏覽器同源策略出現漏洞

 

JSONP實現原理

  • 載入 coding.xxx.com/classindex.…
  • 不一定伺服器端真正有一個classindex.html檔案
  • 伺服器可以根據請求,動態生成一個檔案,返回
  • 通理於<script src="http://coding.xxxxx.com/api.js">
//例如你的網站要跨域訪問xx網的一個介面
//給你一個地址 http://coding.xxxx.com/api.js
//返回內容格式 callback({x:100,y:200})

<script>
window.callback = function(data){
    //這是我們跨域得到資訊
    console.log(data)
}
</script>
<script src="http://coding.m.xxxxx.com/api.js"></script>
複製程式碼

伺服器端設定http header

cookiesessionStoragelocalStorage的區別

  • 容量
  • 是否會攜帶到ajax中
  • API易用性
ios safari隱藏模式下,localStorage.getItem會報錯,建議統一用try-catch封裝
複製程式碼

_________________________面試全家桶_________________________

HTML+CSS 面試整理                                --------------------------------> 點這裡
前端高階面試整理(三大框架等深入知識) --------------------------------> 點這裡
javascript效能優化                                      --------------------------------> 點這裡
javascript設計模式                                      --------------------------------> 點這裡
HTTP相關面試                                            -------------------------------->點這裡

相關文章