web前端面试题之魂(js)
JS基礎(chǔ)
變量
面試題
1、JS使用typeof能得到哪些類型?
考點(diǎn): JS變量類型
typeof undefined, //undefined typeof 'abc' ,//string typeof 123 ,//number typeof true ,//boolean typeof {} ,//object typeof [] ,//object typeof null ,//object typeof console.log ,//function typeof Symbol(1) // symbol2、何時(shí)使用 === 何時(shí)使用 == ?
考點(diǎn): 強(qiáng)類型轉(zhuǎn)換
if(obj.a == null){//這里相當(dāng)于 obj.a === null || obj.a === undefined,簡寫形式//這是 jquery 源碼中推薦的寫法 }3、JS中有哪些內(nèi)置函數(shù)?
Object、Array、Boolean、Number、String、Function、Date、RegExp、Error、Math、JSON、window、document等。。
4、JS變量按照存儲(chǔ)方式區(qū)分哪些類型,并描述其特點(diǎn)
//值類型 //占用空間固定,值保存在棧中 //保存與復(fù)制的是值本身 var a = 10; var b = a; a = 11 console.log(b) //10//引用類型 //占用空間不固定,值保存在堆中 //保存與復(fù)制的是指向?qū)ο蟮囊粋€(gè)指針 var obj1 = {x: 100}; var obj2 = obj1; obj1.x = 200; console.log(obj2.x) //2005、如何理解JSON?
JSON 只不過是一個(gè) JS 對象而已
JSON.stringify({a:10, b:20})
JSON.parse('{"a": 10, "b": 20 }')
變量類型
——鏈接
-
值類型(內(nèi)存中存具體值) vs 引用類型(內(nèi)存中存的指針)
-
引用類型:對象,數(shù)組,函數(shù)
-
引用類型特點(diǎn):不限制擴(kuò)張屬性
-
因?yàn)橐妙愋驼紦?jù)空間較大,所以用指針來共享空間
-
-
typeof運(yùn)算符詳解
- typeof只能區(qū)分值類型的詳細(xì)類型
-
使用instanceof判斷變量的詳細(xì)類型
- arr instanceof Array; //true
-
使用Object.prototype.toString判斷。
- 數(shù)值:返回[object Number]。
- 字符串:返回[object String]。
- 布爾值:返回[object Boolean]。
- undefined:返回[object Undefined]。
- null:返回[object Null]。
- 數(shù)組:返回[object Array]。
- arguments 對象:返回[object Arguments]。
- 函數(shù):返回[object Function]。
- Error 對象:返回[object Error]。
- Date 對象:返回[object Date]。
- RegExp 對象:返回[object RegExp]。
- 其他對象:返回[object Object]。
變量計(jì)算
-
強(qiáng)制類型轉(zhuǎn)換(值類型)
-
字符串拼接
-
== 運(yùn)算符
-
使用 == 的情況,除了以下情況,其他一律用 ===
-
查看對象的屬性是否存在 》if (obj.a == null){ }
-
查看函數(shù)中的參數(shù)是否存在 》function(a,b) {if (a == null) {...} }
var obj = {}; if(obj.a == null){//這里相當(dāng)于 obj.a === null || obj.a === undefined,簡寫形式//這是 jquery 源碼中推薦的寫法 }
-
-
if語句
-
邏輯運(yùn)算 (&&、||、!(not))
-
0、NaN、’’、""、null、undefined、false 自動(dòng)轉(zhuǎn)換為false
-
原型 原型鏈
面試題
1、如何準(zhǔn)確判斷一個(gè)變量是數(shù)組類型?
變量 instanceof Array
var arr = []; arr instanceof Array //true typeof arr //"object", typeof 是無法判斷是否是數(shù)組的2、寫一個(gè)原型鏈繼承的例子
//寫一個(gè)封裝DOM的例子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)讲僮?#xff0c; 可有可無}else{return elem.innerHTML;}}Elem.prototype.on = function(type, fn){var elem = this.elem;elem.addEventListener(type, fn);return this;}var div1 = new Elem('div1');//console.log(div1.html())div1.html('<p>hello world<p>').on('click', function(){alert('clicked');}).html('<p>javascript<p>'3、描述 new 一個(gè)對象的過程
- 創(chuàng)建一個(gè)新對象
- 將構(gòu)造函數(shù)的作用域賦給新對象(this指向這個(gè)新對象)
- 執(zhí)行構(gòu)造函數(shù)中的代碼,即對this賦值
- 返回新對象,即返回this
4、zepto(或其他框架)源碼中如何使用原型鏈
構(gòu)造函數(shù)
//基本碰到首字母大寫的函數(shù), 就是構(gòu)造函數(shù),so構(gòu)造函數(shù)盡量大寫字母開頭 function Foo(name, age) {this.name = namethis.age = agethis.class = 'class-1'//return this //默認(rèn)有這一行 } var f = new Foo('zhangsan', 20) //var f1 = new Foo('lisi', 22) //創(chuàng)建多個(gè)對象構(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ù)
原型規(guī)則和實(shí)例
5條原型規(guī)則
所有的引用類型(數(shù)組、對象、函數(shù)),都具有對象的特性、即可自由擴(kuò)展屬性(除了 “null” 意外)
所有的引用類型(數(shù)組、對象、函數(shù)),都有一個(gè)__proto__(隱式原型) 屬性,屬性值是一個(gè)普通的對象
所有的函數(shù),都有一個(gè)prototype(顯示原型) 屬性, 屬性值也是一個(gè)普通的對象
所有引用類型(數(shù)組、對象、函數(shù)),__proto__ 屬性值都指向它的構(gòu)造函數(shù)的 prototype屬性值
當(dāng)試圖得到一個(gè)對象的某個(gè)屬性時(shí),如果這個(gè)對象本身沒有這個(gè)屬性,那么會(huì)去它的__proto__(即它的構(gòu)造函數(shù)的prototype) 中尋找。
原型鏈
JavaScript對象有一個(gè)指向一個(gè)原型對象的鏈。當(dāng)試圖訪問一個(gè)對象的屬性時(shí),它不僅僅在該對象上搜尋,還會(huì)搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-xbtUgEGA-1590071179192)(https://i.loli.net/2019/05/21/5ce3f4978a28565863.png)]
instanceof
instanceof運(yùn)算符用于測試構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在對象的原型鏈中的任何位置
f instanceof Foo 的判斷邏輯是:
f 的 __proto__一層層往上,能否對應(yīng)到 Foo.prototype
在試著判斷 f instanceof Object
作用域 閉包
面試題
1、說一下對變量提升的理解
-
分為變量定義和函數(shù)聲明(和函數(shù)表達(dá)式的區(qū)別)
-
全局作用域和函數(shù)作用域或者是(ES6)中塊級作用域,變量聲明(var)和函數(shù)聲明會(huì)被提升到作用域頂部,而函數(shù)表達(dá)式不會(huì),只是當(dāng)做一個(gè)var變量提升,函數(shù)沒有被提升,另外ES6 中 let 和 const標(biāo)識(shí)符定義的變量也不會(huì)發(fā)生提升(暫時(shí)性死區(qū) TDZ)
2、說明this幾種不同的使用場景
- 作為構(gòu)造函數(shù)執(zhí)行
- 作為對象屬性執(zhí)行
- 作為普通函數(shù)執(zhí)行
- call apply bind
- 箭頭函數(shù)中(ES6)
this指的是當(dāng)前運(yùn)行的環(huán)境,即執(zhí)行的時(shí)候
3、創(chuàng)建10個(gè)a標(biāo)簽,點(diǎn)擊的時(shí)候彈出來對應(yīng)的序號(hào)
var i; for(i=0, i<10,i++) {var a = document.createElement('a');(function(i) {a.innerHTML= a +'<br>';a.addEventListener('click', function(e) {e.preventDefault();alert(i)})document.body.appendChild(a);})(i) }4、如何理解作用域
- 自由變量: 在當(dāng)前作用域沒有被定義的變量
- 作用域鏈:若在當(dāng)前作用域找不到,則往父級作用域查找,自由變量的查找
- 父級作用域:函數(shù)定義時(shí)所在的上下文
- 閉包兩個(gè)場景,作為參數(shù)傳入和函數(shù)返回值
5、實(shí)際開發(fā)中閉包的應(yīng)用
-
閉包實(shí)際引用中主要用于封裝變量,收斂權(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); //true firstload(10); //false firstload(20); //true
執(zhí)行上下文
范圍:一段
全局:變量定義、函數(shù)聲明
函數(shù):變量定義、函數(shù)聲明、this、arguments、函數(shù)
- 函數(shù)聲明:function fnName () {…};
- 函數(shù)表達(dá)式 var fnName = function () {…};
- 匿名函數(shù):function () {};
- 匿名函數(shù)屬于函數(shù)表達(dá)式
PS:注意“函數(shù)聲明”和“函數(shù)表達(dá)式”的區(qū)別
- JS解析時(shí)會(huì)提升當(dāng)前作用域的函數(shù)聲明,而函數(shù)表達(dá)式必須等到JS引擎執(zhí)行到時(shí),才會(huì)解析函數(shù)表達(dá)式。
- 函數(shù)表達(dá)式后面可以加括號(hào)立即調(diào)用該函數(shù),函數(shù)聲明不可以
- 變量定義會(huì)把聲明提前(undefined)未賦值,函數(shù)聲明會(huì)把整個(gè)函數(shù)提前,函數(shù)表達(dá)式只會(huì)把函數(shù)名提前
this
在全局環(huán)境中,this 永遠(yuǎn)指向 window。
-
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í)行
-
作為對象屬性執(zhí)行
-
作為普通函數(shù)執(zhí)行 (this指向window)
-
call apply bind
作用域
- JS沒有塊級作用域,不要塊中定義變量
- 只有函數(shù)和全局作用域
作用域鏈
自由變量不停的往父級作用域查找,就是所謂的作用域鏈
var a = 100 function F1() {var b = 200//當(dāng)前作用域沒有定義的變量,即“自由變量”function F2() {console.log(a) // a是自由變量console.log(b) // b是自由變量console.log(c)}F2() }閉包
有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)
-
函數(shù)作為返回值,在父作用域去找自由變量的值
-
函數(shù)作為參數(shù)傳遞
異步單線程
面試題目
- 同步和異步的區(qū)別是什么?分別舉一個(gè)同步和異步的例子
- 同步會(huì)阻塞代碼執(zhí)行,而異步不會(huì)
- alert是同步,setTimeout是異步
- 一個(gè)關(guān)于setTimeout的筆試題
- 前端使用異步的場景有哪些?
- 定時(shí)任務(wù):setTimeout setInverval
- 網(wǎng)絡(luò)請求:ajax 動(dòng)態(tài)加載
- 事件綁定
什么是異步(對比同步)
前端使用異步的場景
- 在可能發(fā)生等待的情況,等待過程中不能相當(dāng)alert一樣阻塞程序運(yùn)行,因此在發(fā)生等待的時(shí)候需要異步。
- 定時(shí)任務(wù):setTimeout,setInverval
- 網(wǎng)絡(luò)請求:ajax請求,動(dòng)態(tài)加載
- 事件綁定
異步和單線程
其他知識(shí)
面試題
-
獲取 2017-06-10格式的日期
function formatDate(dt) {if(!dt) {dt = new Date()}var year = dt.getFullYear()var month = dt.getMonth()var date = dt.getDate()if(month < 10){month = '0' + month}if(date < 10){date = '0' + date}return year + '-' + month + '-' + date } console.log(formatDate(new Date())) -
獲取隨機(jī)數(shù),要求是長度一致的字符串格式
var random = Math.random() random = random + '0000000000'; random = random.slice(0, 10); console.log(random) -
寫一個(gè)能遍歷對象和數(shù)組的通用 forEach 函數(shù)
function forEach(obj, fn){var keyif(obj instanceof Array){obj.forEach(function(item, index) {fn(index, item)})}else {if(obj.hasOwnProperty(key)){for(key in obj) {fn(key, obj[key])}}} } var arr = [1,2,3] forEach(arr, function(index, item) {console.log(index, item) }) var obj = {x:100, y:200} forEach(obj, function(key, val) {console.log(key, val) })
日期
Date.now() //獲取當(dāng)前毫秒數(shù) var dt = new Date() dt.getTime() //獲取毫秒數(shù) dt.getFullYear() //年 dt.getMonth() //月 (0 - 11) 要加上 +1 dt.getDate() //日 (0 - 31) dt.getHours() //小時(shí) (0 - 23) dt.getMinutes() //分鐘 (0 - 59) dt.getSeconds() //秒 (0 - 59)Math
Math.random() //獲取隨機(jī)數(shù) 在鏈接后加隨機(jī)數(shù),可以清除緩存數(shù)組API
- forEach 遍歷所有元素
- every 判斷所有元素是否都符合條件
- some 判斷是否有至少一個(gè)元素符合條件
- sort 排序
- map 對元素重新組裝,生成新數(shù)組
- filter 過濾符合條件的元素
對象API
- for(key in obj) {}
JS-WEB-AIP
常說的JS(瀏覽器執(zhí)行的JS)包含兩部分
- 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操作
-
DOM是哪種基本的數(shù)據(jù)結(jié)構(gòu)
- 樹
-
DOM操作的常用API有哪些
- 獲取DOM節(jié)點(diǎn),以及節(jié)點(diǎn)property和Attribute
- 獲取父節(jié)點(diǎn),獲取子節(jié)點(diǎn)
- 新增節(jié)點(diǎn),刪除節(jié)點(diǎn)
-
DOM節(jié)點(diǎn)的Attribute 和property有和區(qū)別
- property是DOM中的屬性,是Javascript里的對象;
- Attribute是HTML上的特性,它的值必須是字符串或者null
- 自定義的Property與Attribute不同步,不相等
- 非自定義的DOM property與 attributes 是有條件同步的
- 在IE<9中,瀏覽器會(huì)把所有的property和attribute強(qiáng)制映射
DOM的本質(zhì)
Element節(jié)點(diǎn)
-
新增節(jié)點(diǎn)
var div1 = document.getElementById('div1') //添加新節(jié)點(diǎn) var p1 = document.createElement('p') p1.innerHTML = 'this is p1' div1.appendChild(p1) //添加新創(chuàng)建的元素 //移動(dòng)已有節(jié)點(diǎn) p2 = document.getElementById('p2') div1.appendChild('p2') -
獲取父元素
var div1 = document.getElementById('div1') var parent = div1.parentElement;var child = div1.childNodes div1.removeChild(child[0]) -
獲取子元素
-
刪除節(jié)點(diǎn)
獲取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('.container')//集合 var plist = document.querySelectorAll('p') //集合節(jié)點(diǎn)屬性property
- style
- className
- nodeName
- nodeType
Attribute屬性操作
- Element.attributes
- Element.getAttribute() 讀取某個(gè)屬性的值
- Element.getAttributeNames() 返回當(dāng)前元素的所有屬性名
- Element.setAttribute() 寫入屬性值
- Element.hasAttribute() 某個(gè)屬性是否存在
- Element.hasAttributes() 當(dāng)前元素是否有屬性
- Element.removeAttribute() 刪除屬性
BOM
- 如何檢測瀏覽器的類型
- 拆解url的各部分
navigator(瀏覽器)
- navigator.userAgent (簡稱ua)
screen
- screen.width
- screen.height
location
- location.href //地址
- location.protocol //協(xié)議
- location.host //域名
- location.pathname //路徑
- location.search //查詢字符串
- location.hash //哈希
history
- history.back() //返回
- history.forward() //前進(jìn)
事件綁定
題目
- 編寫一個(gè)通用的事件監(jiān)聽函數(shù)
- 描述事件冒泡流程
- 對于一個(gè)無限下拉加載圖片的頁面,如何給每個(gè)圖片綁定事件
DOM事件流
DOM事件流(event? flow?)存在三個(gè)階段:事件捕獲階段、處于目標(biāo)階段、事件冒泡階段。 dom標(biāo)準(zhǔn)事件流的觸發(fā)的先后順序?yàn)?#xff1a;先捕獲再冒泡
- 事件捕獲(event? capturing):當(dāng)鼠標(biāo)點(diǎn)擊或者觸發(fā)dom事件時(shí),瀏覽器會(huì)從根節(jié)點(diǎn)開始由外到內(nèi)進(jìn)行事件傳播,即點(diǎn)擊了子元素,如果父元素通過事件捕獲方式注冊了對應(yīng)的事件的話,會(huì)先觸發(fā)父元素綁定的事件。
- **事件冒泡(dubbed? bubbling):**與事件捕獲恰恰相反,事件冒泡順序是由內(nèi)到外進(jìn)行事件傳播,從目標(biāo)元素直到根節(jié)點(diǎn)。
- 阻止事件冒泡 stopPropagation()
關(guān)于IE低版本的兼容性
- IE低版本使用attachEvent綁定事件,和W3C標(biāo)準(zhǔn)不一樣
- IE低版本使用量已經(jīng)非常少,很多網(wǎng)站都早已不支持
- 建議對IE低版本的兼容性:了解即可,無需深究
- 如果遇到對IE低版本要求苛刻的面試,果斷放棄
- IE10及以下不支持捕獲型事件,所以就少了一個(gè)事件捕獲階段,IE11、Chrome?、Firefox、Safari等瀏覽器則同時(shí)存在。
通用事件綁定與解綁
代理
事件委托
JS開發(fā)環(huán)境
- IDE(寫代碼的效率)
版本管理GIT
JS模塊化
打包工具
運(yùn)行環(huán)境
頁面渲染
性能優(yōu)化
JS面試題
6、window.onload 和 DOMConetentLoaded 的區(qū)別?
考點(diǎn):瀏覽器渲染過程
7、用JS創(chuàng)建10個(gè)標(biāo)簽, 點(diǎn)擊的時(shí)候彈出來對應(yīng)的序號(hào)?
考點(diǎn):作用域
8、簡述如何實(shí)現(xiàn)一個(gè)模塊加載器, 實(shí)現(xiàn)類似require.js的基本功能?
考點(diǎn):JS模塊化
9、實(shí)現(xiàn)數(shù)組的隨機(jī)排序?
考點(diǎn):JS基礎(chǔ)算法
HTTP
同源策略
同源策略可防止 JavaScript 發(fā)起跨域請求。源被定義為 URI、主機(jī)名和端口號(hào)的組合。此策略可防止頁面上的惡意腳本通過該頁面的文檔對象模型,訪問另一個(gè)網(wǎng)頁上的敏感數(shù)據(jù)。
跨域
原因:瀏覽器同源策略導(dǎo)致了跨域
作用:隔離惡意文件的重要安全機(jī)制
解決:
jsonp原理詳解
總結(jié)
以上是生活随笔為你收集整理的web前端面试题之魂(js)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微前端解读
- 下一篇: android 小米手机播放短小音频无声