面筋

webpack相關(guān) https://blog.csdn.net/sinat_17775997/article/details/84314006

react相關(guān) https://www.imooc.com/article/309371

JavaScript中常見的八個陷阱總結(jié) https://www.jb51.net/article/117337.htm


0.react和vue

1、監(jiān)聽數(shù)據(jù)變化的實現(xiàn)原理不同

Vue通過 getter/setter以及一些函數(shù)的劫持,能精確知道數(shù)據(jù)變化。

React默認是通過比較引用的方式(diff)進行的,如果不優(yōu)化可能導致大量不必要的VDOM的重新渲染。為什么React不精確監(jiān)聽數(shù)據(jù)變化呢?這是因為Vue和React設(shè)計理念上的區(qū)別,Vue使用的是可變數(shù)據(jù),而React更強調(diào)數(shù)據(jù)的不可變,兩者沒有好壞之分,Vue更加簡單,而React構(gòu)建大型應(yīng)用的時候更加棒。

2、數(shù)據(jù)流的不同

Vue1.0中可以實現(xiàn)兩種雙向綁定:父子組件之間,props可以雙向綁定;組件與DOM之間可以通過v-model雙向綁定。Vue2.x中去掉了第一種,也就是父子組件之間不能雙向綁定了(但是提供了一個語法糖自動幫你通過事件的方式修改),并且Vue2.x已經(jīng)不鼓勵組件對自己的 props進行任何修改了。

React不支持雙向綁定需要自己實現(xiàn),提倡的是單向數(shù)據(jù)流,稱之為onChange/setState()模式。不過由于我們一般都會用Vuex以及Redux等單向數(shù)據(jù)流的狀態(tài)管理框架,因此很多時候我們感受不到這一點的區(qū)別了。

3、HoC和mixins

HoC和mixinsVue組合不同功能的方式是通過mixin,Vue中組件是一個被包裝的函數(shù),并不簡單的就是我們定義組件的時候傳入的對象或者函數(shù)。比如我們定義的模板怎么被編譯的?比如聲明的props怎么接收到的?這些都是vue創(chuàng)建組件實例的時候隱式干的事。由于vue默默幫我們做了這么多事,所以我們自己如果直接把組件的聲明包裝一下,返回一個HoC,那么這個被包裝的組件就無法正常工作了。

React組合不同功能的方式是通過HoC(高階組件)。React最早也是使用mixins的,不過后來他們覺得這種方式對組件侵入太強會導致很多問題,就棄用了mixinx轉(zhuǎn)而使用HoC。高階組件本質(zhì)就是高階函數(shù),React的組件是一個純粹的函數(shù),所以高階函數(shù)對React來說非常簡單。

4、組件通信的區(qū)別

Vue中有三種方式可以實現(xiàn)組件通信:父組件通過props向子組件傳遞數(shù)據(jù)或者回調(diào),雖然可以傳遞回調(diào),但是我們一般只傳數(shù)據(jù);子組件通過事件向父組件發(fā)送消息;通過V2.2.0中新增的provide/inject來實現(xiàn)父組件向子組件注入數(shù)據(jù),可以跨越多個層級。React中也有對應(yīng)的三種方式:父組件通過props可以向子組件傳遞數(shù)據(jù)或者回調(diào);可以通過 context 進行跨層級的通信,這其實和 provide/inject 起到的作用差不多。React 本身并不支持自定義事件,而Vue中子組件向父組件傳遞消息有兩種方式:事件和回調(diào)函數(shù),但Vue更傾向于使用事件。在React中我們都是使用回調(diào)函數(shù)的,這可能是他們二者最大的區(qū)別。

5.模板渲染方式的不同

在表層上,模板的語法不同,React是通過JSX渲染模板。而Vue是通過一種拓展的HTML語法進行渲染,但其實這只是表面現(xiàn)象,畢竟React并不必須依賴JSX。

在深層上,模板的原理不同,這才是他們的本質(zhì)區(qū)別:React是在組件JS代碼中,通過原生JS實現(xiàn)模板中的常見語法,比如插值,條件,循環(huán)等,都是通過JS語法實現(xiàn)的,更加純粹更加原生。而Vue是在和組件JS代碼分離的單獨的模板中,通過指令來實現(xiàn)的,比如條件語句就需要 v-if 來實現(xiàn)對這一點,這樣的做法顯得有些獨特,會把HTML弄得很亂。

舉個例子,說明React的好處:react中render函數(shù)是支持閉包特性的,所以我們import的組件在render中可以直接調(diào)用。但是在Vue中,由于模板中使用的數(shù)據(jù)都必須掛在 this 上進行一次中轉(zhuǎn),所以我們import 一個組件完了之后,還需要在 components 中再聲明下,這樣顯然是很奇怪但又不得不這樣的做法。

6、渲染過程不同

Vue可以更快地計算出Virtual DOM的差異,這是由于它在渲染過程中,會跟蹤每一個組件的依賴關(guān)系,不需要重新渲染整個組件樹。

React在應(yīng)用的狀態(tài)被改變時,全部子組件都會重新渲染。通過shouldComponentUpdate這個生命周期方法可以進行控制,但Vue將此視為默認的優(yōu)化。

如果應(yīng)用中交互復(fù)雜,需要處理大量的UI變化,那么使用Virtual DOM是一個好主意。如果更新元素并不頻繁,那么Virtual DOM并不一定適用,性能很可能還不如直接操控DOM。

7.Vuex和Redux的區(qū)別

從表面上來說,store注入和使用方式有一些區(qū)別。在Vuex中,$store被直接注入到了組件實例中,因此可以比較靈活的使用:使用dispatch、commit提交更新,通過mapState或者直接通過this.$store來讀取數(shù)據(jù)。在Redux中,我們每一個組件都需要顯示的用connect把需要的props和dispatch連接起來。另外,Vuex更加靈活一些,組件中既可以dispatch action,也可以commit updates,而Redux中只能進行dispatch,不能直接調(diào)用reducer進行修改。

