課程講解思路:先列題目引發(fā)思考检盼,再詳細(xì)講解知識(shí)點(diǎn),最后解答
[TOC]
前言
關(guān)于面試
前端水平的三個(gè)層次
- 基層工程師-基礎(chǔ)知識(shí)
- 高級(jí)工程師-項(xiàng)目經(jīng)驗(yàn)
- 架構(gòu)師- 解決方案
幾個(gè)面試題
題目很多,做具有代表的題目乍丈,舉一反三
- js 中使用 typeof 能得到哪些類型 (==js 變量類型==)
- 何時(shí)使用 === 何時(shí)使用 == 衙解? (==強(qiáng)制類型轉(zhuǎn)換==)
- window.onload 和 DOMContentLoaded 的區(qū)別 (==瀏覽器渲染過程==)
- 用 js 連續(xù)創(chuàng)建 10 個(gè) <a> 標(biāo)簽,點(diǎn)擊的時(shí)候彈出來對(duì)應(yīng)的序號(hào) (==作用域==)
- 簡述如何實(shí)現(xiàn)一個(gè)模塊加載器令野,實(shí)現(xiàn)類似 require.js 的基本功能 (==js 模塊化==)
- 實(shí)現(xiàn)數(shù)組的隨機(jī)排序 (==JS 基礎(chǔ)算法==)
思考
- 拿到面試題第一時(shí)間看到的是什么 (==考點(diǎn)==)
- 如何看待永遠(yuǎn)做不完的題海 (==以不變應(yīng)萬變==)
- 如何對(duì)待接下來遇到的面試題舀患? (==總結(jié)考點(diǎn)并擴(kuò)展再反思題目==)
基礎(chǔ)知識(shí)
js 基礎(chǔ)三座大山
- 原型 原型鏈
- 作用域 閉包
- 異步 單線程
面試題
1. js 中使用 typeof 能得到哪些類型
2. 何時(shí)使用 === 何時(shí)使用 ==
if (obj.a == null){
// 這里相當(dāng)于 obj.a === null || obj.a ===undefined ,因?yàn)?undefined == null 值為true
// 這是 JQuery 中推薦的寫法气破, 其余情況全部用 === (避免代碼風(fēng)險(xiǎn)有代碼潔癖)
}
3. JS 中有哪些內(nèi)置函數(shù)
4. JS 變量按照存儲(chǔ)方式區(qū)分為哪些類型聊浅,并描述其特點(diǎn)
5. 如何理解 JSON
知識(shí)點(diǎn)
- 變量類型:值類型 和 引用類型(指針)
- 引用類型包括: 數(shù)組 函數(shù) 對(duì)象;引用類型公共空間,是指針
var a=100;
var b=a;
a=200;
console.log(b) //100
var a={age:20};
var b=a;
b.age=21;
console.log(a.age) //21
- typeof只能區(qū)分值類型的詳細(xì)類型现使,對(duì)引用類型無能為力低匙,但可以區(qū)分出函數(shù)來
typeof undefined;//undefined
typeof 'abc';//string
typeof 123;//number
typeof true;//boolean
typeof {};//object
typeof [];//object
typeof null;//object
typeof console.log//function
-
強(qiáng)制類型轉(zhuǎn)換(值類型的計(jì)算)
- ①字符串拼接
- ②==運(yùn)算符
- ③if語句
- ④邏輯運(yùn)算 (布爾操作符 邏輯非、邏輯與碳锈、邏輯或)
- 邏輯非 顽冶! (結(jié)果總是 true/fasle )
- 如果操作數(shù)是一個(gè)對(duì)象,返回 false
- 邏輯與 &&
- ==如果第一個(gè)操作是對(duì)象則返回第二個(gè)操作數(shù)==
- 如果第二個(gè)操作數(shù)是對(duì)象殴胧,則只有在第一個(gè)操作數(shù)的求值結(jié)果為 true 的情況下才會(huì)返回該對(duì)象
- 如果兩個(gè)操作數(shù)都是對(duì)象渗稍,則返回第二個(gè)操作數(shù)
- 如果第一個(gè)操作數(shù)是 null,則返回 null
- 如果第一個(gè)操作數(shù)是 NaN团滥,則返回 NaN
- 如果第一個(gè)操作數(shù)是 undefined 竿屹,則返回 undefined存璃。
- 邏輯與操作符屬于斷路操作玉罐,如果第一個(gè)操作符能夠決定結(jié)果坯台,那么就不會(huì)再對(duì)第二個(gè)操作數(shù)求值默赂。
-
==邏輯或 ||==
- 如果第一個(gè)操作數(shù)是對(duì)象叛拷,則返回第一個(gè)操作數(shù)
- 如果兩個(gè)操作數(shù)都是對(duì)象趾唱,則返回第一個(gè)操作數(shù)
- 如果第一個(gè)操作數(shù)的求值結(jié)果為 false 奴璃,則返回第二個(gè)操作數(shù)
- 如果兩個(gè)操作數(shù)都是 NaN/null/undefined 瞒滴,則返回 NaN/null/undefined
- 邏輯非 顽冶! (結(jié)果總是 true/fasle )
上面四種操作可能導(dǎo)致強(qiáng)制類型轉(zhuǎn)換
var a=100+10;//110
var b=100+'10'//'10010'
100 =='100'//true
0==''//true
null==undefined//true
var a=true;
if(a){
//...
}
var b=100;
if(b){
//...
}
var c='';
if(c){
//...
}
console.log(10&&0)//0
console.log(''||'abc')//abc
console.log(!window.abc)//true
var a=100;
console.log(!!a)//true
面試題解答 1
面試題1、JS中使用typeof能得到的哪些類型哮缺?
typeof undefined;//undefined
typeof 'abc';//string
typeof 123;//number
typeof true;//boolean
typeof {};//object
typeof [];//object
typeof null;//object
typeof console.log//function
typeof只能區(qū)分值類型的詳細(xì)類型弄跌,對(duì)引用類型無能為力,但可以區(qū)分出函數(shù)來
面試題2尝苇、何時(shí)使用===何時(shí)使用==铛只?
if(obj.a==null){
//這里相當(dāng)于obj.a===null||obj.a===undefined,簡寫形式
//這是jquery源碼中推薦的方法,其他的都用===
}
面試題3糠溜、JS中有哪些*內(nèi)置函數(shù)*--數(shù)據(jù)封裝類對(duì)象淳玩?
//JS作為單純語言的內(nèi)置函數(shù)
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
//Global瀏覽器內(nèi)置對(duì)象
//Math是對(duì)象,不是函數(shù)
面試題4非竿、JS變量按照存儲(chǔ)方式區(qū)分為哪些類型蜕着,并描述其特點(diǎn)
//分為值類型和引用類型
//值類型
var a=10
var b=a
a=11
console.log(b)//10
//引用類型
var obj1={x:100}
var obj2=obj1
obj1.x=200
console.log(obj2.x)//200
值類型直接存儲(chǔ)的是值
引用類型存儲(chǔ)的是指向值的指針,這樣做是為了節(jié)省內(nèi)存
值類型的值賦值后不會(huì)相互干預(yù)
引用類型的賦值是變量指針的賦值红柱,不是真的值的拷貝承匣,他們的賦值是相互干預(yù)的。
面試題5锤悄、如何理解JSON?
//JSON只不過是一個(gè)JS對(duì)像而已悄雅,和MATH一樣
JSON.stringfy({a:10,b:20})
JSON.parse('{"a":10,"b":20}')
//注意:JS中為false的為 0 NaN null undefined '' false
原型和原型鏈
*構(gòu)造函數(shù)*
function Foo(name,age){
this.name=name;
this.age=age;
this.class="class-1";
//return this;//默認(rèn)有這一行
}
var f=new Foo('zhangsan',20)
var f1=new Foo('lisi',22)//創(chuàng)建多個(gè)對(duì)象
//new對(duì)象時(shí)函數(shù)中的this初始化為空對(duì)象,參數(shù)賦值完后返回this給f和f1
*構(gòu)造函數(shù)--擴(kuò)展*
var a={}其實(shí)是var a=new Object()的語法糖
var a=[]其實(shí)是var a=new Array()的語法糖
function Foo(){...}其實(shí)是var Foo=new Function(...)
//使用instanceof判斷一個(gè)函數(shù)是否是一個(gè)變量的構(gòu)造函數(shù)
//對(duì)象铁蹈,數(shù)組,函數(shù)的構(gòu)造函數(shù)其實(shí)是Object,Array,Function
//判斷一個(gè)變量是否是'數(shù)組' 變量 instanceof Array
原型規(guī)則(是學(xué)習(xí)原型鏈的基礎(chǔ))
- 所有的引用類型(數(shù)組众眨,對(duì)象握牧,函數(shù)),都具有對(duì)像特性娩梨,即可自由擴(kuò)展屬性(除了null)
- 所有的引用類型(數(shù)組沿腰,函數(shù),對(duì)象)狈定,都有一個(gè) _proto_ 屬性颂龙,屬性值是一個(gè)普通對(duì)象
- 所有的函數(shù),都有一個(gè) prototype 屬性纽什,屬性值也是一個(gè)普通的對(duì)象
- 函數(shù)的 prototype 稱顯式原型措嵌,引用類型的 _proto 成為隱式原型
- 所有的引用類型(數(shù)組,函數(shù)芦缰,對(duì)象)企巢,其 _proto_ 屬性值都指向其構(gòu)造函數(shù)的 prototype 屬性值
- 當(dāng)試圖獲取一個(gè)對(duì)象的某個(gè)屬性時(shí),如果這個(gè)對(duì)象本身沒有這個(gè)屬性让蕾,那么會(huì)去它的_prot__(即它的構(gòu)造函數(shù)的prototype)
image
var obj={};obj.a=100;
var arr=[];arr.a=100;
function fn(){}
fn.a=100;
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
console.log(fn.prototype)
console.log(obj.__proto__===Object.prototype)
function Foo(name,age){
this.name=name;
}
Foo.prototype.alertName=function(){
alert(this.name)
}
var f=new Foo('zhangsan');
f.printName=function(){
console.log(this.name);
}
f.printName();
f.alertName();
//循環(huán)對(duì)象自身的屬性
var item;
for(item in f){
//高級(jí)瀏覽器已經(jīng)在for in中屏蔽了來自原型的屬性
//但是這里建議大家還是加上這個(gè)判斷浪规,保證程序的健壯性
if(f.hasOwnProperty(item))
console.log(item);
}
*原型鏈*
f.toString()//要去f.__proto__.__proto__中去找
*instanseof*
**注意:** //用于判斷引用類型屬于哪個(gè)構(gòu)造函數(shù)的方法
f instanceof Foo的判斷邏輯是:
f的__proto__一層一層向上找或听,能否對(duì)應(yīng)到Foo.prototype
f instanceof Object也是正確的
面試題解答 2
面試題1、如何準(zhǔn)確判斷一個(gè)變量時(shí)數(shù)組類型笋婿?
var arr=[]
arr instanceof Array //true
typeof arr//object,typeof是無法判斷是否是數(shù)組的
面試題2誉裆、寫一個(gè)原型鏈繼承的例子
①function Animal(){
this.eat=function(){
console.log('animal eat');
}
}
function Dog(){
this.bark=function(){
console.log('dog bark')
}
}
Dog.prototype=new Animal();
var hashiqi=new Dog()
②function Elem(id){
this.elem=document.getElementById(id);
}
Elem.prototype.html=function(val){
var elem=this.elem;
if(val){
elem.innerHTML=val;
return this;//鏈?zhǔn)讲僮? }else{
return elem.innerHTML;
}
}
Elem.prototype.on=function(type,fn){
var elem=this.elem;
elem.addEventListener(type,fn);
return this;
}
var elem=new Elem("div1");
elem.html("<p>hello world</p>").on("click",function(){alert("clicked")}).html("<p>javascript</p>");
面試題3、描述new一個(gè)對(duì)象的過程
①創(chuàng)建一個(gè)新對(duì)象
②this指向這個(gè)新對(duì)象
③執(zhí)行代碼缸濒,即對(duì)this賦值
④返回this
面試題4足丢、zepto(或其他框架)源碼中如何使用原型鏈
①閱讀源碼是高效提高技能的方式
②但不能“埋頭苦鉆”有技巧在其中
③慕課網(wǎng)搜索“zepto設(shè)計(jì)和源碼分析”
執(zhí)行上下文
js 是解釋型語言不是編譯型語言,所以有些錯(cuò)誤在編寫程序時(shí)不會(huì)報(bào)錯(cuò)绍填,什么時(shí)候執(zhí)行什么時(shí)候報(bào)錯(cuò)
- 范圍:一段<script>或者一個(gè)函數(shù)之內(nèi)都會(huì)生成一個(gè)上下文
- 全局:變量定義霎桅,函數(shù)聲明 //執(zhí)行之前,一段<script>會(huì)生成全局上下文
- 函數(shù):變量定義讨永,函數(shù)聲明滔驶,this,arguments //函數(shù)執(zhí)行之前會(huì)生成函數(shù)上下文
- 注意:‘函數(shù)聲明’和‘函數(shù)表達(dá)式’的區(qū)別
console.log(a);//undefined
var a=100
fn('zhangsan') //'zhangsan' 20
function fn(name){
age=20;
console.log(name,age);
var age;
}
this
- this要在執(zhí)行時(shí)才能確認(rèn)值卿闹,定義時(shí)無法確認(rèn)
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
使用場景
①作為構(gòu)造函數(shù)執(zhí)行
function Foo(name){
//this={};
this.name=name;
//return this
}
var f=new Foo('zhangsan')
②作為對(duì)象屬性執(zhí)行
var obj={
name:'A',
printName:function(){
console.log(this.name)
}
}
obj.printName();
③作為普通函數(shù)執(zhí)行
function fn(){
console.log(this) //this===window
}
fn()
④call apply bind
function fn1(name,age){
alert(name);
console.log(this) //this===window
}
fn1.call({x:100},'zhangsan',20)
fn1.apply({x:100},['zhangsan',20])
var fn2=function(name,age){
alert(name);
console.log(this) //this==={x:100}
}.bind({x:100})//bind只能用函數(shù)表達(dá)式揭糕,函數(shù)聲明不可用,會(huì)報(bào)錯(cuò)
fn2('zhangsan',200)
作用域
①?zèng)]有塊級(jí)作用域
if(true){
var name='zhangsan'
}
console.log(name)//'zhangsan'
②只有全局和函數(shù)作用域
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
//當(dāng)前作用域沒有定義的變量著角,即'自由變量'
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();
- ==注意==:函數(shù)的父級(jí)作用域是函數(shù)定義時(shí)候的作用域,不是函數(shù)執(zhí)行時(shí)候的作用域,也就是說那個(gè)作用域定義了這個(gè)函數(shù)旋恼,這個(gè)函數(shù)的父級(jí)作用域就是誰吏口,跟函數(shù)執(zhí)行沒有關(guān)系,函數(shù)自由變量要到父級(jí)作用域中找冰更,就形成了作用域鏈
閉包
- 實(shí)際開發(fā)中閉包的應(yīng)用:封裝變量产徊,收斂權(quán)限
function F1(){
var a=100;
//返回一個(gè)函數(shù)(函數(shù)作為返回值)
return function(){
console.log(a);//自由變量,父作用域?qū)ふ? }
}
//f1得到一個(gè)函數(shù)
var f1=F1();
var a=200;
f1();//100
閉包使用場景
①函數(shù)作為返回值
②函數(shù)作為參數(shù)傳遞(函數(shù)自由變量要到父級(jí)作用域中找)
function F1(){
var a=100;
return function(){
console.log(a);
}
}
var f1=F1();
function F2(fn){
var a=200
fn();(自由變量要到聲明定義時(shí)的父作用域中找蜀细,和執(zhí)行的作用域沒有關(guān)系)
}
F2(f1);//100
面試題解答 3
問題1舟铜、說一下對(duì)變量提升的理解
①變量的定義
②函數(shù)的聲明(注意和函數(shù)表達(dá)式的區(qū)別)
問題2、說明this幾種不同的使用場景
參考上文**this**
問題3奠衔、創(chuàng)建10個(gè)`<a>`標(biāo)簽谆刨,點(diǎn)擊的時(shí)候彈出來對(duì)應(yīng)的序號(hào)
var i;
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);//相當(dāng)于創(chuàng)建了10個(gè)函數(shù)
}
問題4、如何理解作用域
①自由變量
②作用域鏈归斤,即自由變量的查找
③閉包的兩個(gè)場景
問題5痊夭、實(shí)際開發(fā)中閉包的應(yīng)用
//閉包實(shí)際應(yīng)用中主要用于封裝變量,收斂權(quán)限
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);
firstLoad(10);
firstLoad(20);
//你在 isFirstLoad 函數(shù)外面官册,根本不可能修改掉_list的值
異步
何時(shí)需要異步
- ①在可能發(fā)生等待的情況下
- ②等待過程中不能像alert一樣阻塞程序運(yùn)行
- ③因此生兆,所以的”等待的情況”都需要異步
前端使用異步的場景
- ①定時(shí)任務(wù):setTimeout,setInterval
- ②網(wǎng)絡(luò)請(qǐng)求:ajax請(qǐng)求,動(dòng)態(tài)加載
- ③事件綁定
console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300) //100 300 200
異步示例
console.log('start');
$.get('./data1.json',function(data1){
console.log(data1);
})
console.log('end')//'start' 'end' data1
console.log(start);
var img=document.createElement('img')
img.onload=function(){
console.log('loaded')
}//圖片加載完執(zhí)行
img.src='/xx.png';
console.log('end');//start end loaded
console.log('start')
document.getElementById('btn1').addEventListener('click',function(){
alert('clicked');
})//點(diǎn)擊時(shí)才會(huì)執(zhí)行
console.log('end');//start clicked end
同步
console.log(100)
alert(200);
console.log(300) //100 200 300
異步和單線程
js 是單線程的語言鸦难,所以需要異步
console.log(100)
setTimeout(function(){
console.log(200)
})
console.log(300) //100 300 200
上述異步代碼的執(zhí)行過程如下
- 執(zhí)行第一行打印100
- setTimeout 異步執(zhí)行根吁,先暫存起來
- 打印 300
- 待所有程序執(zhí)行完,處于空閑狀態(tài)時(shí)合蔽,拿到暫存的函數(shù)在指定的時(shí)間后執(zhí)行
面試解答 4
問題1击敌、同步和異步的區(qū)別是什么?分別舉一個(gè)同步和異步的例子
①同步會(huì)阻塞代碼執(zhí)行拴事,而異步不會(huì)
②alert是同步沃斤,setTimeout是異步
問題2、一個(gè)關(guān)于setTimeout的筆試題
console.log(1)
setTimeout(function(){
console.log(2)
},0)
console.log(3)
setTimeout(function(){
console.log(4)
},1000)
console.log(5)
//1 3 5 2 4
問題3刃宵、前端使用異步的場景有哪些
①定時(shí)任務(wù):setTimeout衡瓶,setInterval
②網(wǎng)絡(luò)請(qǐng)求:ajax請(qǐng)求,動(dòng)態(tài)加載
③事件綁定
其他(日期牲证、Math哮针、各種常用API)
①日期
Date.now() //獲取當(dāng)前時(shí)間毫秒數(shù)
var dt=new Date()
dt.getTime() //獲取毫秒數(shù)
dt.getFullYear() //年
dt.getMonth() //月
(0-31) dt.getHours() //小時(shí)(0-23)
dt.getMinutes() //分鐘(0-59)
dt.getSeconds() //(0-59)
②Math
Math.random()
random 在實(shí)際中的應(yīng)用有清除緩存的作用,是每次訪問到的都不是緩存
③數(shù)組API
forEach 遍歷所有元素
var arr=[1,2,3]
arr.forEach(function(item,index){
//遍歷數(shù)組的所有元素
console.log(index,item)
})
every 判斷所有元素是否都符合條件
var arr=[1,2,3]
var result=arr.every(function(item,index){
//用來判斷所有的數(shù)組元素坦袍,都滿足一個(gè)條件
if(item<4){
return true;
}
})
console.log(result);
some 判斷是否至少一個(gè)元素符合條件
var arr=[1,2,3]
var result=arr.some(function(item,index){
//用來判斷所有的數(shù)組元素十厢,只要有一個(gè)滿足條件即可
if(item<2){
return true;
}
})
console.log(result);
sort 排序
var arr=[1,4,2,3,5]
var arr2=arr.sort(function(a,b){
//從小到大排序
return a-b
//從大到小排序
//return b-a
})
console.log(arr2)
map 對(duì)元素重新組裝,生成新數(shù)組
var arr=[1,2,3,4]
var arr2=arr.map(function(item,index){
//將元素重新組裝捂齐,并返回
return '<b>'+item+'</b>'
})
console.log(arr2)
filter過濾符合條件的元素
var arr=[1,2,3]
var arr2=arr.filter(function(item,index){
//通過某一個(gè)條件過濾數(shù)組
if(item>=2){
return true;
}
})
console.log(arr2)
④對(duì)象API
var obj={
x:100,
y:200,
z:300
}
var key
for(key in obj){
//注意這里的hasOwnProperty,再講原型鏈時(shí)講過了
if(obj.hasOwnProperty(key)){
console.log(key,obj[key])
}
}
面試題解答 5
問題1蛮放、獲取2017-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){
//強(qiáng)制類型轉(zhuǎn)換
month="0"+month;
}
if(date<10){
//強(qiáng)制類型轉(zhuǎn)換
date="0"+month;
}
return year+"-"+month+"-"+date
}
var dt=new Date()
var formatDate=formatDate(dt)
console.log(formatDate)
問題2、獲取隨機(jī)數(shù)奠宜,要求是長度一直的字符串格式
var random=Math.random()
var random=random+'0000000000' //后面加上10個(gè)零
var random=random.slice(0,10)
console.log(random)
問題3包颁、寫一個(gè)能遍歷對(duì)象和數(shù)組的通用forEach函數(shù)
function forEach(obj,fn){
var key
//準(zhǔn)確判斷是不是數(shù)據(jù)
if(obj instanceof Array){
obj.forEach(function(item,inex){
fn(index,item)
})
}else{
//不是數(shù)組就是對(duì)象
for(key in obj){
fn(key,obj[key])
}
}
}
var arr=[1,2,3];
//注意,這里參數(shù)的順序換了压真,為了和對(duì)象的遍歷格式一致
forEach(arr,function(index,item){
console.log(index,item)
})
var obj={x:100,y:200};
forEach(obj,function(key,value){
console.log(key,value)
})
js-web-api
本期主要內(nèi)容
- Dom操作
- Bom操作
- 事件綁定
- Ajax請(qǐng)求(包括http協(xié)議)
- 存儲(chǔ)
注意:內(nèi)置函數(shù)和內(nèi)置對(duì)象的區(qū)別
- 內(nèi)置函數(shù):Object Array RegExp Function Error Date Number Boolean String…
- 內(nèi)置對(duì)象:Math JSON…
注:
- JS基礎(chǔ)知識(shí):ECMA 262標(biāo)準(zhǔn)
- JS-WEB-API:W3C標(biāo)準(zhǔn)徘六,它參與規(guī)定任何JS基礎(chǔ)相關(guān)的東西,不管什么變量類型榴都、原型、作用域和異步漠其,只管定義用于瀏覽器JS操作頁面的API和全局變量
DOM
html是xml的一種特殊結(jié)構(gòu)
DOM 本質(zhì):
DOM 可以理解為:
瀏覽器把拿到的html代碼嘴高,結(jié)構(gòu)化一個(gè)瀏覽器能識(shí)別并且js可操作性的一個(gè)模型而已
①獲取DOM節(jié)點(diǎn)
var div1=document.getElementById(‘div1’);//元素
var divList=document.getElementsByTagName(‘div’); //集合
console.log(divList.length)
console.log(divList[0])
var containerList=document.getElementsByClassName(“.contaner”)//集合
var pList=document.querySelectorAll(‘p’)//集合
②property
var pList=document.querySelectorAll(‘a(chǎn)ll’);
var p=pList[0];
console.log(p.style.width)
p.style.width=’100px’
console.log(p.className)
p.className=’p1’
//獲取nodeName和nodeType
console.log(p.nodeName)
console.log(p.nodeType)
- DOM 結(jié)構(gòu)操作
- 新增節(jié)點(diǎn)
- 查詢子節(jié)點(diǎn)
- 查詢父節(jié)點(diǎn)
- 刪除節(jié)點(diǎn)
面試題解答 6
問題1和屎、dom是哪種基本的數(shù)據(jù)結(jié)構(gòu)拴驮?
樹
問題2、Dom操作的常用API有哪些柴信?
①獲取DOM節(jié)點(diǎn)套啤,以及節(jié)點(diǎn)的property和Attribute
②獲取父節(jié)點(diǎn),獲取子節(jié)點(diǎn) childNodes/ parentNode
③新增節(jié)點(diǎn)随常,刪除節(jié)點(diǎn)
問題3潜沦、Dom節(jié)點(diǎn)的Attribute和Property有和區(qū)別萄涯?
①property只是一個(gè)JS對(duì)象的屬性的修改
②Attribute是對(duì)html標(biāo)簽屬性的修改
BOM操作
- 測試瀏覽器型號(hào) navigator
var ua=navigator.userAgent
var isChrome=ua.indexOf(‘Chrome’)
console.log(isChrome)
- screen
- location
- history
console.log(screen.width)
console.log(scr)
console.log(location.href)
console.log(location.protocal)
console.log(location.pathname)
console.log(location.search)
console.log(location.hash)
history.back()
histort.forward()
面試題解答 7
題目1、如何檢測瀏覽器的類型
var ua=navigator.userAgent
var isChrome=ua.indexOf(‘Chrome’)
console.log(isChrome)
題目2唆鸡、拆解url的各部分
參考location
事件
- 通用事件綁定
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() //阻止默認(rèn)行為
alert(‘clicked’)
})
注:關(guān)于IE低版本的兼容性
①IE低版本使用attachEvent綁定事件涝影,和W3C標(biāo)準(zhǔn)不一樣
②IE低版本使用量以非常少,很多網(wǎng)站都早已不支持
建議對(duì)IE低版本的兼容性:了解即可争占,無需深究
如果遇到對(duì)IE低版本要求苛刻的面試燃逻,果斷放棄
事件冒泡
在父級(jí) div 中定義的事件,會(huì)在子級(jí)的事件執(zhí)行之后冒泡上來執(zhí)行
- 阻止事件冒泡 e.stopPropagation()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
<script type="text/javascript">
// 利用阻止冒泡的機(jī)制實(shí)現(xiàn):只點(diǎn)擊 p1 的時(shí)候彈窗激活
function bindEvent(elem,type,func) {
elem.addEventListener(type,func)
}
var p1 = document.getElementById('p1')
bindEvent(p1,'click',function(e){
e.stopPropagation()
alert('激活')
})
bindEvent(body,'click',function (e) {
alert('取消')
})
</script>
</body>
</html>
- 代理
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<a href="#">a5</a>
<p>fjdk</p>
<h1>jfkd</h1>
<!-- ...隨時(shí)會(huì)新增更多的 a 標(biāo)簽 -->
</div>
<script type="text/javascript">
// 要求用代理的方式實(shí)現(xiàn) 動(dòng)態(tài)事件綁定臂痕,綁定 div1 中的所有 a 標(biāo)簽
var div = document.getElementById('div1')
function bindEvent(elem,type,func) {
elem.addEventListener(type,func)
}
bindEvent(div,'click',function(e){
console.log(e) // MouseEvent
console.log(e.target) // 完整的 a 標(biāo)簽 對(duì)象 <a href="#">a3</a>
console.log(e.target.nodeName); // 都是大寫
if(e.target.nodeName === 'A'){
alert(e.target.innerHTML)
}
})
</script>
</body>
</html>
面試題解答 8
問題1伯襟、編寫一個(gè)通用的事件監(jiān)聽函數(shù) bind Event
問題2、描述事件冒泡流程
①DOM樹形結(jié)構(gòu)
②事件冒泡
③阻止冒泡
④冒泡的應(yīng)用(代理)
問題3握童、對(duì)于一個(gè)無線下拉加載圖片的頁面姆怪,如何給每個(gè)圖片綁定事件
①使用代理
②知道代理的兩個(gè)優(yōu)點(diǎn)
代碼簡潔
減少瀏覽器內(nèi)存占用
ajax
// 指定了請(qǐng)求目標(biāo),也明確了如何處理之后舆瘪,就可以發(fā)送請(qǐng)求了
var request = new XMLHttpRequest();
request.open('GET',url,true);// 指定請(qǐng)求目標(biāo)片效,三個(gè)參數(shù),1.GET or POST 2.請(qǐng)求路徑 3.是否異步 (默認(rèn)true英古,可以不寫)
request.onreadystatechange() = function(){
if(request.readyState === 4){
// 請(qǐng)求完成
if(request.status === 200){
// 請(qǐng)求成功淀衣,獲得一個(gè)成功的響應(yīng),此后可以開始請(qǐng)求成功后的處理
request.responseText//responseText 保存文本字符串格式
request.responseXML//responseXML 保存 Content-Type 頭部中指定為 "text/html" 的數(shù)據(jù)
}else{
// 請(qǐng)求失敗,根據(jù)響應(yīng)碼判斷失敗原因
console.log('error,status:'+request.status)
}
}else{
// 請(qǐng)求還在繼續(xù)
}
}
注:IE兼容性問題
- ①IE低版本使用ActiveXObject召调,和W3C標(biāo)準(zhǔn)不一樣
- ②IE低版本使用量非常少膨桥,很多網(wǎng)站都早已不支持
- ③建議對(duì)IE低版本的兼容性了解即可,無需深究
- ④如果遇到對(duì)IE低版本要求苛刻的面試唠叛,果斷放棄
http 狀態(tài)碼
0-(未初始化)還沒有調(diào)用send()方法
1-(載入)已調(diào)用send()方法只嚣,正在發(fā)送請(qǐng)求
2-(載入完成)send()方法執(zhí)行完成,已經(jīng)接收得到全部響應(yīng)內(nèi)容
3-(交互)正在解析響應(yīng)內(nèi)容
4-(完成)響應(yīng)內(nèi)容解析完成艺沼,可以在客戶端調(diào)用了
2xx-表示成功處理請(qǐng)求册舞。如200
3xx-需要重定向,瀏覽器直接跳轉(zhuǎn)
4xx-客戶端請(qǐng)求錯(cuò)誤障般,如404
5xx-服務(wù)器端錯(cuò)誤调鲸,如500
跨域
- 什么是跨域
- JSONP
- 服務(wù)器端設(shè)置http header
存儲(chǔ)
- cookie
- localStorage
- sessionStorage
==區(qū)別:==
- 容量 cookie 只有 4 kb localStorage 最大 5MB
- 是否會(huì)攜帶到 ajax 中
- API 易用性
開發(fā)環(huán)境
前端工程師 IDE
- webstorm
- sublime
- vscode
- atom (小清新)
Git 版本管理
- 正式項(xiàng)目都需要版本管理,可以清晰的看到歷史版本
- 多人協(xié)作開發(fā)
- Git 和 Linux 是一個(gè)作者
網(wǎng)絡(luò) Git 服務(wù)器
- github
- coding.net(國內(nèi))
- 碼云
常用 git 基本命令
前端構(gòu)建工具
- grunt
- gulp
- fis3
- webpack
webpack
linux 基礎(chǔ)命令
1. mkdir a // 在當(dāng)前目錄中創(chuàng)建一個(gè)空文件夾'a'
2. ls // 查看當(dāng)前目錄下的文件
3. ll // ls -l 的簡寫
4. cd a // 進(jìn)入當(dāng)前目錄下的 a 目錄
5. pwd // 查看當(dāng)前目錄的路徑
6. cd .. // 返回上層目錄
7. rm -rf a // 刪除文件夾 a
8. vi a.js // 或者 vim 藐石;編輯 a.js 文件,寫入新的內(nèi)容并保存則會(huì)創(chuàng)建定拟;鍵入 i 進(jìn)入插入模式于微,ESC 返回剛剛的模式 :w 保存 :q 退出 :wq 保存并退出
9. cp a.js a1.js // 拷貝 a.js 存入 a1.js
10. mv a1.js <new dir> // 將 a1.js 移動(dòng)到新的文件夾下
11. rm a.js // 刪除 a.js
12. cat a.js // 查看 a.js
13. head a.js // 查看頭部內(nèi)容
14. tail a.js // 查看尾部內(nèi)容
15. head -n 1 a.js // 查看第一行
16. tail -n 2 a.js // 查看后兩行
16. grep '2' a.js // 搜索 包含 '2'
性能優(yōu)化
原則
- 多使用內(nèi)存,緩存或者其他
- 減少 CPU 計(jì)算,減少網(wǎng)絡(luò)請(qǐng)求
從哪里入手
- (加載資源)頁面資源如何加載更快
- 靜態(tài)資源的壓縮合并(多個(gè)js文件合成一個(gè)js文件株依,減少請(qǐng)求)壓縮代碼減少體積
- 使用靜態(tài)資源緩存
- 使用 CDN 讓資源加載更快
- 使用 SSR 后端渲染驱证,讓數(shù)據(jù)直接輸出到 HTML 中
- 對(duì)于頁面的渲染以及動(dòng)態(tài)操作如何更快
- CSS 放前面,JS 放后面
- 懶加載(圖片懶加載勺三,下載加載)
- 減少 DOM 查詢雷滚,對(duì) DOM 查詢做緩存
- 減少 DOM 操作,多個(gè)操作盡量合并在一起執(zhí)行
- 事件節(jié)流
幾個(gè)示例
// 1. 懶加載,頁面首次渲染先加載一個(gè)預(yù)覽圖吗坚,再用用DOM操作改變其真實(shí)需要加載的圖片
<img id = 'img1' src="preview.png" data-relsrc="abc.png"/>
<script>
var img1 = document.getElementById('img1')
img1.src = img1.getAttribute('data-realsrc')
</script>
// 2. 緩存 DOM 查詢
<script>
var i
for(i = 0;i<document.getElementsByTagName('p').length;i++){
// 每次循環(huán)都得執(zhí)行一次 DOM 查詢
}
// 緩存 DOM 查詢是這樣的
var pList = document.getElementById('p')
var i
for(i = 0;i<pList.length;i++){
//TODO
}
// 3. 合并 DOM 插入
var listNode = document.getElementById('list')
// 要插入 10 個(gè) li 標(biāo)簽
var frag = document.createDocumentFragment()
var i,li
for(i = 0; i < 10; i++){
li = document.createElement('li')
li.innerHTML = "list item " + i
frag.appendChild(li)
}
listNode.appendChild(frag)// 插入不是本身而是所有子孫節(jié)點(diǎn)
// 3. 事件節(jié)流
var textarea = document.getElementById('text')
var timeoutId
textarea.addEventListener('keyup',function{
if(timeoutId){
clearTimeout(timeoutId)
}
timeoutId = setTimeout(function(){
// 觸發(fā) change 事件
},100)
</script>
window.load
頁面的全部資源加載完成才會(huì)執(zhí)行
document.DOMContentLoaded
DOM 渲染完成即可執(zhí)行祈远,此時(shí)圖片,視頻還可能沒有加載完
安全性(了解)
- XSS (Cross Site Scripting) 跨站請(qǐng)求攻擊
- 舉例:博客文章中嵌入 script 標(biāo)簽商源,獲取閱讀者的 cookie 信息
- 解決辦法: 前端替換關(guān)鍵字或者后端替換车份,后端替換的效率高
- XSRF(Cross-site request forgery) 跨站請(qǐng)求偽造
- 增加驗(yàn)證流程,指紋牡彻,密碼扫沼,短信等
面試技巧
- 好看的簡歷,項(xiàng)目經(jīng)歷(貼上==定期維護(hù)==的博客庄吼,個(gè)人開源項(xiàng)目)
- 簡歷不可造假缎除,貼上的都應(yīng)在能力范圍內(nèi),造假很容易出破綻
- 如何看待加班总寻,救急 不救 窮
- 遇到不會(huì)回答的問題器罐,說出知道的部分也可以,轉(zhuǎn)一下問題的也比回答“不知道”好
- 談?wù)勅秉c(diǎn):說一下最近學(xué)習(xí)的東西
- 面試過程中面試官傾向于問怎么實(shí)現(xiàn)的渐行,對(duì)于不知道怎么實(shí)現(xiàn)的用法要謹(jǐn)慎說明轰坊,類似 jquery 某個(gè)用法,只知道用法不知道原理很容易被問住