從實現(xiàn)原理上來說,最大的區(qū)別是兩點:Redux使用的是不可變數(shù)據(jù),而Vuex的數(shù)據(jù)是可變的,因此,Redux每次都是用新state替換舊state,而Vuex是直接修改。Redux在檢測數(shù)據(jù)變化的時候,是通過diff的方式比較差異的,而Vuex其實和Vue的原理一樣,是通過getter/setter來比較的,這兩點的區(qū)別,也是因為React和Vue的設(shè)計理念不同。React更偏向于構(gòu)建穩(wěn)定大型的應(yīng)用,非常的科班化。相比之下,Vue更偏向于簡單迅速的解決問題,更靈活,不那么嚴格遵循條條框框。因此也會給人一種大型項目用React,小型項目用Vue的感覺。

解釋一下典型的react 和 redux數(shù)據(jù)流。

首先是dispatch一個action。然后reducer會收到這個action, 根據(jù)這個action對狀態(tài)進行修改store。狀態(tài)修改以后會被處理容器捕捉到。從而對相關(guān)的界面進行更新

———————————————


1.介紹一下Javascript的執(zhí)行上下文?

執(zhí)行上下文有且只有三類,全局執(zhí)行上下文,函數(shù)上下文,與eval上下文;eval一般不會使用。

全局執(zhí)行上下文只有一個,在客戶端中一般由瀏覽器創(chuàng)建,也就是我們熟知的window對象,我們能通過this直接訪問到它。

函數(shù)執(zhí)行上下文可存在無數(shù)個,每當一個函數(shù)被調(diào)用時都會創(chuàng)建一個函數(shù)上下文;需要注意的是,同一個函數(shù)被多次調(diào)用,都會創(chuàng)建一個新的上下文。

執(zhí)行上下文棧也叫調(diào)用棧,執(zhí)行棧用于存儲代碼執(zhí)行期間創(chuàng)建的所有上下文,具有LIFO(Last In First Out后進先出,也就是先進后出)的特性。

JS代碼首次運行,都會先創(chuàng)建一個全局執(zhí)行上下文并壓入到執(zhí)行棧中,之后每當有函數(shù)被調(diào)用,都會創(chuàng)建一個新的函數(shù)執(zhí)行上下文并壓入棧內(nèi);由于執(zhí)行棧LIFO的特性,所以可以理解為,JS代碼執(zhí)行完畢前在執(zhí)行棧底部永遠有個全局執(zhí)行上下文。

2.NaN 是什么,用 typeof 會輸出什么?

NaN 是 ‘not a number’ 的縮寫,表示 “不是一個數(shù)字”

通常會在一個數(shù)字和其他類型運算過程中產(chǎn)生:

雖然它 “不是一個數(shù)字”,但是 NaN 的 typeof 結(jié)果卻是 number

console.log(typeof (NAN)); // number

NaN 和任何變量都不相等,包括 NaN 自己

console.log(NaN === NaN); // false

判斷一個變量是不是 NaN 可以用 isNaN()方法或者Number.isNaN()方法

3.instance 如何使用?

在書面語中,實例是實際的例子,而在計算機語音中,實例就是一個類的真實對象,類在實例化后就叫做一個實例。類是靜態(tài)的,不占進程內(nèi)存,而實例擁有動態(tài)內(nèi)存。通俗的說,打個比方,汽車是一個類,張三的車,李四的車就是汽車的實例。

實例和對象的區(qū)別

實例是類的具象化產(chǎn)品

對象是一個具有多種屬性的內(nèi)容結(jié)構(gòu)

實例都是對象,而對象不全是實例

instance 如何使用

instance通過new操作符來創(chuàng)建實例對象,它可以用來判斷對象是否是某個類或構(gòu)造函數(shù)的實例。

創(chuàng)建一個實例有三種方式:

關(guān)鍵字 new 創(chuàng)建:var ins = new Object(); ins.name = "dandan"; ins.job = "javascript";

工廠模式創(chuàng)建:function createInstance(name,job){var ins = new Object();ins.name = name;ins.job = job;ins.sayName = function(){alert(this.name);}return ins;}

構(gòu)造函數(shù)模式:function createInstance(name,job){this.name = name;this.job = job;this.sayName = function(){alert(this.name);}}

4.函數(shù)中的arguments是數(shù)組嗎?類數(shù)組轉(zhuǎn)數(shù)組的方法了解一下?

不是

類數(shù)組轉(zhuǎn)數(shù)組

Array.from()

[...arguments]

5.

閉包的定義

閉包指的是那些引用了另一個函數(shù)作用域中變量的函數(shù),通常是在嵌套函數(shù)中實現(xiàn)的

閉包的優(yōu)缺點

優(yōu)點:對私有變量進行保護和保存,創(chuàng)建一個安全的環(huán)境,保證內(nèi)部代碼不受到外部的干涉,(實現(xiàn)私有成員,對外只暴露幾個接口)

缺點:如果使用不當會造成內(nèi)存泄漏

閉包的應(yīng)用

函數(shù)的防抖和節(jié)流,唯一彈窗,瀏覽器判斷以及柯里化函數(shù)、compose組合函數(shù),react樹狀更新機制等都應(yīng)用到了閉包。

//防抖

function debounce(func,wait,...args){

let timeout;? ? //延時器變量

return function(){

? const context = this;

? if (timeout) clearTimeout(timeout);

? let callNow = !timeout;? ? //是否立即執(zhí)行

? timeout = setTimeout(() => {

? ? timeout = null;

? },wait)

? if(callNow) func.apply(context,args)

}

}

單例模式前端最典型的應(yīng)用場景,全局唯一消息框

```html

<head>

? ? <meta charset="UTF-8">

? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">

? ? <title>Document</title>

? ? <style>

? ? ? ? .model {

? ? ? ? ? ? width: 200px;

? ? ? ? ? ? height: 200px;

? ? ? ? ? ? border: 1px solid aqua;

? ? ? ? ? ? position: fixed;

? ? ? ? ? ? top: 50%;

? ? ? ? ? ? left: 50%;

? ? ? ? ? ? transform: translate(-50%, -50%);

? ? ? ? ? ? text-align: center;

? ? ? ? }

? ? </style>

</head>

<body>

? ? <div id="loginBtn">點我</div>

? ? <script>

? ? ? ? var getSingle = function (fn) {

? ? ? ? ? ? var result; //緩存實例

? ? ? ? ? ? return function () {

? ? ? ? ? ? ? ? return result || (result = fn.apply(this, arguments))

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? var createLoginLayer = function () {

? ? ? ? ? ? var oDiv = document.createElement("div");

? ? ? ? ? ? oDiv.innerHTML = "我是登錄浮窗";

? ? ? ? ? ? oDiv.className = "model";

? ? ? ? ? ? oDiv.style.display = "none";

? ? ? ? ? ? document.body.appendChild(oDiv);

? ? ? ? ? ? return oDiv;

? ? ? ? }

? ? ? ? var createSingleLoginLayer = getSingle(createLoginLayer);

? ? ? ? document.getElementById("loginBtn").onclick = function () {

? ? ? ? ? ? //動態(tài)創(chuàng)建彈窗

? ? ? ? ? ? //新建一個彈窗實例,內(nèi)部使用單例模式管理,一直只能有一個.

? ? ? ? ? ? var loginLayer = createSingleLoginLayer();

? ? ? ? ? ? loginLayer.style.display = "block"

? ? ? ? }

? ? </script>

</body>

```

(1)柯里化函數(shù)【偏應(yīng)用函數(shù)】

是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。

1.函數(shù)復(fù)用

// 正常正則驗證字符串

reg.test(txt)

// 函數(shù)封裝后

function check(reg,txt){

returnreg.test(txt)

}

check(/\d+/g,'test')//false

check(/[a-z]+/g,'test')//true

// Currying后

function curryingCheck(reg){

return function(txt){

? ? return reg.test(txt)

}}

var hasNumber=curryingCheck(/\d+/g)

var hasLetter=curryingCheck(/[a-z]+/g)

hasNumber('test1')// true

hasNumber('testtest')// false

hasLetter('21212')// false

2. 提前確認

var on = function(element, event, handler) {? ? if (document.addEventListener) {? ? ? ? if (element && event && handler) {? ? ? ? ? ? element.addEventListener(event, handler, false);? ? ? ? }? ? } else {? ? ? ? if (element && event && handler) {? ? ? ? ? ? element.attachEvent('on' + event, handler);? ? ? ? }? ? }}var on = (function() {? ? if (document.addEventListener) {? ? ? ? return function(element, event, handler) {? ? ? ? ? ? if (element && event && handler) {? ? ? ? ? ? ? ? element.addEventListener(event, handler, false);? ? ? ? ? ? }? ? ? ? };? ? } else {? ? ? ? return function(element, event, handler) {? ? ? ? ? ? if (element && event && handler) {? ? ? ? ? ? ? ? element.attachEvent('on' + event, handler);? ? ? ? ? ? }? ? ? ? };? ? }})();

//換一種寫法可能比較好理解一點,上面就是把isSupport這個參數(shù)給先確定下來了var on = function(isSupport, element, event, handler) {? ? isSupport = isSupport || document.addEventListener;? ? if (isSupport) {? ? ? ? return element.addEventListener(event, handler, false);? ? } else {? ? ? ? return element.attachEvent('on' + event, handler);? ? }}

curry的一些性能問題你只要知道下面四點就差不多了:

? ? 存取arguments對象通常要比存取命名參數(shù)要慢一點

? ? 一些老版本的瀏覽器在arguments.length的實現(xiàn)上是相當慢的

? ? 使用fn.apply( … ) 和 fn.call( … )通常比直接調(diào)用fn( … ) 稍微慢點

? ? 創(chuàng)建大量嵌套作用域和閉包函數(shù)會帶來花銷,無論是在內(nèi)存還是速度上

其實在大部分應(yīng)用中,主要的性能瓶頸是在操作DOM節(jié)點上,這js的性能損耗基本是可以忽略不計的,所以curry是可以直接放心的使用。

類庫封裝,rollup, 構(gòu)建器打包 webpack

webpack更適合打包組件庫、應(yīng)用程序之類的應(yīng)用,而rollup更適合打包純js的類庫。

6. new 一個構(gòu)造函數(shù),如果函數(shù)返回 return {} 、 return null , return 1 , return true 會發(fā)生什么情況?

只有在構(gòu)造函數(shù) return 的數(shù)據(jù)類型是 Object 時才會執(zhí)行該 return 語句,其余情況均返回該構(gòu)造函數(shù)的一個實例。

return {} 返回空對象,

其余情況返回實例。

7.symbol 有什么用處?

Symbol是原始類型,

可以給對象設(shè)置唯一值類型的屬性

把Symbol作為對象,它提供了很多靜態(tài)方法,是JS很多底層的實現(xiàn)原理出處

- Symbol.toPrimitive

- Symbol.hasInstance

- Symbol.toStringTag

- Symbol.iterator

- Symbol.asyncIterator

vuex/redux中需要派發(fā)很多行為標識,可以把這些行為標識統(tǒng)一管理,利用Symbol的唯一性來進行管理實現(xiàn)

8.判斷數(shù)據(jù)類型的方式有哪些?

string,number,object,boolean,undefined,null,symbol,bigint

1.null === undefined 但是null == undefined

== 代表相同, ===代表嚴格相同, 為啥這么說呢,

這么理解: 當進行雙等號比較時候: 先檢查兩個操作數(shù)數(shù)據(jù)類型,如果相同, 則進行===比較, 如果不同, 則愿意為你進行一次類型轉(zhuǎn)換, 轉(zhuǎn)換成相同類型后再進行比較, 而===比較時, 如果類型不同,直接就是false.

2.undefined不是保留值,直接定義會有危險可以用void 0

3.null代表空值,undefined代表未定義


9.如何判斷一個對象是不是空對象?

使用 Object.keys(obj).length 為 0,說明是空對象

10.call 、bind 、 apply 區(qū)別

call 、bind 、 apply 這三個函數(shù)的第一個參數(shù)都是 this 的指向?qū)ο螅?/p>

call 的參數(shù)是直接放進去的,第二第三第 n 個參數(shù)全都用逗號分隔,直接放到后面 obj.myFun.call(db,'成都', ... ,'string' )。

apply 的所有參數(shù)都必須放在一個數(shù)組里面?zhèn)鬟M去 obj.myFun.apply(db,['成都', ..., 'string' ])。

bind 除了返回是函數(shù)以外,它 的參數(shù)和 call 一樣。

當然,三者的參數(shù)不限定是 string 類型,允許是各種類型,包括函數(shù) 、 object 等等!

11.判斷數(shù)組類型的方法

var arr = []

arr.constructor === Array // true

Array.isArray(arr)

Object.prototype.toString.call(arr) === '[object Array]'

arr instanceof Array

Array.prototype.isPrototypeOf(arr)

12.分析一下箭頭語法為什么不能當做構(gòu)造函數(shù)

是因為箭頭函數(shù)沒有 [[Construct]] 。如果通過new調(diào)用,就會出錯

functionPerson(){}

console.log(Person.prototype);

// {constructor: ?}

let Animal=()=>{};

console.log(Animal.prototype);

// undefined

注意點:

箭頭函數(shù)沒有自己的 this,而是繼承父作用域的 this

不支持 call bind,改變 this 指向。

不綁定 arguments

沒有 prototype 屬性


13.你知道webpack的作用是什么嗎?

模塊打包??梢詫⒉煌K的文件打包整合在一起,并且保證它們之間的引用正確,執(zhí)行有序。利用打包我們就可以在開發(fā)的時候根據(jù)我們自己的業(yè)務(wù)自由劃分文件模塊,保證項目結(jié)構(gòu)的清晰和可讀性。

編譯兼容。在前端的“上古時期”,手寫一堆瀏覽器兼容代碼一直是令前端工程師頭皮發(fā)麻的事情,而在今天這個問題被大大的弱化了,通過webpack的Loader機制,不僅僅可以幫助我們對代碼做polyfill,還可以編譯轉(zhuǎn)換諸如.less, .vue, .jsx這類在瀏覽器無法識別的格式文件,讓我們在開發(fā)的時候可以使用新特性和新語法做開發(fā),提高開發(fā)效率。

能力擴展。通過webpack的Plugin機制,我們在實現(xiàn)模塊化打包和編譯兼容的基礎(chǔ)上,可以進一步實現(xiàn)諸如按需加載,代碼壓縮等一系列功能,幫助我們進一步提高自動化程度,工程效率以及打包輸出的質(zhì)量。


14.說一下模塊打包運行的原理

如果面試官問你Webpack是如何把這些模塊合并到一起,并且保證其正常工作的,你是否了解呢?

首先我們應(yīng)該簡單了解一下webpack的整個打包流程:

1、讀取webpack的配置參數(shù);

2、啟動webpack,創(chuàng)建Compiler對象并開始解析項目;

3、從入口文件(entry)開始解析,并且找到其導入的依賴模塊,遞歸遍歷分析,形成依賴關(guān)系樹;

4、對不同文件類型的依賴模塊文件使用對應(yīng)的Loader進行編譯,最終轉(zhuǎn)為Javascript文件;

5、整個過程中webpack會通過發(fā)布訂閱模式,通過plugin注入鉤子,而webpack的插件即可通過監(jiān)聽這些關(guān)鍵的事件節(jié)點,執(zhí)行插件任務(wù)進而達到干預(yù)輸出結(jié)果的目的。

其中文件的解析與構(gòu)建是一個比較復(fù)雜的過程,在webpack源碼中主要依賴于compiler和compilation兩個核心對象實現(xiàn)。

compiler對象是一個全局單例,他負責把控整個webpack打包的構(gòu)建流程。compilation對象是每一次構(gòu)建的上下文對象,它包含了當次構(gòu)建所需要的所有信息,每次熱更新和重新構(gòu)建,compiler都會重新生成一個新的compilation對象,負責此次更新的構(gòu)建過程。

而每個模塊間的依賴關(guān)系,則依賴于AST語法樹。每個模塊文件在通過Loader解析完成之后,會通過acorn庫生成模塊代碼的AST語法樹,通過語法樹就可以分析這個模塊是否還有依賴的模塊,進而繼續(xù)循環(huán)執(zhí)行下一個模塊的編譯解析。

最終Webpack打包出來的bundle文件是一個IIFE的執(zhí)行函數(shù)。

優(yōu)化

0.優(yōu)化Loader 對于Loader來說,首先優(yōu)化的當是babel了,babel會將代碼轉(zhuǎn)成字符串并生成AST,然后繼續(xù)轉(zhuǎn)化成新的代碼,轉(zhuǎn)換的代碼越多,效率就越低。優(yōu)化Loader的搜索范圍,include: [resolve('src')],// 只在src文件夾下查找。可以將babel編譯過文件緩存起來,以此加快打包時間,主要在于設(shè)置cacheDirectory,loader:'babel-loader?cacheDirectory=true'

1.webpack打包出來的文件,減少緩存可以用hash:true

2.啟用用gzip,壓縮html和css代碼,通過配置刪除console.log和debugger等,防止可能造成的內(nèi)存泄漏

3.Tree shaking生產(chǎn)環(huán)境它會刪除項目中未被引用的代碼

4.DllPlugin該插件可以將特定的類庫提前打包然后引入

15.innerHTML、 nodeValue與 textContent之間的區(qū)別

element.innerHTML設(shè)置或獲取HTML語法表示的元素的后代, 顧名思義就是返回DOM節(jié)點的子HTML代碼, 如果是設(shè)置的話會解析HTML(會遭到惡意攻擊)

node.nodeValue 一般用來獲取文本節(jié)點的值

node.textContent獲取節(jié)點及子節(jié)點的文本內(nèi)容,而且不會受css影響會返回隱藏的節(jié)點的內(nèi)容,設(shè)置內(nèi)容不會解析成HTML

<div id="test">

? 123

<span>456</span>

? <span style="display:none;">789</span>

</div>

<script>

? const testDOM = document.getElementById('test')

const innerHTMLStr = testDOM.innerHTML

const nodeValueStr = testDOM.childNodes[0].nodeValue

const textContent = testDOM.textContent

console.log(innerHTMLStr)

// '\n? 123\n<span>456</span><span style="display:none;">789</span>\n'

console.log(nodeValueStr)

// '\n? 123\n? '

console.log(textContent)

// '\n? 123\n? 456789\n'

</script>


16.怎樣添加、移除、移動、復(fù)制、創(chuàng)建和查找節(jié)點?

(1)創(chuàng)建新節(jié)點

createDocumentFragment() //創(chuàng)建一個DOM片段

createElement() //創(chuàng)建一個具體的元素

createTextNode() //創(chuàng)建一個文本節(jié)點

(2)添加、移除、替換、插入、復(fù)制

appendChild() //添加

removeChild() //移除

replaceChild() //替換

insertBefore() //在已有的子節(jié)點前插入一個新的子節(jié)點

cloneNode() //復(fù)制

(3)查找

getElementsByTagName() //通過標簽名稱

getElementsByName()//通過元素的Name屬性的值(IE容錯能力較強,會得到一個數(shù)組,其中包括id等于 name值的)

getElementById() //通過元素Id,唯一性


17.輸入框中只能輸入數(shù)字 請輸入您的年齡

JS代碼如下所示:

//當按鍵按下時,阻止非數(shù)字字符的輸入

function digitOnly(event) {

var code= event.keyCode | | event.which; //ie| |firefox if( (code<48) | | (code>57) ) {

if(event.preventDefault) { //firefox

event.preventDefault( ) ;

}

/ /當按鍵彈起時 , 剔除輸入中的非中文字符——解決復(fù)制粘貼進來的非數(shù)字function filterChar(input){

input.value= input.value.replace(/ [^0-9] /g, ' ' ) ;

}



18.瀏覽器輸入url后經(jīng)歷的過程

一般會經(jīng)歷以下幾個過程:

1、首先,在瀏覽器地址欄中輸入url

2、瀏覽器先查看瀏覽器緩存-系統(tǒng)緩存-路由器緩存,如果緩存中有,會直接在屏幕中顯示頁面內(nèi)容。若沒有,則跳到第三步操作。

3、在發(fā)送http請求前,需要域名解析(DNS解析),解析獲取相應(yīng)的IP地址。

4、瀏覽器向服務(wù)器發(fā)起tcp連接,與瀏覽器建立tcp三次握手。

5、握手成功后,瀏覽器向服務(wù)器發(fā)送http請求,請求數(shù)據(jù)包

6、服務(wù)器處理收到的請求,將數(shù)據(jù)返回至瀏覽器,四次揮手。https://m.sohu.com/a/221520733_465908

7、瀏覽器收到HTTP響應(yīng)

8、讀取頁面內(nèi)容,瀏覽器渲染,解析html源碼

9、生成Dom樹、解析css樣式、js交互

10、客戶端和服務(wù)器交互

11、ajax查詢

其中,步驟2的具體過程是:

瀏覽器緩存:瀏覽器會記錄DNS一段時間,因此,只是第一個地方解析DNS請求;

操作系統(tǒng)緩存:如果在瀏覽器緩存中不包含這個記錄,則會使系統(tǒng)調(diào)用操作系統(tǒng),獲取操作系統(tǒng)的記錄(保存最近的DNS查詢緩存);

路由器緩存:如果上述兩個步驟均不能成功獲取DNS記錄,繼續(xù)搜索路由器緩存;

ISP緩存:若上述均失敗,繼續(xù)向ISP搜索。


19.如何最小化重繪(repaint)和回流(reflow)?

需要對元素進行復(fù)雜重繪時,可以先隱藏(display:"none"),操作完成后再顯示.

需要創(chuàng)建多個DOM節(jié)點時,使用DocumentFragment創(chuàng)建完之后一次性的加入documnet

緩存Layout屬性值,如:var left =elem.offsetLeft;這樣,多次使用left產(chǎn)生一次回流

盡量避免用table布局(table元素一旦觸發(fā)回流就會導致table里所有的其他元素回流)

避免使用css表達式(expression),因為每次調(diào)用都會重新計算值(包括加載頁面)

盡量使用css屬性簡寫,如:用border代替border-width,border-style,border-color

批量修改元素樣式:element.style.xxx

重繪: 當頁面中元素樣式的改變并不影響它在文檔流中的位置時,也就是說布局沒有發(fā)生改變時(比如只是改變元素的顏色)。

回流:當渲染樹(Render Tree)中的部分(或全部)元素的尺寸、結(jié)構(gòu)、顯示隱藏等發(fā)生改變時,瀏覽器重新渲染的過程稱為回流。 簡而言之,任何會改變元素幾何信息(元素的位置和尺寸大小)的操作,都會觸發(fā)回流。 回流是影響瀏覽器性能的關(guān)鍵 因素。

比如:

(1)添加或者刪除可見的 DOM 元素(不可見元素不會觸發(fā)回流);

(2)元素尺寸或位置發(fā)生改變

(3)元素內(nèi)容變化,比如文字數(shù)量或圖片大小

(4)瀏覽器窗口大小發(fā)生改變

(5)CSS偽類的激活(例如::hover,從而改變了元素的布局的)

注意

回流必定會發(fā)生重繪,重繪不一定會引發(fā)回流。

回流比重繪的代價要更高。有時即使僅僅回流一個單一的元素,它的父元素以及任何跟它相關(guān)的元素也會產(chǎn)生回流,牽一發(fā)動全身。

如何避免(減少)回流

css避免設(shè)置多層內(nèi)聯(lián)樣式。

如果需要設(shè)置動畫效果,最好將元素脫離正常的文檔流。

避免使用CSS表達式(例如:calc())。避免頻繁操作樣式,最好將樣式列表定義為class并一次性更改class屬性。

避免頻繁操作DOM,創(chuàng)建一個documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中。

可以先為元素設(shè)置為不可見:display: none,操作結(jié)束后再把它顯示出來。


20.Sass、LESS

LESS的安裝和Sass安裝有所不同,他不需要依賴于Ruby環(huán)境,就能直接安裝使用。不過LESS安裝分為兩種:客戶端和服務(wù)器端安裝

LESS樣式中聲明變量和調(diào)用變量和Sass一樣,唯一的區(qū)別就是變量名前面使用的是“@”字符。LESS是CSS的一種擴展形式,它并沒有閹割CSS的功能,而是在現(xiàn)有的CSS語法上,添加了很多額外的功能。

Sass聲明變量必須是“$”開頭,后面緊跟變量名和變量值,而且變量名和變量值需要使用冒號(:)分隔開。就像CSS屬性設(shè)置一樣,Sass也同時支持老的語法,老的語法和常規(guī)的CSS語法略有不同,他需要嚴格的語法,任何的縮進和字符的錯誤都會造成樣式的編譯錯誤。Sass可以省略大括號({})和分號(;),完全依靠嚴格的縮進和格式化代碼


21.移動端你們一般采用什么布局?移動端設(shè)計稿是多大的尺寸?

定寬布局

一般移動端設(shè)計稿是640或者750的尺寸


22.em和rem的區(qū)別

em相對父級元素設(shè)置的font-size來設(shè)置大小 如果父元素沒有設(shè)置font-size ,則繼續(xù)向上查找,直至有設(shè)置font-size元素

rem直接參照html標簽字體大小,并且所有使用rem單位的都是參照html標簽,windowWidth/37.5


23.移動端click 300毫秒延遲原因?

移動端瀏覽器會有一些默認的行為,比如雙擊縮放、雙擊滾動。這些行為,尤其是雙擊縮放,主要是為桌面網(wǎng)站在移動端的瀏覽體驗設(shè)計的。而在用戶對頁面進行操作的時候,移動端瀏覽器會優(yōu)先判斷用戶是否要觸發(fā)默認的行為。


24.固定定位布局 鍵盤擋住輸入框內(nèi)容?

// css

? ? .mainBox{

? ? ? ? height:100vh;

? ? ? ? position:relative;

}

? ? .inputBox{

? ? ? ? position:absolute;

? ? ? ? bottom:0;

}

// 輸入框獲得焦點事件

? ? ? onFocus() {

? ? ? ? setTimeout(function(){

? ? ? ? ? // 設(shè)置body的高度為可視高度+302

? ? ? ? ? // 302為原生鍵盤的高度

? ? ? ? ? document.getElementsByTagName('body')[0].style.height= (window.innerHeight+ 302) + 'px';

? ? ? ? ? document.body.scrollTop= 302;

? ? ? ? }, 300)

}

// 輸入框失去焦點事件

? ? ? onBlur() {

? ? ? ? // 設(shè)置body恢復(fù)原來的高度

? ? ? ? document.getElementsByTagName('body')[0].style.height= window.innerHeight+ 'px';

}

低版本ios不支持fixed,為了兼容(IScroll.js可以支持fixed)

var u = navigator.userAgent, app = navigator.appVersion;

varisiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);//ios終端

if(isiOS) {

$('textarea').focus(function() {

window.setTimeout('scrollBottom()',500);

? ? });

}

functionscrollBottom() {

window.scrollTo(0, $('body').height());

}

或者直接調(diào)用input時

document.body.scrollTop = document.body.scrollHeight;

https://www.cnblogs.com/guolao/p/11936709.html


25.移動端兼容問題?

scroll元素滑動,ios滑動比較生澀

? ? 解決辦法:給父類設(shè)置-webkit-overflow-scrolling:touch

iphone及ipad下輸入框默認內(nèi)陰影

? ? 解決辦法: 設(shè)置樣式 -webkit-appearance:none;

IOS 在點擊div的時候會出現(xiàn)黑灰色背景塊

? ? -webkit-text-size-adjust: 100%;

? ? -webkit-tap-highlight-color: rgba(0, 0, 0, 0);

ios 長按出現(xiàn)拷貝、復(fù)制等菜單選項

? ? -webkit-touch-callout: none;

/*系統(tǒng)默認菜單被禁用*/

? ? -webkit-user-select: none;

/*webkit瀏覽器*/

? ? -khtml-user-select: none;

/*早期瀏覽器*/

? ? -moz-user-select: none;

/*火狐*/

? ? -ms-user-select: none;

/*IE10*/

? ? user-select: none;

背景圖片設(shè)置,rentina屏幕下圖片模糊

? ? 解決辦法:使用2倍圖或者background-size設(shè)為二分之一

ios系統(tǒng)中元素被觸摸時產(chǎn)生的半透明灰色遮罩

? ? 解決辦法:設(shè)置樣式 -webkit-tap-highlight-color:rgba(255,255,255,0)

css width\height百分比值

? ? 百分比在低端機型上會有不同的表現(xiàn),具體情況具體分析。(低版本的oppo和華為手機上面出現(xiàn)過)

? ? 解決辦法:建議盡量不使用百分比,可以使用rem去實現(xiàn)。

? ? 使用css3控制背景圖的切換

在手機上面效果卡頓,且切換會有問題

? ? 解決辦法:使用css合并切換圖層,使用css中的幀動畫通過控制background-position來顯示圖片位置,這種寫法手機上面兼容性較好

使用animation同時使用transform和rotate:

在手機上面效果被覆蓋并且效果出問題

? ? 解決辦法:transform3d增加一個z坐標數(shù)值

使用css中的scale影響圖片變的模糊不清楚

? ? 原因:scale導致了頁面的重排和重繪

? ? 解決辦法:給css中加上translageZ(0)

ios機型使用圓角的overflow:hidden,會導致圓角遮罩不生效

? ? 解決辦法:

? ? overflow: hidden;

? ? border-radius: 30px;

? ? transform: rotate(0deg);

輸入框在android版本小于10的手機中會有默認白色背景和邊框,導致樣式錯亂.

? ? background-color: transparent;

? ? FILTER: alpha(opacity=0);//安卓兼容

h5 圖片長按保存禁用

? ? //慎用,因為設(shè)置次屬性可能導致頁面不能滾動,根據(jù)自己實際情況來采取即可

? ? 解決辦法:img{

? ? ? pointer-events:none;/* 禁止長按圖片保存 */

? ? }

禁止長按鏈接與圖片彈出菜單

? ? 解決辦法:a,img{ -webkit-touch-callout: none}


<meta name="App-Config" content="fullscreen=yes,useHistoryState=yes,transition=yes"/>

<meta content=yes name=apple-mobile-web-app-capable/>

<meta content=yes name=apple-touch-fullscreen/>

<meta content="telephone=no,email=no" name=format-detection/>

<meta name="viewport"? content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no//禁用縮放,viewport-fit=cover"http://iphonex適配>


iPhone上的Safari(還有些webkit android手機瀏覽器)會自動對看起來像是電話號碼的數(shù)字串(包括已經(jīng)加入連字符或括號格式化過的)添加電話鏈接,點擊之后會詢問用戶是否想要撥打該號碼。如果你不希望開啟這個自動識別,可以將它關(guān)閉:

<meta name="format-detection" content="telephone=no" />

如果你關(guān)閉自動識別后,又希望某些電話號碼能夠鏈接到iPhone的撥號功能,那么可以通過這樣來聲明電話鏈接:

<a href="tel:13800138000">13800138000</a>

<meta content="email=no" name="format-detection" />//安卓將不識別郵箱


26.消除transition閃屏

.css {

? ? -webkit-transform-style: preserve-3d;

? ? -webkit-backface-visibility: hidden;

? ? -webkit-perspective: 1000;

}

開啟硬件加速

解決頁面閃白

保證動畫流暢

.css {

-webkit-transform: translate3d(0, 0, 0);

-moz-transform: translate3d(0, 0, 0);

-ms-transform: translate3d(0, 0, 0);

transform: translate3d(0, 0, 0);

}

設(shè)計高性能CSS3動畫的幾個要素

盡可能地使用合成屬性transform和opacity來設(shè)計CSS3動畫,

不使用position的left和top來定位

利用translate3D開啟GPU加速


27.手機拍照和上傳圖片

/**IOS有拍照、錄像、選取本地圖片功能,*部分Android只有選擇本地圖片功能。*Winphone不支持*/

<input type="file" accept="images/*" />

28.頁面切換動畫?

react-addons-css-transition-group

29.移動端如何清除輸入框內(nèi)陰影

在iOS上,輸入框默認有內(nèi)部陰影,但無法使用box-shadow來清除,如果不需要陰影,可以這樣關(guān)閉:

input,

textarea {

border: 0;

-webkit-appearance: none;

}

30.屏幕旋轉(zhuǎn)的事件和樣式

<!-- uc強制豎屏 --><meta name="screen-orientation" content="portrait">?

<!-- QQ強制豎屏 --> <meta name="x5-orientation" content="portrait">

window.orientation,取值:正負90表示橫屏模式、0和180表現(xiàn)為豎屏模式;

window.onorientationchange = function(){

switch(window.orientation){

case -90:

case 90:

alert("橫屏:" + window.orientation);

case 0:

case 180:

alert("豎屏:" + window.orientation);

break;

}

}

樣式

//豎屏時使用的樣式

@media all and (orientation:portrait) {

.css{}

}

//橫屏時使用的樣式

@media all and (orientation:landscape) {

.css{}

}

webview難以強制控制豎屏

31.audio元素和video元素在ios和andriod中無法自動播放

應(yīng)對方案:觸屏即播

$('html').one('touchstart',function(){

audio.play()

})

32.搖一搖功能

HTML5 deviceMotion:封裝了運動傳感器數(shù)據(jù)的事件,可以獲取手機運動狀態(tài)下的運動加速度等數(shù)據(jù)。

33. web識別移動端的設(shè)備

var userAgentInfo = navigator.userAgent;

var Agents = new Array("Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod");

或者

? ? ? const ua = window.navigator.userAgent.toLocaleLowerCase();

? ? ? const isIOS = /iphone|ipad|ipod/.test(ua);

? ? ? const isAndroid = /android/.test(ua);

? ? ? const isMiuiBrowser = /miuibrowser/.test(ua);

34.web后臺鎖屏息屏監(jiān)聽

window.resize

visibilitychange可以監(jiān)聽手機鎖屏和瀏覽器切換到后臺的動作。fidder抓包debugger

35.如何解決盒子邊框溢出

-webkit-box-sizing:border-box;

當你指定了一個塊級元素時,并且為其定義了邊框,設(shè)置了其寬度為100%。在移動設(shè)備開發(fā)過程中我們通常會對文本框定義為寬度100%,將其定義為塊級元 素以實現(xiàn)全屏自適應(yīng)的樣式,但此時你會發(fā)現(xiàn),該元素的邊框(左右)各1個像素會溢了文檔,導致出現(xiàn)橫向滾動條,為解決這一問題,我們可以為其添加一個特殊 的樣式-webkit-box-sizing:border-box;用來指定該盒子的大小包括邊框的寬度。

36.websocket

websocket是HTML5的一個新協(xié)議,它允許服務(wù)端向客戶端傳遞信息,實現(xiàn)瀏覽器和客戶端雙工通信。websocket彌補了HTTP不支持長連接的特點。

websocket+echarts可能產(chǎn)生內(nèi)存泄漏問題,可以通過clear()在更新內(nèi)容鎖定縮放,定位位置,離開組件時dispose()解決

var ws;

/**

* 連接 websocket

* @param func onopen要執(zhí)行的函數(shù),可以為空

*/

function ws_connect(func) {

? ? ws = new WebSocket("ws://" + ws_ip);

? ? // 服務(wù)端主動推送消息時會觸發(fā)這里的 onmessage

? ? ws.onmessage = function (e) {

? ? ? ? console.log('ws_onmessage ');

? ? };

? ? ws.onopen = function (e) {

? ? ? ? console.log('ws_onopen');

? ? ? ? // 開啟心跳

? ? ? ? ws_heart();

? ? ? ? if (typeof func == 'function') {

? ? ? ? ? ? func();

? ? ? ? }

? ? };

? ? ws.onerror = function (e) {

? ? ? ? console.error("ws_onerror:", e);

? ? };

? ? ws.onclose = function (e) {

? ? ? ? console.log('ws_onclose:code:' + e.code + ';reason:' + e.reason + ';wasClean:' + e.wasClean);

? ? };

}

$(function () {

? ? var func = function () {

? ? ? ? var data = {type: 'login'};

? ? ? ? ws.send(JSON.stringify(data));

? ? };

// 頁面加載時第一次連接,也可以傳空

? ? ws_connect(func);

});

————————————————

斷線重連

重新連接的時候 Websocket 的屬性 readyState 有著至關(guān)重要的作用,先了解一下這個屬性的含義(以下其中之一):

0 (CONNECTING)

正在鏈接中

1 (OPEN)

已經(jīng)鏈接并且可以通訊

2 (CLOSING)

連接正在關(guān)閉

3 (CLOSED)

連接已關(guān)閉或者沒有鏈接成功

除了第一次連接,每一次連接時都必須考慮當前的連接狀態(tài),比如我要執(zhí)行 ws.send(data); ,在四種狀態(tài)下的執(zhí)行時機是不同的,如下:

0 (CONNECTING)

正在鏈接中 - 等連接成功后,在 ws.onopen 里執(zhí)行

1 (OPEN)

已經(jīng)鏈接并且可以通訊 - 直接執(zhí)行就是了

2 (CLOSING)

連接正在關(guān)閉 - 等關(guān)閉完成后,在 ws.onclose 里重新連接,在重連成功的 ws.onopen 里執(zhí)行

3 (CLOSED)

連接已關(guān)閉或者沒有鏈接成功 - 重新連接,在重連成功的 ws.onopen 里執(zhí)行

這樣每次發(fā)送數(shù)據(jù)都能保證連接成功(除非網(wǎng)絡(luò)斷了或服務(wù)器掛了),寫一個函數(shù) ws_execute() 封裝這些操作,這個函數(shù)如下:

/**

* 根據(jù)連接狀態(tài)單線程連接 websocket

* @param func onopen要執(zhí)行的函數(shù),可以為空

*/

function ws_execute(func) {

? ? console.log('ws_execute:readyState:' + ws.readyState);

? ? if (ws.readyState == 0) {

? ? ? ? // 正在鏈接中

? ? ? ? var _old$open = ws.onopen;

? ? ? ? ws.onopen = function (e) {

? ? ? ? // 原本 onopen 里的代碼先執(zhí)行完畢

? ? ? ? ? ? _old$open.apply(this, arguments);

? ? ? ? ? ? if (typeof func == 'function') {

? ? ? ? ? ? ? ? func();

? ? ? ? ? ? }

? ? ? ? };

? ? } else if (ws.readyState == 1) {

? ? ? ? // 已經(jīng)鏈接并且可以通訊

? ? ? ? if (typeof func == 'function') {

? ? ? ? ? ? func();

? ? ? ? }

? ? } else if (ws.readyState == 2) {

? ? ? ? // 連接正在關(guān)閉

? ? ? ? var _old$close = ws.onclose;

? ? ? ? ws.onclose = function (e) {

? ? ? ? // 原本 onclose 里的代碼先執(zhí)行完畢

? ? ? ? ? ? _old$close.apply(this, arguments);

? ? ? ? ? ? ws_connect(func);

? ? ? ? };

? ? } else if (ws.readyState == 3) {

? ? ? ? // 連接已關(guān)閉或者沒有鏈接成功

? ? ? ? ws_connect(func);

? ? }

}

————————————————

業(yè)務(wù)邏輯里發(fā)送數(shù)據(jù)是這樣的(代碼片斷):

// 發(fā)送數(shù)據(jù)時,將代碼構(gòu)造成函數(shù)作為參數(shù),等 onopen 時執(zhí)行

var func = function () {

? ? var data = {type: 'audio'};

? ? ws.send(JSON.stringify(data));

};

ws_execute(func);

————————————————

心跳

有了上面的 ws_execute() 函數(shù),心跳就簡單了,比如每1分鐘向服務(wù)器發(fā)送一次數(shù)據(jù):

var ws_heart_i = null;

/**

* websocket 每1分鐘發(fā)一次心跳

*/

function ws_heart() {

? ? if (ws_heart_i) clearInterval(ws_heart_i);

? ? ws_heart_i = setInterval(function () {

? ? ? ? console.log('ws_heart');

? ? ? ? var func = function () {

? ? ? ? ? ? var data = {type: 'ping'};

? ? ? ? ? ? ws.send(JSON.stringify(data));

? ? ? ? };

? ? ? ? ws_execute(func);

? ? }, 60000);

}

————————————————

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

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

  • 0.鏈接 狀態(tài)碼精選 https://www.cnblogs.com/yaya-003/p/12653602.ht...
    蛋撻xjc閱讀 615評論 0 0
  • 0 HTML5相關(guān) websocket WebSocket 使用ws或wss協(xié)議,Websocket是一個持久化的...
    可愛多小姐閱讀 1,018評論 0 0
  • JavaScript 作用域和作用域 執(zhí)行上下文 范圍: 一段 或一個函數(shù) 全局: 變量定義,函數(shù)聲明 一段 函數(shù)...
    羅恬閱讀 411評論 0 0
  • 一、CSS問題 1.flex布局 display:flex; 在父元素設(shè)置,子元素受彈性盒影響,默認排成一行,如果...
    陳二狗想吃肉閱讀 807評論 0 9
  • 為什么學習Python? 通過什么途徑學習的Python? 上網(wǎng)收集視頻,資料 關(guān)注公證號 買教程,書籍 Pyth...
    130920閱讀 1,419評論 0 0

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