web前端面经
注冊登錄是怎么實現的
1.登陸注冊要做成受控組件,組件定義state,和表單綁定2.redux-saga調用數據請求,發送action修改數據,useEffect中dispatch發送數據請求,后端比對用戶名是否重復,返回state3.前端根據返回的信息成功跳轉登陸頁4.登陸發送數據請求,數據庫對比用戶名密碼是否正確, 根據后端返回的結果進入首頁5.setCookie將用戶登錄名密碼token存cookie中 通過JWT(Json web token)6.免密登陸 getCookie獲取token 發給后端對比 根據返回結果是否自動登陸7.注冊通過Ant Design ,validator中進行表單正則的驗證8.用戶體驗 注冊的時候跳轉其他頁面的時候給用戶提示是否需要跳轉,避免因為跳轉后導致注冊信息沒有了 用組件內后置守衛做如果輸入框都沒有填信息,不攔截跳轉如果用戶輸入信息,彈窗提示,點確定,跳轉,點取消,不跳轉項目中遇到什么困難,怎么解決的?
1.react中配置二級路由 地址變化 但是界面不更新 使用dva/router中的withRouter高階組件解決的2.圖表聯動怎么實現我們只需要把當前被選中圖表的事件,直接發給其他圖表即可,然后判斷被選中的圖表是哪個作為區分onTouchEvent(event)普通事件傳遞3.產品經理要求智能匹配產品 找網上類似功能的網站 查看源碼 和主管討論需要一個設計一個投資習慣和風險承受能力測試,從后端獲取這個客戶測試的結果 以及客戶平常投資的習慣 生成不同的關鍵字根據關鍵字從數據庫中匹配產品 展示界面4.后臺管理系統遇到遇到什么奇葩的需求后臺管理系統和普通App面向用戶的區別
toB和toC的項目面向企業內部和面向用戶的項目的區別后臺管理系統權限比較細 App高并發比較多 做性能優化正則表達式
\d 匹配數字 \D 匹配非數字 \w 匹配數字字母下劃線 \W 匹配非數字字母下劃線 \n 匹配一個換行符 \s 匹配任何不可見字符包括空格、制表符、換頁符等等 \S 匹配任何可見字符 ^ 匹配輸入字行首 $匹配輸入行尾 *(0到多次)匹配前面的子表達式任意次 +(1到多) 匹配前面的子表達式一次或多次(大于等于1次) ?(0或1)匹配前面的子表達式零次或一次 {n}n是一個非負整數,匹配確定的n次 {n,}n是一個非負整數。至少匹配n次Ajax
我對 ajax 的理解是,它是一種異步通信的方法,通過直接由 js 腳本向服務器發起 http 通信,然后根據服務器返回的數據,更新網頁的相應部分,而不用刷新整個頁面的一種方法。 創建步驟:創建xhr對象->配置Ajax請求地址通過open方法->發送請求通過send方法->監聽請求,接收響應 //1:創建Ajax對象 var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本 //2:配置 Ajax請求地址 xhr.open('get','index.xml',true); //3:發送請求 xhr.send(null); // 嚴謹寫法 //4:監聽請求,接受響應 xhr.onreadysatechange=function(){if(xhr.readySate==4&&xhr.status==200 || xhr.status==304)console.log(xhr.responseXML) }js 延遲加載的方式
js 的加載、解析和執行會阻塞頁面的渲染過程,因此我們希望 js 腳本能夠盡可能的延遲加載,提高頁面的渲染速度。 我了解到的幾種方式是:1、將 js 腳本放在文檔的底部,來使 js 腳本盡可能的在最后來加載執行。 2、給 js 腳本添加 defer 屬性,這個屬性會讓腳本的加載與文檔的解析同步解析,然后在文檔解析完成后再執行這個腳本文件,這樣的話就能使頁面的渲染不被阻塞。多個設置了 defer 屬性的腳本按規范來說最后是順序執行的,但是在一些瀏覽器中可能不是這樣。 3、給 js 腳本添加 async屬性,這個屬性會使腳本異步加載,不會阻塞頁面的解析過程,但是當腳本加載完成后立即執行 js腳本,這個時候如果文檔沒有解析完成的話同樣會阻塞。多個 async 屬性的腳本的執行順序是不可預測的,一般不會按照代碼的順序依次執行。 4、動態創建 DOM 標簽的方式,我們可以對文檔的加載事件進行監聽,當文檔加載完成后再動態的創建 script 標簽來引入 js 腳本。模塊化開發的理解
我對模塊的理解是,一個模塊是實現一個特定功能的一組方法。在最開始的時候,js 只實現一些簡單的功能, 所以并沒有模塊的概念,但隨著程序越來越復雜,代碼的模塊化開發變得越來越重要。由于函數具有獨立作用域的特點,最原始的寫法是使用函數來作為模塊,幾個函數作為一個模塊, 但是這種方式容易造成全局變量的污染,并且模塊間沒有聯系。后面提出了對象寫法,通過將函數作為一個對象的方法來實現,這樣解決了直接使用函數作為模塊的一些缺點, 但是這種辦法會暴露所有的所有的模塊成員,外部代碼可以修改內部屬性的值。現在最常用的是立即執行函數的寫法,通過利用閉包來實現模塊私有作用域的建立,同時不會對全局作用域造成污染。js 的幾種模塊規范
js 中現在比較成熟的有四種模塊加載方案:第一種是 CommonJS 方案,它通過 require 來引入模塊,通過 module.exports 定義模塊的輸出接口。這種模塊加載方案是服務器端的解決方案,它是以同步的方式來引入模塊的,因為在服務端文件都存儲在本地磁盤,所以讀取非常快,所以以同步的方式加載沒有問題。但如果是在瀏覽器端,由于模塊的加載是使用網絡請求,因此使用異步加載的方式更加合適。第二種是 AMD 方案,這種方案采用異步加載的方式來加載模塊,模塊的加載不影響后面語句的執行,所有依賴這個模塊的語句都定義在一個回調函數里,等到加載完成后再執行回調函數。require.js 實現了 AMD 規范。第三種是 CMD 方案,這種方案和 AMD 方案都是為了解決異步模塊加載的問題,sea.js 實現了 CMD 規范。它和require.js的區別在于模塊定義時對依賴的處理不同和對依賴模塊的執行時機的處理不同。第四種方案是 ES6 提出的方案,使用 import 和 export 的形式來導入導出模塊。AMD和CMD規范的區別?
它們之間的主要區別有兩個方面。 第一個方面是在模塊定義時對依賴的處理不同。AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊。而 CMD 推崇就近依賴,只有在用到某個模塊的時候再去 require。 第二個方面是對依賴模塊的執行時機處理不同。首先 AMD 和 CMD 對于模塊的加載方式都是異步加載,不過它們的區別在于模塊的執行時機,AMD 在依賴模塊加載完成后就直接執行依賴模塊,依賴模塊的執行順序和我們書寫的順序不一定一致。而 CMD在依賴模塊加載完成后并不執行,只是下載而已,等到所有的依賴模塊都加載好后,進入回調函數邏輯,遇到 require 語句 的時候才執行對應的模塊,這樣模塊的執行順序就和我們書寫的順序保持一致了。ES6模塊與CommonJS 模塊、AMD、CMD的差異
1.CommonJS 模塊輸出的是一個值的拷貝, ES6 模塊輸出的是值的引用。 CommonJS 模塊輸出的是值的,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。 ES6 模塊的運行機制與 CommonJS 不一樣。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令 import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊里面去取值。 2.CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。CommonJS 模塊就是對象,即在輸入時是先加載整個模塊,生成一個對象,然后再從這個對象上面讀取方法,這種加載稱為“運行時加載”。 而 ES6 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。requireJS的核心原理
require.js 的核心原理是通過動態創建 script 腳本來異步引入模塊,然后對每個腳本的 load 事件進行監聽,如果每個腳本都加載完成了,再調用回調函數js的原理(運行機制)
首先js是單線程運行的,在代碼執行的時候,通過將不同函數的執行上下文壓入執行棧中來保證代碼的有序執行。 在執行同步代碼的時候,如果遇到了異步事件,js引擎并不會一直等待其返回結果,而是會將這個事件掛起,繼續執行執行棧中的其他任務所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。 同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務; 異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有等主線程任務執行完畢,"任務隊列"開始通知主線程,請求執行任務,該任務才會進入主線程執行。當同步事件執行完畢后,再將異步事件對應的回調加入到與當前執行棧中不同的另一個任務隊列中等待執行。 任務隊列可以分為宏任務對列和微任務對列,當當前執行棧中的事件執行完畢后,js 引擎首先會判斷微任務對列中是否有任務可以執行,如果有就將微任務隊首的事件壓入棧中執行。 當微任務對列中的任務都執行完成后再去判斷宏任務對列中的任務。異步運行機制如下: (1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。 (2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。 (3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。 (4)主線程不斷重復上面的第三步。arguments 的對象
arguments對象是函數中傳遞的參數值的集合。它是一個類似數組的對象,因為它有一個length屬性, 我們可以使用數組索引表示法arguments[1]來訪問單個值,但它沒有數組中的內置方法, 如:forEach、reduce、filter和map。我們可以使用Array.prototype.slice將arguments對象轉換成一個數組。Array.prototype.slice.call(arguments)V8 引擎的垃圾回收機制
v8的垃圾回收機制基于分代回收機制,這個機制又基于世代假說,這個假說有兩個特點,一是新生的對象容易早死,另一個是不死的對象會活得更久。基于這個假說,v8 引擎將內存分為了新生代和老生代。 新創建的對象或者只經歷過一次的垃圾回收的對象被稱為新生代。經歷過多次垃圾回收的對象被稱為老生代。 新生代被分為 From 和 To 兩個空間,To 一般是閑置的。當 From 空間滿了的時候會執行 Scavenge(斯蓋V橘) 算法進行垃圾回收。當我們執行垃圾回收算法的時候應用邏輯將會停止,等垃圾回收結束后再繼續執行。這個算法分為三步: (1)首先檢查 From 空間的存活對象,如果對象存活則判斷對象是否滿足晉升到老生代的條件,如果滿足條件則晉升到老生代。如果不滿足條件則移動 To 空間。 (2)如果對象不存活,則釋放對象的空間。 (3)最后將 From 空間和 To 空間角色進行交換。 新生代對象晉升到老生代有兩個條件: (1)第一個是判斷是對象否已經經過一次 Scavenge 回收。若經歷過,則將對象從 From 空間復制到老生代中;若沒有經歷,則復制到 To 空間。 (2)第二個是 To 空間的內存使用占比是否超過限制。當對象從 From 空間復制到 To 空間時,若 To 空間使用超過 25%,則對象直接晉升到老生代中。設置 25% 的原因主要是因為算法結束后,兩個空間結束后會交換位置,如果 To 空間的內存太小,會影響后續的內存分配。老生代采用了標記清除法和標記壓縮法。 標記清除法首先會對內存中存活的對象進行標記,標記結束后清除掉那些沒有標記的對象。由于標記清除后會造成很多的內存碎片,不便于后面的內存分配。所以了解決內存碎片的問題引入了標記壓縮法。 由于在進行垃圾回收的時候會暫停應用的邏輯,對于新生代方法由于內存小,每次停頓的時間不會太長,但對于老生代來說每次垃圾回收的時間長,停頓會造成很大的影響。 為了解決這個問題 V8 引入了增量標記的方法,將一次停頓進行的過程分為了多步,每次執行完一小步就讓運行邏輯執行一會,就這樣交替運行垃圾回收機制的兩種方法
現在各大瀏覽器通常用采用的垃圾回收有兩種方法:標記清除、引用計數。1、標記清除這是javascript中最常用的垃圾回收方式。當變量進入執行環境是,就標記這個變量為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變量所占用的內存,因為只要執行流進入相應的環境,就可能會用到他們。當變量離開環境時,則將其標記為“離開環境”。垃圾收集器在運行的時候會給存儲在內存中的所有變量都加上標記。然后,它會去掉環境中的變量以及被環境中的變量引用的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量,原因是環境中的變量已經無法訪問到這些變量了。最后。垃圾收集器完成內存清除工作,銷毀那些帶標記的值,并回收他們所占用的內存空間。2、引用計數另一種不太常見的垃圾回收策略是引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其所占的內存空間給收回來。這樣,垃圾收集器下次再運行時,它就會釋放那些引用次數為0的值所占的內存。會造成內存泄漏的操作
1.意外的全局變量 2.被遺忘的計時器或回調函數 3.脫離 DOM 的引用 4.閉包第一種情況是我們由于使用未聲明的變量,而意外的創建了一個全局變量,而使這個變量一直留在內存中無法被回收。 第二種情況是我們設置了setInterval定時器,而忘記取消它,如果循環函數有對外部變量的引用的話,那么這個變量會被一直留在內存中,而無法被回收。 第三種情況是我們獲取一個DOM元素的引用,而后面這個元素被刪除,由于我們一直保留了對這個元素的引用,所以它也無法被回收。 第四種情況是不合理的使用閉包,從而導致某些變量一直被留在內存當中。ECMAScript(ES)
ECMAScript 是編寫腳本語言的標準,ECMA(European Computer Manufacturers Association)規定一下他的標準,因為當時有java語言了,又想強調這個東西是讓ECMA這個人定的規則,所以就這樣一個神奇的東西誕生了,這個東西的名稱就叫做ECMAScript。 javaScript = ECMAScript + DOM + BOMES2015(ES6)新特性
塊作用域 類 箭頭函數 模板字符串 對象解構 Promise 模塊 Symbol 代理(proxy)Set 函數默認參數 rest 擴展運算符 數組和對象的擴展ES2016(ES7)新特性
求冪運算符(**)(因顆錄此) Array.prototype.includes()方法數組原型的方法,查找一個數值是否在數組中,只能判斷一些簡單類型的數據,對于復雜類型的數據無法判斷。該方法接受兩個參數,分別是查詢的數據和初始的查詢索引值。ES2017(ES8)新特性
async await函數參數列表結尾允許逗號es2017允許函數對象的定義調用時參數可以加入尾逗號,以及json對象array對象都允許Object.values()values: [obj],返回obj自身可枚舉屬性的屬性值的集合(安吹斯) Object.entries()entries:[obj], 與values類似,返回的一個2元素的數組Object.getOwnPropertyDescriptors()getOwnpropertyDescriptors: [obj],返回obj對象的屬性描述符(get 哦 潑破踢 迪斯虧不踢斯) String padding: padStart()和padEnd(),填充字符串達到當前長度在字符串首位開始添加string直到滿足length為止并返回新的字符串ShareArrayBuffer和Atomics對象,用于從共享內存位置讀取和寫入 (夏爾 啊銳 八法兒) (啊偷沒此)ES2018(ES9)新特性
異步迭代 Promise.finally()(飯的嘞) Rest/Spread 屬性 (銳斯特)(斯破銳的) 正則表達式命名捕獲組(Regular Expression Named Capture Groups) 正則表達式反向斷言(lookbehind) 正則表達式dotAll模式 正則表達式 Unicode 轉義 (右內扣的) 非轉義序列的模板字符串ES2019(ES10)新特性
行分隔符(U + 2028)和段分隔符(U + 2029)符號現在允許在字符串文字中,與JSON匹配 更加友好的JSON.stringify 新增了Array的flat()方法和flatMap()方法 新增了String的trimStart()方法和trimEnd()方法 Object.fromEntries() Symbol.prototype.description String.prototype.matchAll Function.prototype.toString()現在返回精確字符,包括空格和注釋 簡化try{} catch{},修改catch綁定 新的基本數據類型BigInt globalThis import() Legacy RegEx 私有的實例方法和訪問器ES2020(ES11)新特性
私有變量ES11在類中新增私有變量控制符#,在內部變量或者函數前添加一個hash符號#,可以將它們設置為私有屬性,只能在類的內部可以使用。 空值合并運算符空值合并操作符就是 ?? :如果左側的值為null或者undefined就返回左側的值,如果沒有就返回右側的值 可選鏈操作符可選鏈操作符 (?.) :如果左側表達式有值,就會繼續訪問右側的字段 BigInt使用BigInt的方式有兩種:1.在數字后面加n2.使用BigInt函數 動態導入globalThis提供一種標準化的方式去訪問全局對象,可以在任意上下文中獲取全局對象自身,并且不用擔心環境的問題 Promise.all缺陷與Promise.allSettledpromise.all可以并發執行異步任務,如果其中某個任務執行出現了異常,所有任務都會over,Promise會直接進入reject狀態使用Promise.allSettled,它會創建一個新的promise,在所有promise完成后返回一個包含每個promise結果的數組var,let和const的區別
1.var聲明的變量會掛載在window上,而let和const聲明的變量不會: 2.var聲明變量存在變量提升,let和const不存在變量提升 3.let和const聲明形成塊作用域 4.同一作用域下let和const不能聲明同名變量,而var可以const 一旦聲明必須賦值,不能使用null占位。聲明后不能再修改如果聲明的是復合類型數據,可以修改其屬性暫存死區 var a = 100; if(1){a = 10;//在當前塊作用域中存在a使用let/const聲明的情況下,給a賦值10時,只會在當前作用域找變量a,// 而這時,還未到聲明時候,所以控制臺Error:a is not definedlet a = 1; }var和let在for循環的一些不同表現
在var中執行的時候: 因為var是沒有塊級作用域的,所以在for循環中聲明的i會存在于test()函數作用域中。每一次for循環就會聲明一次i,但后面聲明的變量會覆蓋前面聲明的變量。 在let中執行的時候:因為塊級作用域的原因,let聲明的i都會存在于for塊級作用域中,每一次for循環都會生成一個塊級作用域。箭頭函數
箭頭函數表達式的語法比函數表達式更簡潔箭頭函數沒有自己的this值。箭頭函數里的this指向的是父級的this. 箭頭函數表達式更適用于那些本來需要匿名函數的地方,并且它不能用作構造函數。在箭頭函數版本中,當只有一個表達式或值需要返回,我們只需要()括號, 不需要 return 語句,箭頭函數就會有一個隱式的返回。如果我們在一個箭頭函數中有一個參數,則可以省略括號。箭頭函數不能訪問arguments對象。所以調用第一個getArgs函數會拋出一個錯誤。 相反,我們可以使用rest參數來獲得在箭頭函數中傳遞的所有參數。模板字符串
模板字符串是在 JS 中創建字符串的一種新方法。我們可以通過使用反引號使模板字符串化。在ES5版本中,我們需要添加\n以在字符串中添加新行。在模板字符串中,我們不需要這樣做。在 ES5 版本中,如果需要在字符串中添加表達式或值,則需要使用`+`運算符。 在模板字符串s中,我們可以使用${expr}嵌入一個表達式,這使其比 ES5 版本更整潔。對象解構
對象解構是從對象或數組中獲取或提取值的一種新的、更簡潔的方法 我們還可以為屬性取別名 let { firstName: fName, position } = employee; 當然如果屬性值為 undefined 時,我們還可以指定默認值 let { firstName = "Mark" } = employee;Set及應用場景
一、創建Set對象實例 Set 對象允許你存儲任何類型的唯一值,無論是原始值或者是對象引用 1.構造函數 (伊特波)語法:new Set([iterable])參數:iterable 如果傳遞一個可迭代對象,它的所有元素將被添加到新的Set中;如果不指定此參數或其值為null,則新的 Set為空二、Set實例屬性size屬性將會返回Set對象中元素的個數三、Set實例方法 1.add() 方法用來向一個 Set 對象的末尾添加一個指定的值語法:mySet.add(value)參數:value 必需,需要添加到 Set 對象的元素的值 2.delete() 方法可以從一個 Set 對象中刪除指定的元素語法:mySet.delete(value)參數:value 將要刪除的元素返回值:成功刪除返回 true,否則返回 false 3.clear() 方法用來清空一個 Set 對象中的所有元素語法:mySet.clear() 4.has() 方法返回一個布爾值來指示對應的值value是否存在Set對象中語法:mySet.has(value)參數:value 必須,是否存在于Set的值返回值:如果指定的值(value)存在于Set對象當中,返回true; 否則返回 false 5.entries() (安吹斯)語法:mySet.entries()返回值:一個新的包含 [value, value] 形式的數組迭代器對象,value 是給定集合中的每個元素,迭代器 對象元素的順序即集合對象中元素插入的順序 6.values()語法:mySet.values() 或者 mySet.keys()返回值:返回一個 Iterator(因特瑞特) 對象,這個對象以插入Set對象的順序包含了原 Set 對象里的每個元素 7.forEach()語法:mySet.forEach(callback[, thisArg]) (this傲歌)參數:callback 每個元素都會執行的函數thisArg 當執行callback函數時候,可以當作this來使用 5、什么是WeakSet()? 和Set結構類似,也是不重復的值的集合,但WeakSet的成員只能是對象(null 除外)。 而且 WeakMap 的鍵名所指向的對象,不計入垃圾回收機制。應用場景: 1、簡單數組去重 2、JSON數組去重JSON數組是比較常見的一種數據結構,形如[{…},…{…}]假如你需要統計某個屬性中不同的值。step1:先使用.map將JSON數組變成簡單數組,然后用set執行去重step2: 由于生成的Set屬于可迭代對象,所以可以使用數組解構符進行解構 3、二維數組去重我們可以將Set用作存儲每項的唯一值,結合reduce進行對比,得出無重復的項目。當然,上面的代碼缺點還是不少的。因為只是簡單地將其轉變成字符串作為對比的鍵,所以不能區分[1,2]、[‘1’ ,‘2’]、[‘1,2’]等子數組。 4、數組之間的對比Set的特性不單單可以可以用于單數組,對于數組之間的比較也是十分在行。什么是WeakSet()?和Set結構類似,也是不重復的值的集合,但WeakSet的成員只能是對象。WeakSet的API:add() //增delete() //刪has() //是否存在為什么WeakSet不可遍歷?因為WeakSet的成員都是弱引用,隨時可能消失,成員是不穩定的。WeakSet的用處:使用ws儲存DOM節點,就不用擔心節點從文檔移除時,會引發內存泄漏(即在被移除的節點上綁定的click等事件)。Proxy
Proxy 可以理解成,在目標對象之前架設一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,可以譯為“代理器”函數式編程
函數式編程(通常縮寫為FP)是通過編寫純函數,避免共享狀態、可變數據、副作用 來構建軟件的過程。數式編程是聲明式 的而不是命令式 的,應用程序的狀態是通過純函數流動的。與面向對象編程形成對比,面向對象中應用程序的狀態通常與對象中的方法共享和共處。 函數式編程是一種編程范式 ,這意味著它是一種基于一些基本的定義原則(如上所列)思考軟件構建的方式。當然,編程范式的其他示例也包括面向對象編程和過程編程。 函數式的代碼往往比命令式或面向對象的代碼更簡潔,更可預測,更容易測試高階函數
首先高階函數肯定是函數,不同的是輸入的參數和返回的值這兩項中的一項必須是函數才能叫高階函數。 這個問題在回答的時候可以稍微拓展一下,介紹一下常用的的高階函數, 比如:map、flatMap、filter、reduce、fold。為什么函數被稱為一等公民
在JavaScript中,函數不僅擁有一切傳統函數的使用方式(聲明和調用),而且可以做到像簡單值一樣:賦值(var func = function(){})、 傳參(function func(x,callback){callback();})、 返回(function(){return function(){}}),這樣的函數也稱之為第一級函數(First-class Function)。不僅如此,JavaScript中的函數還充當了類的構造函數的作用,同時又是一個Function類的實例(instance)(因斯疼斯)。這樣的多重身份讓JavaScript的函數變得非常重要。. new操作符的實現
1、創建一個空對象 {} 2、將構造函數中的this指向新創建的對象 (原型鏈)obj.__proto__ = Dog.prototype // 設置原型鏈 3、鏈接該對象到另一個對象 __proto__ 4、如果該函數沒有返回對象,則返回this回調函數?回調函數有什么缺點
回調函數是一個匿名函數,它作為一個參數傳遞給其他的代碼,其作用是在需要的時候方便調用這段(回調函數)代碼。可以讓異步代碼同步執行。 回調函數有一個致命的弱點,就是容易寫出回調地獄(Callback hell)instanceof的原理
instanceof 可以正確的判斷對象的類型,因為內部機制是通過判斷對象的原型鏈中是不是能找到類型的 prototype。 實現 instanceof:首先獲取類型的原型 然后獲得對象的原型 然后一直循環判斷對象的原型是否等于類型的原型,直到對象原型為 null,因為原型鏈最終為 nullfunction myInstanceof(left, right) {let prototype = right.prototypeleft = left.__proto__while (true) {if (left === null || left === undefined)return falseif (prototype === left)return trueleft = left.__proto__} }設計模式
設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 1、單例模式 2、工廠模式 3、觀察者模式 4、代理模式 5、策略模式 6、迭代器模式單例模式(Singleton Pattern)單例模式中Class的實例個數最多為1。當需要一個對象去貫穿整個系統執行某些任務時,單例模式就派上了用場。而除此之外的場景盡量避免單例模式的使用,因為單例模式會引入全局狀態,而一個健康的系統應該避免引入過多的全局狀態。工廠模式工廠模式定義一個用于創建對象的接口,這個接口由子類決定實例化哪一個類。該模式使一個類的實例化延遲到了子類。而子類可以重寫接口方法以便創建的時候指定自己的對象類型。 使用場景:如果你不想讓某個子系統與較大的那個對象之間形成強耦合,而是想運行時從許多子系統中進行挑選的話,那么工廠模式是一個理想的選擇 class Product {constructor(name) {this.name = name}init() {console.log('init')}} class Factory {create(name) {return new Product(name)} } // use let factory = new Factory() let p = factory.create('p1') p.init() https://juejin.im/post/6844904200917221389#heading-81js的基本數據類型、值是如何存儲的
JavaScript一共有8種數據類型 7種基本數據類型: Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示獨一無二的值)和BigInt(es10新增)1種引用數據類型 Object(Object本質上是由一組無序的名值對組成的)。 里面包含 function、Array、Date等。JavaScript不支持任何創建自定義類型的機制,而所有值最終都將是上述 8 種數據類型之一。 原始數據類型:直接存儲在棧(stack)中,占據空間小、大小固定,屬于被頻繁使用數據,所以放入棧中存儲。 引用數據類型:同時存儲在棧(stack)和堆(heap)中,占據空間大、大小不固定。引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址后從堆中獲得實體。&& 、||和!! 運算符
&& 叫邏輯與,在其操作數中找到第一個虛值表達式并返回它,如果沒有找到任何虛值表達式,則返回最后一個真值表達式。它采用短路來防止不必要的工作。 || 叫邏輯或,在其操作數中找到第一個真值表達式并返回它。這也使用了短路來防止不必要的工作。在支持 ES6 默認函數參數之前,它用于初始化函數中的默認參數值。 !! 運算符可以將右側的值強制轉換為布爾值,這也是將值轉換為布爾值的一種簡單方法js的數據類型的轉換
在 JS 中類型轉換只有三種情況,分別是:轉換為布爾值(調用Boolean()方法) 轉換為數字(調用Number()、parseInt()和parseFloat()方法) 轉換為字符串(調用.toString()或者String()方法)js 內置對象
js 中的內置對象主要指的是 在程序執行前存在全局作用域里的由 js定義的一些全局值屬性、函數和用來實例化其他對象的構造函數對象。 一般我們經常用到的如全局變量值 NaN、undefined, 全局函數如 parseInt()、parseFloat() 用來實例化對象的構造函數如 Date、Object 等, 還有提供數學計算的單體內置對象如 Math 對象。null 和 undefined 的區別
首先 Undefined 和 Null 都是基本數據類型,這兩個基本數據類型分別都只有一個值,就是 undefined 和 null。 undefined 代表的含義是未定義, null 代表的含義是空對象(其實不是真的對象,請看下面的注意!)。一般變量聲明了但還沒有定義的時候會返回 undefined,null 主要用于賦值給一些可能會返回對象的變量,作為初始化。 當我們對兩種類型使用 typeof 進行判斷的時候,Null 類型化會返回 “object”,這是一個歷史遺留的問題。當我們使用雙等 號對兩種類型的值進行比較時會返回 true,使用三個等號時會返回 false。{}和[]的valueOf和toString的結果
{} 的 valueOf 結果為 {} ,toString 的結果為 "[object Object]" [] 的 valueOf 結果為 [] ,toString 的結果為 ""js 的作用域和作用域鏈
作用域: 作用域是定義變量的區域,它有一套訪問變量的規則,這套規則來管理瀏覽器引擎如何在當前作用域以及嵌套的作用域中根據變量(標識符)進行變量查找。作用域鏈: 作用域鏈的作用是保證對執行環境有權訪問的所有變量和函數的有序訪問,通過作用域鏈,我們可以訪問到外層環境的變量和函數。作用域鏈的本質上是一個指向變量對象的指針列表。變量對象是一個包含了執行環境中所有變量和函數的對象。作用域鏈的前端始終都是當前執行上下文的變量對象。全局執行上下文的變量對象(也就是全局對象)始終是作用域鏈的最后一個對象。 當我們查找一個變量時,如果當前執行環境中沒有找到,我們可以沿著作用域鏈向后查找。js 創建對象的方式
我們一般使用字面量的形式直接創建對象,但是這種創建方式對于創建大量相似對象的時候,會產生大量的重復代碼。但 js和一般的面向對象的語言不同,在 ES6 之前它沒有類的概念。但是我們可以使用函數來進行模擬,從而產生出可復用的對象創建方式,我了解到的方式有這么幾種:(1)第一種是工廠模式,工廠模式的主要工作原理是用函數來封裝創建對象的細節,從而通過調用函數來達到復用的目的。但是它有一個很大的問題就是創建出來的對象無法和某個類型聯系起來,它只是簡單的封裝了復用代碼,而沒有建立起對象和類型間的關系。(2)第二種是構造函數模式。js 中每一個函數都可以作為構造函數,只要一個函數是通過 new 來調用的,那么我們就可以把它稱為構造函數。執行構造函數首先會創建一個對象,然后將對象的原型指向構造函數的 prototype 屬性,然后將執行上下文中的 this 指向這個對象,最后再執行整個函數,如果返回值不是對象,則返回新建的對象。因為 this 的值指向了新建的對象,因此我們可以使用 this 給對象賦值。構造函數模式相對于工廠模式的優點是,所創建的對象和構造函數建立起了聯系,因此我們可以通過原型來識別對象的類型。但是構造函數存在一個缺點就是,造成了不必要的函數對象的創建,因為在 js 中函數也是一個對象,因此如果對象屬性中如果包含函數的話,那么每次我們都會新建一個函數對象,浪費了不必要的內存空間,因為函數是所有的實例都可以通用的。(3)第三種模式是原型模式,因為每一個函數都有一個 prototype 屬性,這個屬性是一個對象,它包含了通過構造函數創建的所有實例都能共享的屬性和方法。因此我們可以使用原型對象來添加公用屬性和方法,從而實現代碼的復用。這種方式相對于構造函數模式來說,解決了函數對象的復用問題。但是這種模式也存在一些問題,一個是沒有辦法通過傳入參數來初始化值,另一個是如果存在一個引用類型如 Array 這樣的值,那么所有的實例將共享一個對象,一個實例對引用類型值的改變會影響所有的實例。(4)第四種模式是組合使用構造函數模式和原型模式,這是創建自定義類型的最常見方式。因為構造函數模式和原型模式分開使用都存在一些問題,因此我們可以組合使用這兩種模式,通過構造函數來初始化對象的屬性,通過原型對象來實現函數方法的復用。這種方法很好的解決了兩種模式單獨使用時的缺點,但是有一點不足的就是,因為使用了兩種不同的模式,所以對于代碼的封裝性不夠好。(5)第五種模式是動態原型模式,這一種模式將原型方法賦值的創建過程移動到了構造函數的內部,通過對屬性是否存在的判斷,可以實現僅在第一次調用函數時對原型對象賦值一次的效果。這一種方式很好地對上面的混合模式進行了封裝。(6)第六種模式是寄生構造函數模式,這一種模式和工廠模式的實現基本相同,我對這個模式的理解是,它主要是基于一個已有的類型,在實例化時對實例化的對象進行擴展。這樣既不用修改原來的構造函數,也達到了擴展對象的目的。它的一個缺點和工廠模式一樣,無法實現對象的識別。對this、call、apply和bind的理解
1、在瀏覽器里,在全局范圍內this 指向window對象; 2、在函數中,this永遠指向最后調用他的那個對象; 3、構造函數中,this指向new出來的那個新的對象; 4、call、apply、bind中的this被強綁定在指定的那個對象上; 5、箭頭函數中this比較特殊,箭頭函數this為父作用域的this,不是調用時的this.要知道前四種方式,都是調用時確定,也就是動態的,而箭頭函數的this指向是靜態的,聲明的時候就確定了下來; 6、apply、call、bind都是js給函數內置的一些API,調用他們可以為函數指定this的執行,同時也可以傳參。什么是 DOM 和 BOM
DOM指的是文檔對象模型,它指的是把文檔當做一個對象來對待,這個對象主要定義了處理網頁內容的方法和接口。 BOM指的是瀏覽器對象模型,它指的是把瀏覽器當做一個對象來對待,這個對象主要定義了與瀏覽器進行交互的法和接口。BOM的核心是 window,而 window 對象具有雙重角色,它既是通過 js 訪問瀏覽器窗口的一個接口, 又是一個 Global(全局)(歌樓波)對象。 這意味著在網頁中定義的任何對象,變量和函數,都作為全局對象的一個屬性或者方法存在。 window 對象含有 location 對象、navigator(那V給特)對象、screen(斯歌銳)對象等子對象, 并且 DOM 的最根本的對象 document 對象也是 BOM 的 window 對象的子對象。三種事件模型
事件 是用戶操作網頁時發生的交互動作或者網頁本身的一些操作,現代瀏覽器一共有三種事件模型。 DOM0級模型: 這種模型不會傳播,所以沒有事件流的概念,同元素 綁定多個事件,只會綁定最后一次的事件,前面的會被覆蓋。IE 事件模型:在該事件模型中,一次事件共有兩個過程,事件處理階段,和事件冒泡階段。事件處理階段會首先執行目標元素綁定的監聽事件。然后是事件冒泡階段,冒泡指的是事件從目標元素冒泡到 document,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行。這種模型通過 attachEvent 來添加監聽函數,可以添加多個監聽函數,會按順序依次執行。detachEvent刪除事件DOM2 級事件模型: 在該事件模型中,一次事件共有三個過程,第一個過程是事件捕獲階段事件處理階段,和事件冒泡階段。捕獲指的是事件從 document 一直向下傳播到目標元素,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行。。這種事件模型,事件綁定的函數是 addEventListener,其中第三個參數可以指定事件是否在捕獲階段執行。取消事件removeEventListener事件委托(代理)
本質上是利用了事件冒泡的機制。 并且父節點可以通過事件對象獲取到目標節點,因此可以把子節點的監聽函數定義在父節點上, 由父節點的監聽函數統一處理多個子元素的事件,這種方式稱為事件委托 支持為同一個DOM元素注冊多個同類型事件,可將事件分成事件捕獲和事件冒泡機制事件傳播
事件傳播有三個階段: 捕獲階段–事件從 window 開始,然后向下到每個元素,直到到達目標元素事件或event.target。 目標階段–事件已達到目標元素。 冒泡階段–事件從目標元素冒泡,然后上升到每個元素,直到到達 window。什么是事件捕獲 當事件發生在 DOM 元素上時,該事件并不完全發生在那個元素上。在捕獲階段,事件從window開始,一直到觸發事件的元素。 什么是事件冒泡? 事件冒泡剛好與事件捕獲相反,當前元素---->body ----> html---->document ---->window。當事件發生在DOM元素上時,該事件并不完全發生在那個元素上。在冒泡階段,事件冒泡,或者事件發生在它的父代,祖父母,祖父母的父代,直到到達window為止。DOM 操作
(1)創建新節點createDocumentFragment() //創建一個DOM片段 (科瑞A特)(法歌們特)createElement() //創建一個具體的元素createTextNode() //創建一個文本節點(2)添加、移除、替換、插入appendChild(node) removeChild(node)replaceChild(new,old) (銳普利斯)insertBefore(new,old) (因色特比佛)(3)獲取、查找getElementById();getElementsByName();getElementsByTagName();getElementsByClassName();querySelector(); (斯來科特)querySelectorAll();(4)屬性操作getAttribute(key); (去比又特)setAttribute(key, value);hasAttribute(key);removeAttribute(key);數據檢測類型判斷
檢測方法4種1、Object.prototype.toString.call()作用: 可以檢測所有數據類型所有數據類型都可以檢測,而且非常正確語法: Object.prototype.toString.call( 'xxx'/11/[ ] )返回值: [object Xxx], Xxx 就是對象的類型2、constructor作用: 可以檢測基本數據類型和引用數據類型弊端: 把類的原型進行重寫, 很有可能把之前的constructor覆蓋 檢測出來的結果就會不準確語法: ("xx")/([])/(function(){}).constructor === String/Array/Function 返回值: true/false 3、instanceOf原理: 判斷對象類型,基于原型鏈去判斷(obj instanceof Object)左邊對象的原型鏈proto上是否有右邊構造函數的proptotype屬性作用: 判斷左邊的對象是否是右邊構造函數的實例弊端: 用于引用類型的檢測, 對于基本數據類型不生效語法: " "/[ ]/true instanceOf String/Array/Boolean返回值: true/false 4、typeOf作用: 用于檢測基本數據類型和函數弊端: 引用數據類型(Arrary/function/object)只會返回Object, 不起作用語法: typeOf " "/[ ]/xx返回值: "string"/"boolean"/"object" (無法區分)原型/原型鏈
原型: Javascript規定,每一個函數都有一個prototype對象屬性,指向另一個對象 prototype就是調用構造函數所創建的那個實例對象的原型原型鏈: 實例對象與原型之間的連接,叫做原型鏈。 JS在創建對象的時候,都有一個叫做__proto__的內置屬性,用于指向創建它的函數對象的原型對象prototype。獲取原型的方法 p.proto p.constructor.prototype Object.getPrototypeOf(p)prototype、proto、constructor三者的關系
1、prototype: 每一個函數都有一個prototype這個屬性,而這個屬性指向一個對象,這個對象我們叫做原型對象 作用:節約內存擴展屬性和方法可以實現類之間的繼承 2、__proto__: 每一個對象都有一個__proto__屬性,__proto__指向創建自己的那個構造函數的原型對象對象可以直接訪問__proto__里面的屬性和方法 3、constructor: 指向創建自己的那個構造函數 ,是原型上的方法總結: 當我們創建一個構造函數的時候這個構造函數自帶了一個prototype屬性,而這個屬性指向一個對象,也就是原型對象。 這個原型對象里面有一個constructor構造器,它的作用是指向創建自己的構造函數。 除此之外 prototype還可以存放公共的屬性和方法。 當我們實例化一個對象的時候(被new調用的時候),這個對象自帶了一個 proto 屬性, 這個proto 指向創建自己的構造函數的原型對象。可以使用這個原型對象里面的屬性和方法constructor與class的區別
傳統的javascript中只有對象,沒有類的概念。它是基于原型的面向對象語言。 原型對象特點就是將自身的屬性共享給新對象。 ES6引入了Class(類)這個概念,通過class關鍵字可以定義類。 該關鍵字的出現使得其在對象寫法上更加清晰,更像是一種面向對象的語言constructor: constructor()方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。 一個類必須有constructor()方法,如果沒有顯式定義,一個空的 constructor()方法會被默認添加。構造函數與普通函數的區別
1. 返回值類型的區別:構造函數是沒有返回值類型的,普通函數是有返回值類型的,即使函數沒有返回值,返回值類型也要寫上void。 2. 函數名的區別:構造函數的函數名必須要與類名一致,普通函數的函數名只要符合標識符的命名規則即可。 3. 調用方式的區別:構造函數是在創建對象的時候由jvm調用的。普通函數是由我們使用對象調用的,一個對象可以對象多次普通的函數, 4. 作用上的區別:構造函數的作用用于初始化一個對象。普通函數是用于描述一類事物的公共行為的。跨域出現的原因/解決方法
1. 為什么出現了跨域 2. 跨域解決方式有哪些?原因:由于瀏覽器的同源策略,即屬于不同域的?面之間不能相互訪問各自的?面內容。哪些情況下產生跨域 1、域名不同 2、端口號不同 3、協議不同(http/https) 4、域名和域名對應ip 5、主域名相同(127.0.01 和 localhost) 多域名匹配一個ip地址 6、子域名不同(一級和二級域名)解決方法1、后端設置白名單 后端不存在跨域(后端代碼脫離瀏覽器,后端是服務器端) 利用后端(自己公司的后端)去獲取接口數據,將數據傳給前端 2、jsonp 原理:利用瀏覽器的"漏洞" src不受同源策略的影響,可以請求任何鏈接 。動態創建script標簽,將事先寫好的函數名傳給服務器,供服務器使用 (1)script標簽src屬性不存在跨域 (2)get方式--傳遞函數名 --弊端 (3)callback回調函數(傳遞函數名) 3、反向代理 proxy webpack配置(采用Socket協議) "proxy": {"/index.php": {"target": "http://qinqin.net","changeOrigin": true}} 4、CORS解決跨域(xhr2)(后端)后端配置響應頭,如果需要有特殊的約定字符,前端需要配置請求頭 CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源(協議 + 域名 + 端口)服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。 需要服務器(提供接口的源碼里面)添加下面兩句話。 header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Method:POST,GET');jsonp是一種非正式傳輸協議,用于解決跨域問題流程: 1、創建一個全局函數 2、創建一個script標簽 3、給script添加src 4、給src添加回調函數test(callback=test) callback是傳給后端的一個參數 5、將script放到?面上 6、script請求完成,將自己從?面上刪除閉包原理/優點/缺點/使用場景
1. 什么是閉包 what 函數嵌套函數 能夠讀取其他函數內部變量的函數 2. 優缺點優點: 1、使用閉包是不會污染全局環境,2、方便進行模塊化開發,缺點: 就是不恰當使用會造成內存泄漏 【解決方式:清除變量】 3. 閉包的應用場景函數防抖計數器閉包原理:定義在一個函數內部的函數(函數嵌套函數),閉包就是將函數內部和函數外部連接起來的一座橋梁。 打破了作用域鏈的規則 閉包就是能夠讀取其他函數內部變量的函數 優點: 1、使用閉包是不會污染全局環境, 2、方便進行模塊化開發, 3、減少形參個數,延長了形參的生命周期,壞處: 1、就是不恰當使用會造成內存泄漏 閉包的不適用于返回閉包的函數是個特別大的函數,很多高級應用都要依靠閉包實現.使用場景 1、通過循環給頁面上多個dom節點綁定事件 2、封裝私有變量(計數器) 3、延續局部變量的壽命 4、高階組件 5、函數防抖模塊化的就是以閉包為基礎構建的;內存泄漏
1、意外的全局變量 2、被遺忘的定時器 3、沒有清除的dom應用 ,故要及時清除, 4、濫用閉包清除內存泄漏方法有兩種,一是標記清除,二便是引用計數清除。promise/async&await
Promise是es6新增的,異步編程的一種解決方案,用來取代回調函數和事件,比傳統的解決方案——回調函數和事件——更合理和更強大。Promise 對象用于延遲(deferred) 計算和異步(asynchronous)計算。一個Promise對象代表著一個還未完成,但預期將來會完成的操作。Promise 對象是一個返回值的代理,這個返回值在promise對象創建時未必已知。它允許你為異步操作的成功或失敗指定處理方法。這使得異步方法可以像同步方法那樣返回值:異步方法會返回一個包含了原返回值的 promise 對象來替代原返回值。有三種狀態:pending(進行中)、fulfilled(resolve已成功)和rejected(銳杰克騰德)(已失敗)promise的特點: (1)對象的狀態不受外界影響。Promise對象代表一個異步操作。 (2)一旦狀態設定,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為resolve和從pending變為rejected。只要這兩種情況發生,狀態就凝固了promise的方法: promise實例方法:Promise.prototype.then Promise.prototype.catch一:resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去;二:reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。三:Promise.prototype.finallyfinally方法用于指定不管 Promise 對象最后狀態如何,都會執行的操作。該方法是 ES2018 引入標準的。promise的靜態方法 Promise.all():用于將多個 Promise 實例,包裝成一個新的 Promise 實例,接受一個數組作為參數,只有數組里面的每個狀態都變成resolve,則新的 Promise 實例狀態才會變成resolve.Promise.race():將Promise對象數組中最先執行完成的內容通過后面then傳出promise的基本使用: 通過new promise創建一個promise對象,里面有一個參數,參數是一個回調函數, 回調函數中有2個參數:resolve、reject resolve()當異步執行成功的時候調用的方法,reject()當異步失敗的時候調用的方法。 除此之外promise有一個then方法,當成功的時候執行第一個回調函數,當失敗的時候執行第二個回調函數。 第二個回調函數也可以通過promise對象.catch調用 Promise.all():當所有的異步代碼都執行完畢以后才會執行.then中的操作 Promise.race():只要有一個promise執行完畢后就會執行.then操作promise的三種狀態: 1.pending - 進行中 2.fulfilled - 成功 3.rejected - 失敗鏈式調用: promise俗稱鏈式調用,它是es6中最重要的特性之一 簡單的說可以不停的then調用嵌套在調用(異步之后,鏈式調用方式執行回調),這種操作方式稱為promiseasync異步能干什么? 就是用來修飾函數,使該函數異步執行,不阻礙后續函數的執行 同時我們注意到,async修飾的函數也帶有then catch方法, 因此,經async修飾的函數也 是一個promise await只能放在async中,且只能修飾promise對象 1. promise的誕生是為了簡化函數嵌套調用流程,也便于后續維護 2. async/await定義了異步函數,并在其內部可通過await等待promise對象,阻塞后 續的執行 await關鍵字必須在async函數里面 await會阻塞當前直到完成 async返回reject的方法,當拋出異常等同于reject async / await與 Promise的主要區別是: Promise代碼完全都是Promise的API(then、catch等等),操作本身的語義反而不容易看出來, async / await函數的實現最簡潔,最符合語義,幾乎沒有語義不相關的代碼 async / await 函數就是 Generator 函數的語法糖async/await函數的優勢 1. 使用async函數可以讓代碼簡潔很多,不需要像Promise一樣需要些then,不需要寫匿名函數處理Promise的resolve值,也不需要定義多余的data變量,還避免了嵌套代碼 2. 使用aync/await的話,catch能處理JSON.parse錯誤 promise中不能處理 3. 條件語句也和錯誤捕獲是一樣的,在 Async 中也可以像平時一般使用條件語句promise的狀態處理的原理:promise.all和promise.race
Pomise.all的使用Promise.all可以將多個Promise實例包裝成一個新的Promise實例。同時,成功和失敗的返回值是不同的,成功的時候返回的是一個結果數組,而失敗的時候則返回最先被reject失敗狀態的值。Promise.all獲得的成功結果的數組里面的數據順序和Promise.all接收到的數組順序是一致的,在前端開發請求數據的過程中,偶爾會遇到發送多個請求并根據請求順序獲取和使用數據的場景,使用Promise.all毫無疑問可以解決這個問題。Promise.race的使用Promise.race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])里面哪個結果獲得的快,就返回那個結果,不管結果本身是成功狀態還是失敗狀態。Generator
Generator 的中文名稱是生成器,它是ECMAScript6中提供的新特性。 在過去,封裝一段運算邏輯的單元是函數。函數只存在“沒有被調用”或者“被調用”的情況, 不存在一個函數被執行之后還能暫停的情況,而Generator的出現讓這種情況成為可能。通過 function* 來定義的函數稱之為“生成器函數”(generator function),它的特點是可以中斷函數的執行, 每次執行yield語句之后,函數即暫停執行,直到調用返回的生成器對象的next()函數它才會繼續執行。也就是說 Generator 函數是一個狀態機,封裝了多個內部狀態。 執行 Generator 函數返回一個遍歷器對象(一個指向內部狀態的指針對象), 調用遍歷器對象的next方法,使得指針移向下一個狀態。每次調用next方法, 內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)為止。yield關鍵字 真正讓Generator具有價值的是yield關鍵字,這個yield關鍵字讓 Generator內部的邏輯能夠切割成多個部分。 發現函數執行到第一個yield關鍵字的時候就停止了。要讓業務邏輯繼續執行完,需要反復調用.next() 可以簡單地理解為yield關鍵字將程序邏輯劃分成幾部分,每次.next()執行時執行一部分。 這使得程序的執行單元再也不是函數,復雜的邏輯可以通過yield來暫停。.next()調用時,返回一個對象,這個對象具備兩個屬性。 其中一個屬性是布爾型的done。它表示這個Generator對象的邏輯塊是否執行完成。 另一個屬性是value,它來自于yield語句后的表達式的結果。通過.next()傳遞參數,可以賦值給yield關鍵字前面的變量聲明。堆/棧
1、堆——引用類型地址傳遞堆:動態分配的內存,大小不定,不會自動釋放。存放引用類型的值 先進后出FILO引用類型: Object(Arrary, Date, Math,Function, Object)訪問方法: JS不能直接訪問內存中的值, 只能操作對象的地址, 所以產生深/淺拷貝問題棧--基本類型值傳遞 2、棧——自動分配內存空間,系統自動釋放,存放基本類型的值和引用類型的地址先進先出FIFO基本類型: Undefined、Null、Boolean、Number 和 String, Symbol(ES6新增)訪問方法: 按值訪問, 直接操作內存中的值深/淺拷貝及方法
深/淺拷貝針對的是引用類型淺拷貝 淺拷貝只復制指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存。 新舊互相影響,改變的是地址 新值===原值,只能拷貝一層數組方法: slice截取, concat拼接, filter過濾, map 對象方法: Object.assign({},obj), Object.create(obj)展開運算符: {...obj},[...arr] 深拷貝 深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象 新舊互不影響,改變的是值 新值=/=原值,可以拷貝多層1、JSON序列化JSON.parse(JSON.stringify(obj))對象-->字符串-->對象這個方式的弊端:1、如果obj里面有時間對象,則JSON.stringify后再JSON.parse的結果,時間將只是字符串的形式,而不是對 象的形式2、如果obj里有RegExp(正則表達式的縮寫)、Error對象,則序列化的結果將只得到空對象;3、如果obj里有函數,undefined,則序列化的結果會把函數或 undefined丟失;4、如果obj里有NaN、Infinity和-Infinity,則序列化的結果會變成null5、JSON.stringify()只能序列化對象的可枚舉的自有屬性,不可枚舉的不能被復制可枚舉:可枚舉性(enumerable)用來控制所描述的屬性,是否將被包括在for...in循環之中。具體來說,如果一個屬性的enumerable為false,下面三個操作不會取到該屬性。for..in循環、Object.keys方法、JSON.stringify方法 2、原生實現遞歸+淺拷貝3、工具實現【第三方封裝庫】 loadsh _.cloneDeep(obj).DeepClone()用于 Model / Entity / ... ... 等引用類型對象的深度克隆特性說明1.不需要對對象做任何特殊處理,直接 .DeepClone() 即可得到該對象的深度克隆2.不受對象層次深度限制,均可實現深度克隆(下面會給出幾個簡單示例 ... ...) Immutable Object.create()set和map
Set:它類似于數組,但是成員的值都是唯一的,沒有重復的值。 Set本身是一個構造函數,用來生成 Set 數據結構,數組作為參數。不說set 數據結構Set new set()存儲數據 set.size得到存儲的數據長度 has()判斷某個值是否存在set中 foreach遍歷set不說map : new map map.set map.get map.delete都是用來存儲數據用的,但是存儲的數據格式不同 set 直接存儲 任意類型數據 map 存儲數據的時候,必須以key,value的形式, set 使用forEach 遍歷的時候,key和value值是一樣的 而map 遍歷的時候,key就是存進去的對象的key,value就是存在的值for循環這種寫法比較麻煩,因此數組提供內置的forEach方法。forEach沒有返回值,無法中途跳出forEach循環,break命令或return命令都不能奏效。for...in循環主要是為遍歷對象而設計的,不適用于遍歷數組**for...of循環相比上面幾種做法,有一些顯著的優點。 有著同for...in一樣的簡潔語法,但是沒有for...in那些缺點。 不同于forEach方法,它可以與break、continue和return配合使用。 提供了遍歷所有數據結構的統一操作接口。宏任務和微任務
js 是單線程執行的,js中的任務按順序一個一個的執行,但是一個任務耗時太長,那么后面的任務就需要等待,為了解決這種情況,將任務分為了同步任務和異步任務,而異步任務又可以分為微任務和宏任務概念 1.宏任務:當前調用棧中執行的代碼成為宏任務。(主代碼快,定時器等等)。 2.微任務:當前(此次事件循環中)宏任務執行完,在下一個宏任務開始之前需要執行的任務,可以理解為回調事件。(promise.then,proness.nextTick等等)。 3.宏任務中的事件放在callback queue中,由事件觸發線程維護;微任務的事件放在微任務隊列中,由js引擎線程維護。運行機制 1. 在執行棧中執行一個宏任務。 2. 執行過程中遇到微任務,將微任務添加到微任務隊列中。 3. 當前宏任務執行完畢,立即執行微任務隊列中的任務。 4. 當前微任務隊列中的任務執行完畢,檢查渲染,GUI線程接管渲染。 5. 渲染完畢后,js線程接管,開啟下一次事件循環,執行下一次宏任務(事件隊列中取)。微任務:process.nextTick、MutationObserver、Promise.then catch finally 宏任務:I/O、setTimeout、setInterval、setImmediate、requestAnimationFramejs執行順序,(先執行宏任務列,微任務隊列) 先同步再異步,在此基礎上先宏任務再微任務流程:同步和異步任務分別進入不同的執行“場所”,同步進入主線程,異步進入Event Table并注冊函數。當指定的事情完成時,Event Table會將這個函數移入Event Queue。主線程內的任務執行完畢為空,回去了Event Queue讀取對應的函數,進入主線程。上述過程會不斷重復,也就是常說的Event Loop(事件循環)。但是,JS異步還有一個機制,就是遇到宏任務,先執行宏任務,將宏任務放入event queue,然后再執行微任務,將微任務放入eventqueue,但是,這兩個queue不是一個queue。當你往外拿的時候先從微任務里拿這個回調函數,然后再從宏任務的queue拿宏任務的回調函數,js異步操作
1、定時器都是異步操作 2、事件綁定都是異步操作 3、AJAX中一般我們都采取異步操作(也可以同步) 4、回調函數可以理解為異步(不是嚴謹的異步操作) 5、promise 6、generator(ES6) 通過yield關鍵字可以讓任務在需要的地方暫停,每一步的值可以通過next獲取 7、async/await(ES7) await得到的就是async異步返回值,底層原理還是promise中的resolve方法 8、設計模式-發布訂閱模式 9、事件監聽表單只能輸入數字
正則 type numberProxy和Reflect
Proxy用于修改某些操作的默認行為,即對編程語言層面進行修改,屬于“元編程”,Proxy意思為“代理”,即在訪問對象之前建立一道“攔截”,任何訪問該對象的操作之前都會通過這道“攔截”,即執行Proxy里面定義的方法let pro = new Proxy(target,handler)其中 new Proxy相當于創建了一個Proxy實例,target為所要攔截的目標對象,handler也是一個對象,里面定義的是對攔截對象所要進行的攔截方法Proxy也可以作為其他對象的原型對象使用上述實例將pro作為obj的原型對象使用,雖然obj本身沒有name這個屬性,但是根據原型鏈,會在pro上讀取到name屬性,之后會執行相對應的攔截操作。let pro = new Proxy(target,handler); let obj = Object.create(pro);Proxy常用的攔截方法
get(target,name,property)方法 用于攔截某個讀取屬性的操作,第一個參數為目標對象,第二個參數為屬性名稱,第三個屬性為操作所針對的對象(可選參數)set(target,name,value,property) 用于攔截某個屬性的賦值操作,第一個參數為目標對象,第二個參數為屬性名,第三個參數為屬性值,第四個參數為操作行為所針對的對象(可選參數)has(target,key) 用來攔截對象是否具有某個屬性值的操作,第一個參數為目標對象,第二個參數為屬性名Reflect(銳付萊克特)對象: Reflect設計的目的是為了優化Object的一些操作方法以及合理的返回Object操作返回的結果,對于一些命令式的Object行為,Reflect對象可以將其變為函數式的行為Reflect(target,name,property) Reflect.has(obj,"name") Reflect.get(target,name,property)瀏覽器優化
減少請求數量圖片處理雪碧圖gulp Base64 使用字體圖標來代替圖片 - 自定義字體 @font-face{} 在安卓下可以使用webp格式的圖片減小資源大小 - webpack優化HTML壓縮CSS壓縮JS壓縮與混亂圖片壓縮優化網絡連接cdnCDN即內容分發網絡,它能夠實時地根據網絡流量和各節點的連接、負載狀用戶可就近取得所需內容,解決 Internet網絡擁擠的狀況,提高用戶訪問網站的響應速度優化資源加載資源加載位置1、CSS文件放在head中,先外鏈,后本頁2、JS文件放在body底部,先外鏈,后本頁3、body中間盡量不寫style標簽和script標簽資源加載時機1、異步script標簽2、模塊按需加載需要根據路由來加載當前頁面需要的業務模塊3、資源懶加載與資源預加載減少重繪回流當render tree中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建。這就稱為回流當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響布局的,比如 background-color。則就叫稱為重繪。回流必將引起重繪,而重繪不一定會引起回流。css3硬件加速(GPU加速)六.【DOM優化】 1、緩存DOM 2、減少DOM深度及DOM數量 3、批量操作DOM 4、批量操作CSS樣式 5、在內存中操作DOM 6、DOM元素離線更新 7、DOM讀寫分離 8、事件代理 9、防抖和節流 10、及時清理環境請求頭
Accept(艾可塞克特) 告訴WEB服務器自己接受什么介質類型,*/* 表示任何類型,type/* 表示該類型下的所有子類型,type/sub-type。Accept-Charset(恰斯特) 瀏覽器告訴服務器自己能接收的字符集。Accept-Encoding(因扣定) 瀏覽器申明自己接收的編碼方法,通常指定壓縮方法,是否支持壓縮,支持什么壓縮方法(gzip,deflate)Accept-Language 瀏覽器申明自己接收的語言。語言跟字符集的區別:中文是語言,中文有多種字符集,比如big5,gb2312,gbk等等。Authorization(哦瑟惹C遜) 當客戶端接收到來自WEB服務器的 WWW-Authenticate 響應時,用該頭部來回應自己的身份驗證信息給WEB服務器。If-Match 如果對象的 ETag 沒有改變,其實也就意味著對象沒有改變,才執行請求的動作,獲取文檔。If-None-Match 如果對象的 ETag 改變了,其實也就意味著對象也改變了,才執行請求的動作,獲取文檔。(莫得反得) If-Modified-Since(森恩斯) 如果請求的對象在該頭部指定的時間之后修改了,才執行請求的動作(比如返回對象),否則返回代碼304,告訴瀏覽器該對象沒有修改。例如:If-Modified-Since:Thu, 10 Apr 2008 09:14:42 GMTIf-Unmodified-Since 如果請求的對象在該頭部指定的時間之后沒修改過,才執行請求的動作(比如返回對象)。If-Range /reinge/ 瀏覽器告訴 WEB 服務器,如果我請求的對象沒有改變,就把我缺少的部分給我,如果對象改變了,就把整個對象給我。瀏覽器通過發送請求對象的ETag 或者自己所知道的最后修改時間給 WEB 服務器,讓其判斷對象是否改變了。總是跟 Range 頭部一起使用。Range 瀏覽器(比如 Flashget 多線程下載時)告訴 WEB 服務器自己想取對象的哪部分。例如:Range: bytes=1173546Proxy-Authenticate(噢三特K特) 代理服務器響應瀏覽器,要求其提供代理身份驗證信息。Proxy-Authorization 瀏覽器響應代理服務器的身份驗證請求,提供自己的身份信息。Host 客戶端指定自己想訪問的WEB服務器的域名/IP 地址和端口號。如Host:rss.sina.com.cnReferer(銳佛爾) 瀏覽器向WEB 服務器表明自己是從哪個網頁URL獲得點擊當前請求中的網址/URL, 例如:Referer:http://www.ecdoer.com/User-Agent(A就特) 瀏覽器表明自己的身份(是哪種瀏覽器)。 例如:User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN;rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14static有什么特性
new出來一個實例對象是否帶有static屬性 static用ES5怎么寫沒有創建對象,也能使用屬性和調用方法用來形成靜態代碼塊以優化程序性能。因為只會在類加載的時候執行一次。因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行。static塊可以置于類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次被static修飾的變量或者方法是獨立于該類的任何對象,也就是說,這些變量和方法不屬于任何一個實例對象,而是被類的實例對象所共享。類第一次加載初始化的時候就去加載static部分,后面可以重新賦值static用ES5怎么寫: 靜態是通過類名直接調用 class A staticB 直接用A.B 將B綁定在A上async await
同步還是異步 await同步 async異步async和await有兩個關鍵字,一個寫在函數外面,一個寫在函數里面,函數外面是異步的,函數里面是同步的,調用函數的那一行其實是異步的,下一行 函數里面轉成阻塞的async await => promise 改寫async函數中 let a=await promise 的a函數 let b=await promise 的b函數promise.all改寫 Promise.allSettled Promise.anypromise實現promise.all的方法async使用的時候報錯,如何捕獲try...catchvar test3 = async function () {try {await p1();await p2();p3();} catch (e) {console.log('p1失敗了', e)}}await后面有個接口 接口要2S才能完成 接口2S才會執行$.ajax中async:false的阻塞和await這種阻塞有什么區別
沒區別怎么攜帶cookie發送給后端
設置請求頭 請求頭中攜帶cookie對象淺拷貝在react中用到哪些地方,為什么
為什么在react中要使用淺拷貝redux中要求:狀態是只讀的,唯一且不可修改的,reducer必須是一個純函數因為redux中數據不可更改,所以redux中的數據應該要拷貝 返回一個新值ajax、axios、fetch之間的詳細區別以及優缺點
1.jQuery ajax $.ajax({type: 'POST',url: url,data: data,dataType: dataType,success: function () {},error: function () {}}); 優缺點:是對原生XHR的封裝,除此以外還增添了對JSONP的支持。本身是針對MVC的編程,不符合現在前端MVVM的浪潮基于原生的XHR開發,XHR本身的架構不清晰,已經有了fetch的替代方案JQuery整個項目太大,單純使用ajax卻要引入整個JQuery非常的不合理(采取個性化打包的方案又不能享受CDN服務)2.axiosaxios({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);}); 優缺點:Axios本質上也是對原生XHR的封裝,只不過它是Promise的實現版本,符合最新的ES規范,從它的官網上可以看到它有以下幾條特性:從 node.js 創建 http 請求支持 Promise API客戶端支持防止CSRF提供了一些并發請求的接口(重要,方便了很多的操作)3.fetchtry {let response = await fetch(url);let data = response.json();console.log(data);} catch(e) {console.log("Oops, error", e);} 優缺點:符合關注分離,沒有將輸入、輸出和用事件來跟蹤的狀態混雜在一個對象里更好更方便的寫法更加底層,提供的API豐富(request, response)脫離了XHR,是ES規范里新的實現方式fetch是一個低層次的API,你可以把它考慮成原生的XHR,所以使用起來并不是那么舒服, 需要進行封裝,例如: 1)fetch只對網絡請求報錯,對400,500都當做成功的請求,需要封裝去處理 2)fetch默認不會帶cookie,需要添加配置項 3)fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現的超時控制并不能阻止請求過程繼續在后臺運行,造成了量的浪費 4)fetch沒有辦法原生監測請求的進度,而XHR可以為什么要用axios? axios 是一個基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特征:從瀏覽器中創建 XMLHttpRequest從 node.js 發出 http 請求支持 Promise API攔截請求和響應轉換請求和響應數據取消請求自動轉換JSON數據客戶端支持防止CSRF/XSRF回流/重繪 | 防抖/節流
回流: 當渲染樹中的一部分或者全部因為元素的尺寸、布局、隱藏等改變而需要重新構建的時候,這時 候就會發生回流。 每個?面都至少發生一次回流,也就是?面第一次加載的時候。 在回流的時候,瀏覽器會使渲染樹中受到影響的元素部分失效,并重新繪制這個部分的渲染樹, 完成回流以后,重繪: 當渲染樹中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響布局的,比如background-color。則就叫稱為重繪。防抖: 短時間內多次觸發同一事件,只執行最后一次,或者只執行最開始的一次,中間的不執行。 在事件觸發時,開始計時,在規定的時間(delay)內,若再次觸發事件,將上一次計時(timer)清空,然后重新開始計時。保證只有在規定時間內沒有再次觸發事件之后,再去執行這個事件。 節流: 指定時間間隔內,若事件被多次觸發,只會執行一次 在事件觸發之后,開始計時,在規定的時間(delay)內,若再次觸發事件,不對此事件做任何處理。保證在規定時間內只執行一次事件.減少重繪和回流的方式
CSS使用transform替代top使用visibility替換display:none避免使用table布局盡可能在DOM樹的最末端改變class避免設置多層內聯樣式將動畫效果應用到position屬性為absoulte或fixed的元素上避免使用css表達式將頻繁重繪或者回流的節點設置為圖層css硬件加速JavaScript避免頻繁操作樣式避免頻繁操作DOM避免頻繁讀取會引發重繪/回流的屬性對具有復雜動畫的元素使用絕對定位事件循環Event Loop
Event Loop 即事件循環 是指瀏覽器或者Node的一種解決JavaScript單線程運行時不阻塞的一種機制,單線程的是所有任務都在主線程上完成,任務太多的時候,頁面卡死,eventLoop可以解決單線程阻塞問題,程序中會有兩個線程,一個主線程,一個eventLoop線程,負責主線程和其他進程之間的通信,遇到I/O的時候,主線程會讓eventLoop線程通知對應的程序,主線程的任務會繼續往后執行,等I/O程序執行完了,eventLoop線程會把結果返回給主線程,主線程利用回調函數調用結果,完成任務 (1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。 (2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。 (3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。 (4)主線程不斷重復上面的第三步。宏任務和微任務的執行順序一次事件循環中,先執行宏任務隊列里的一個任務,再把微任務隊列里的所有任務執行完畢,再去宏任務隊列取下一個宏任務執行。同步異步的區別
在js中,所有任務都分為同步任務和異步任務兩大類。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。(1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。 (2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。 (3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。 (4)主線程不斷重復上面的第三步。有時候 setTimeout明明寫的延時3秒,實際卻5,6秒才執行函數,這又是因為什么?答:setTimeout 并不能保證執行的時間,是否及時執行取決于 JavaScript 線程是擁擠還是空閑。 瀏覽器的JS引擎遇到setTimeout,拿走之后不會立即放入異步隊列,同步任務執行之后,timer模塊會到設置時間之后放到異步隊列中。js引擎發現同步隊列中沒有要執行的東西了,即運行棧空了就從異步隊列中讀取,然后放到運行棧中執行。所以setTimeout可能會多了等待線程的時間。 這時setTimeout函數體就變成了運行棧中的執行任務,運行棧空了,再監聽異步隊列中有沒有要執行的任務,如果有就繼續執行,如此循環,就叫Event Loop。數據請求設置請求數據格式Content-Type
1.瀏覽器默認的 application/x-www-form-urlencoded(url因扣得的) 這應該是最常見的 POST 提交數據的方式了。瀏覽器的原生 form 表單,如果不設置 enctype 屬性,那么最終就會以 application/x-www-form-urlencoded 方式提交數據。2.multipart(莫踢怕特)/form-data 這也是一個常見的 POST 數據提交的方式。我們使用表單上傳文件時,就要讓 form 的 enctype 等于這個值3.application/json 除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify 4.text/xml 相比于JSON,不能更好的適用于數據交換,它包含了太多的包裝, 而且它跟大多數編程語言的數據模型不匹配,讓大多數程序員感到詫異,XML是面向數據的,JSON是面向對象和結構的,JSON會給程序員一種更加親切的感覺。數組扁平化
flat(infinite)
1. reduce遍歷數組每一項,若值為數組則遞歸遍歷,否則concat。function flatten(arr) { return arr.reduce((result, item)=> {return result.concat(Array.isArray(item) ? flatten(item) : item);}, []); }reduce是數組的一種方法,它接收一個函數作為累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值。 reduce包含兩個參數:回調函數,傳給total的初始值// 求數組的各項值相加的和: arr.reduce((total, item)=> { // total為之前的計算結果,item為數組的各項值return total + item; }, 0);2. toString & split 調用數組的toString方法,將數組變為字符串然后再用split分割還原為數組function flatten(arr) {return arr.toString().split(',').map(function(item) {return Number(item);}) } 因為split分割后形成的數組的每一項值為字符串,所以需要用一個map方法遍歷數組將其每一項轉換為數值型3. join & split 和上面的toString一樣,join也可以將數組轉換為字符串function flatten(arr) {return arr.join(',').split(',').map(function(item) {return parseInt(item);}) }4. 遞歸遞歸的遍歷每一項,若為數組則繼續遍歷,否則concatfunction flatten(arr) {var res = [];arr.map(item => {if(Array.isArray(item)) {res = res.concat(flatten(item));} else {res.push(item);}});return res; }5. 擴展運算符 es6的擴展運算符能將二維數組變為一維[].concat(...[1, 2, 3, [4, 5]]); // [1, 2, 3, 4, 5]根據這個結果我們可以做一個遍歷,若arr中含有數組則使用一次擴展運算符,直至沒有為止。function flatten(arr) {while(arr.some(item=>Array.isArray(item))) {arr = [].concat(...arr);}return arr; }如何擴展數組,讓他擁有新的方法
Array.prototype.push.apply(a,b)class中super作用是什么
es5 的繼承是先創建子類的this,然后將父類的方法添加到子類的this上去; es6 的繼承是創建父類的this對象,然后再對this對象添加方法/屬性。 而super方法就是用來創建父類this對象的。實際上執行的是 super.sport.call(this);xss攻擊和csrf攻擊是什么
1、CSRF(Cross-site request forgery):跨站請求偽造。 (1)登錄受信任網站A,并在本地生成Cookie。(如果用戶沒有登錄網站A,那么網站B在誘導的時候,請求網站A的api 接口時,會提示你登錄) (2)在不登出A的情況下,訪問危險網站B(其實是利用了網站A的漏洞)CSRF如何防御 方法一: Token 驗證:(用的最多)(1)服務器發送給客戶端一個token;(2)客戶端提交的表單中帶著這個token。(3)如果這個 token 不合法,那么服務器拒絕這個請求。 方法二: 隱藏令牌:把 token 隱藏在 http 的 head頭中。方法二和方法一有點像,本質上沒有太大區別,只是使用方式上有區別。 方法三: Referer(銳服爾) 驗證:Referer 指的是頁面請求來源。意思是,只接受本站的請求,服務器才做響應;如果不是,就攔截。2、XSS(Cross Site Scripting):跨域腳本攻擊。 XSS攻擊的核心原理是:不需要你做任何的登錄認證,它會通過合法的操作(比如在url中輸入、在評論框中輸入),向你的頁面注入腳本(可能是js、hmtl代碼塊等)。 最后導致的結果可能是:盜用Cookie破壞頁面的正常結構,插入廣告等惡意內容D-doss攻擊 XSS的攻擊方式 1、反射型發出請求時,XSS代碼出現在url中,作為輸入提交到服務器端,服務器端解析后響應,XSS代碼隨響應內容一起傳回給瀏覽器,最后瀏覽器解析執行XSS代碼。這個過程像一次反射,所以叫反射型XSS。 2、存儲型存儲型XSS和反射型XSS的差別在于,提交的代碼會存儲在服務器端(數據庫、內存、文件系統等),下次請求時目標頁面時不用再提交XSS代碼。XSS的防范措施(encode + 過濾)主要有三個: 1、編碼:對用戶輸入的數據進行HTML Entity(安特踢) 編碼。 2、過濾:移除用戶輸入的和事件相關的屬性。如onerror可以自動觸發攻擊,還有onclick等。(總而言是,過濾掉一些不安全的內容)移除用戶輸入的Style節點、Script節點、Iframe節點。(尤其是Script節點,它可是支持跨域的呀,一定要移除)。 3、校正避免直接對HTML Entity進行解碼。使用DOM Parse轉換,校正不配對的DOM標簽。這個概念,它的作用是把文本解析成DOM結構。比較常用的做法是,通過第一步的編碼轉成文本,然后第三步轉成DOM對象,然后經過第二步的過濾。還有一種簡潔的答案:首先是encode,如果是富文本,就白名單。3、CSRF 和 XSS 的區別: 區別一:CSRF:需要用戶先登錄網站A,獲取 cookie。XSS:不需要登錄。 區別二:(原理的區別)CSRF:是利用網站A本身的漏洞,去請求網站A的api。XSS:是向網站 A 注入 JS代碼,然后執行 JS 里的代碼,篡改網站A的內容。webapp和小程序有什么區別
首先,微信小程序已經提供了一套 view, data, model, router 層的開發工具, 對于開發簡單應用,小程序是可以比 webapp 更加快速的。但是實際上微信小程序提供的這一套開發框架,要開發一些復雜應用,是很困難的, 因為:小程序不支持 npm 等 package manager(麥呢橘)無法復用社區中已經很成熟的 web 框架和工具組件只能封裝 view 和 style,無法封裝行為(handler),行為只能定義在 page 上小程序有 1mb 的限制,所以我們只能將圖片之類的靜態資源事先放在服務器上其次,微信小程序是由微信自己來 host,開發者只需要上傳就好, 而微信 webapp 需要開發者自己 host,還需要注冊域名甚至備案才可以調用微信接口以及跟公眾號集成。 所以微信小程序降低了開發者的門檻。綜上,對于簡單的工具型應用,微信小程序可以讓開發者加快開發速度,降低發布門檻, 這種類型的應用比較適合微信小程序。對于復雜的應用,webapp 是更適合的形式。react優缺點
優點: 1、采用虛擬 DOM,它并不直接對DOM進行操作,安插在javascript邏輯和實際的DOM之間,性能好 2、跨瀏覽器兼容:虛擬DOM幫助我們解決了跨瀏覽器問題,它為我們提供了標準化的API,甚至在IE8中都是沒問題的。 3、一切都是組件:代碼更加 模塊化 ,重用代碼更容易,可維護性高。 4、單向數據流:redux 實現是一個用于在JavaScript應用中創建單向數據層的架構,它隨著React視圖庫的開發而被Facebook概念化。 5、同構、純粹的javascript:因為搜索引擎的爬蟲程序依賴的是服務端響應而不是JavaScript的執行,預渲染你的應用有助于搜索引擎優化。 6、兼容性好:比如使用RequireJS來加載和打包,而Browserify(不弱瑟)和Webpack適用于構建大型應用。它們使得那些艱難的任務不再讓人望而生畏。 7、JSX語法:為了更加便利的模擬DOM結構,我們使用了JSX語法,可以讓我們在JS中編譯DOM結構 8、函數式編程:JS的最大特點就是函數式編程,在React中,函數式編程可謂式無處不見缺點: 不適合單獨做一個完整的框架:react是視圖層框架,大型項目想要一套完整的框架的話,也許還需要引入Flux和route相關的東西。react生命周期
16版本: 初始階段: constructor定義state componentWillMount(這個鉤子函數在將來會被棄用)為掛載做準備工作 render 解析 this.state 和 this.props 將jsx型的虛擬dom渲染為對象類型的虛擬domrender 中不允許使用 this.setState() 如何你使用了,就會棧溢出 componentDidMount表示組件掛載結束虛擬dom -> Real dom可以獲取真實dom數據請求 -> 賦值給state第三方庫實例化/DOM操作更新階段: componentWillReceiveProps(在17版本中被棄用)這個鉤子實際作用是判斷組件身上的props是否發生改變 shouldComponentUpdate可以決組件是否要更新渲染 return true/false接收新舊狀態,用于作對比(淺對比)一般需要我們手動作深對比這個鉤子函數是React組件性能優化的一種方式 componentWillUpdate表示組件更新前的準備這個鉤子函數在未來版本被棄用 render和初始化階段的作用一致 componentDidUpdate對Real dom 作操作注意:父組件數據更新,子組件會重新運行render,反之不行每次都要運行子組件render,會造成react性能浪費 粗略解決方案:在shouldComponentUpdate中,可判斷哪些數據改變從而來控制return true/false 繼而決定是否需要更新render渲染更好的解決方案:1.引用PureComponent,讓類組件繼承(extends)PureComponent 如:class App extends PureComponent{}2.引用memo,讓函數組件寫在memo()里 如:const memoApp =memo(function App() {})3.除了memo之外,更細致的是函數組件中還可以用useCallback(方法)和useMemo(對象和數組)兩個鉤子阻止組件render銷毀階段: componentWillUnmount銷毀組件清除無用實例和事件 錯誤捕獲:componentDidCatch用戶捕獲子組件throw的錯誤,然后顯示回退UI15版本: 相對于16版本,初始化階段(constructor鉤子變成下列兩個):定義于初始化props的 getDefalutProps 鉤子函數定義于初始化state的 getInitialState 鉤子函數 沒有錯誤捕獲階段17版本: 相對于16版本 少3多2少了componentWillMount,componentWillReceiveProps,componentWillUpdate 3個鉤子函數(斯塔得可) (迪外的) 多了static getDerivedStateFromProps鉤子函數 (破外服)一個靜態方法,所以不能在這個函數里面使用this,這個函數有兩個參數nextProps和prevState,這個函數會返回一個對象用來更新當前的state對象,如果不需要更新可以返回null。簡單說就是,可以增加一次state狀態(斯那坡秀的) 多了getSnapshotBeforeUpdate鉤子函數快照這個函數有一個返回值,會作為第三個參數傳遞給componentDidUpdate鉤子redux流程 redux的原理
view用actionCreator(酷睿A特)創建一個action,里面可能包含一些數據 使用store的dispatch方法將action傳入store store將action與舊的state轉發給reducer reducer深拷貝state,并返回一個新的state給store store接收并更新state 使用store.subscribe(薩布斯快不)訂閱更新,重新render組件redux組成state :用來存儲數據和數據管理的、更新視圖reducer:是一個純函數,接收舊 state 和 action,根據不同的 Action 做出不同的操作并返回新的 stateactions:發送動作給reducer,reducer接收動作,判斷動作類型修改數據,修改事件后,組件重新做redux事件的訂閱Redux三大原則 單一數據源:整個應用的 state 被存儲在一個 Object tree 中,且只存在于唯一的Store中state 是只讀的:唯一改變 state 的方法就是觸發 action,action 是一個用于描述發生事件的普通對象,視圖部分只需要表達想要修改的意圖,所有修改都會被集中化處理。狀態的改變通過純函數來完成:Redux使用純函數方式來執行狀態的修改,Action表明了修改狀態值的意圖,而真正執行狀態修改的則是Reducer。且Reducer必須是一個純函數,當Reducer接收到Action時,Action并不能直接修改State的值,而是通過創建一個新的狀態對象來返回修改的狀態。redux 中間件
在action 和 store 之間執行中間件Redux中間件機制Redux本身就提供了非常強大的數據流管理功能,但這并不是它唯一的強大之處,它還提供了利用中間件來擴展自身功能,以滿足用戶的開發需求(米的為爾) applyMiddlewares():它是 Redux 的原生方法,作用是將所有中間件組成一個數組,依次執行。 applyMiddleware顧名思義,用于調用各種中間件; applyMiddleware執行后,將所有入參中間件存入一個數組,并且返回一個閉包(閉包的概念不做累述) 閉包接受一個createStore作為入參并且執行后返回下一個閉包。redux-thunk|異步action
首先檢查參數 action 的類型,如果是函數的話,就執行這個 action 函數, 并把 dispatch, getState, extraArgument(哎克斯拽埃歌門特) 作為參數傳遞進去, 否則就調用 next 讓下一個中間件繼續處理 action 好處可以進行前后端數據交互 缺點將帶有數據請求的action和沒有帶有數據請求的action混在一起了缺點解決: 棄用redux-thunk,使用redux-sagaredux-saga可以將異步action和普通action區別開來redux-saga|集中處理異步action
redux-saga可以將異步action和普通action區別開來,控制器與更優雅的異步處理 redux-saga就是用Generator(杰呢瑞特)來處理異步。redux-saga文檔并沒有說自己是處理異步的工具,而是說用來處理邊際效應(side effects),這里的邊際效應你可以理解為程序對外部的操作,比如請求后端,比如操作文件。redux-saga相當于在Redux原有數據流中多了一層,通過對Action進行監聽,從而捕獲到監聽的Action,然后可以派生一個新的任務對state進行維護(這個看項目本身的需求),通過更改的state驅動View的變更。redux-saga同樣是一個redux中間件,它的定位就是通過集中控制action,起到一個類似于MVC中控制器的效果。 同時它的語法使得復雜異步操作不會像promise那樣出現很多then的情況,更容易進行各類測試。redux與react-redux的關系
redux是獨立的應用狀態管理工具。它是可以獨立于react之外的。如果我們需要在react當中運用它,那么我們需要手動訂閱store的狀態變化,來對我們的react組件進行更新。react-reudx這個工具,就幫我們實現了這個功能,我們只需對store進行處理,react組件就會有相應的變化。Redux的核心由三部分組成:Store, Action, Reducer。 Store: 是個對象,貫穿你整個應用的數據都應該存儲在這里。 Action: 是個對象,必須包含type這個屬性,reducer將根據這個屬性值來對store進行相應的處理。除此之外的屬性,就是進行這個操作需要的數據。 Reducer: 是個函數。接受兩個參數:要修改的數據(state) 和 action對象。根據action.type來決定采用的操作,對state進行修改,最后返回新的state。總結 Redux: store, action, reducer store: getState, dispatch, subscribe combineReducers (克木拜恩) createStore store ? dispatch ? action ? reducerreact-redux: connect : 將store作為props注入 provider(破外的): 使store在子孫組件的connect中能夠獲取到react-reudx
1. UI組件|顯示頁面?? (破森特遜弄)React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件 2. 容器組件|負責管理數據/復雜邏輯?UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。 3. Provider組件|容器組件獲取state??所有的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動生成。也就是說,用戶負責視覺層,狀態管理則是全部交給它。 4. connect()|UI組件+容器組件React-Redux 提供connect方法,用于從 UI 組件生成容器組件。connect的意思,就是將這兩種組件連起來。DVA與CRA相比的優點
dva:dva 首先是一個基于 redux 和 redux-saga 的數據流方案,然后為了簡化開發體驗,dva 還額外內置了 react-router 和 fetch,所以也可以理解為一個輕量級的應用框架。--- 來自官方。相比于cra只是多了內置的redux和redux-saga,幫我們處理了數據流這方面的需求而已。如果只是想要達到這個效果的話,直接在cra中增加dva-core的依賴也是可以做到的。umi:是一個可插拔的企業級 react 應用框架。umi和cra都是應用框架,可能相比cra來說umi的功能點更多一些,只能說是功能性的話umi要相對來說更勝一籌flux
flux 是 react 中的類似于 vuex 的公共狀態管理方案,它是 Facebook 官方給出的應用架構,利用數據的單向流動的形式對公共狀態進行管理。現已不推薦使用。flux的組成View:視圖層Action:視圖發出的消息Dispatcher:派發者,用來接收Action,執行回調函數Store:數據層,存放狀態,一旦發生改動flux 在進行數據更新時,會經歷以下幾步:用戶與 View 層交互,觸發 ActionAction 使用 dispatcher.dispatch 將Action自己的狀態發送給dispatcherdispatcher 通過register注冊事件,再通過Action傳入的類型來觸發對應的 Store 回調進行更新Store 里進行相應的數據更新,并觸發 View 層事件使試圖也同步更新View層 收到信號進行更新redux和flux的區別1)redux是flux中的一個實現Flux的核心思想就是數據和邏輯永遠單向流動2)在redux中我們只能定義一個store,在flux中我們可以定義多個3)在redux中,store和dispatch都放到了store,結構更加清晰4)在redux中本身就內置State對象,對倉庫的管理更加明確React 中 keys 的作用
key是react用于追蹤哪些列表被修改、被添加或者被移出的輔助標識。在開發過程中,我們需要保證某些元素在同級的元素中key是具有唯一性的特性,在react Diff算法中React會借助元素的key值來判斷該元素是新創建的還是移動而來的元素,從而減少元素的不必要的重復渲染。此外,我們還需要借助key值來判斷元素與本地狀態的關聯關系,因此我們絕不可忽視轉換函數中 Key 的重要性。react根據key來決定是銷毀重新創建組件還是更新組件,原則是:key相同,組件有所變化,react會只更新組件對應變化的屬性。 key不同,組件會銷毀之前的組件,將整個組件重新渲染。react新特性和diff算法
render 支持返回這五類: React elements, 數組, Fragments, Portal, String/numbers, boolean/null, 基礎數據類型Fiber React Fiber的方法其實很簡單——分片。把一個耗時長的任務分成很多小片,每一個小片的運行時間很短,雖然總時間依然很長,但是在每個小片執行完之后,都給其他任務一個執行的機會,這樣唯一的線程就不會被獨占,其他任務依然有運行的機會。新的生命周期函數 由于異步渲染的改動,componentWillMount, componentWillReceiveProps,componentWillUpdate 三個函數將被廢棄。 由于這是一個很大的改變會影響很多現有的組件,所以需要慢慢的去改。 目前react 16 只是會報warning,在react 17就只能在前面加UNSAFE_的前綴來使用diff算法 作用: 計算出Virtual DOM中真 正變化的部分,并只針對該部分進行原生DOM操作,而非重新渲染整個頁面getDerivedStateFromProps static getDerivedStateFromProps(props, state)在調用render方法之前調用, 無論是在初始安裝還是后續更新。它應返回一個對象來更新狀態,或者返回null以不更新任何內容。根據props更新state 這個生命周期可用于替代componentWillReceivePropsgetSnapshotBeforeUpdate() getSnapshotBeforeUpdate(prevProps, prevState)在最近呈現的輸出被提交到例如DOM之前調用。它使組件可以在可能更改之前從DOM捕獲一些信息(例如滾動位置)。此生命周期返回的任何值都將作為參數傳遞給componentDidUpdate()。hookslazy、suspense lazy需要跟Suspence配合使用。 lazy實際上是幫助我們實現代碼分割的功能。由于有些內容,并不一定要在首屏展示,所以這些資源沒有必要一開始就要去獲取,那么這些資源就可以動態獲取。 這樣的話,相當于把不需要首屏展示的代碼分割出來,減少首屏代碼的體積,提升性能。Suspence 很像Error Boundary,不同的是Error Boundary是用來捕獲錯誤,顯示相應的callback組件。而Suspence是用來捕獲還沒有加載好的組件,并暫停渲染,顯示相應的callback。setState概述,同步異步
1. 兩個參數及用法第一個參數可以是對象或者函數,是更新state 第二個參數獲取最新的state,副作用操作,dom操作事件觸發聲明,數據獲取,第三方庫實例化2. 同步/異步原理setState在合成事件和鉤子函數中是異步的 在原生事件和setTimeout中是同步的setState的“異步”并不是說內部由異步代碼實現,其實本身執行的過程和代碼都是同步的,只是合成事件和鉤子函數的調用順序在更新之前,導致在合成事件和鉤子函數中沒法立馬拿到更新后的值,形式了所謂的“異步”,當然可以通過第二個參數 setState(partialState, callback) 中的callback拿到更新后的結果。setState 的批量更新優化也是建立在“異步”(合成事件、鉤子函數)之上的,在原生事件和setTimeout 中不會批量更新,在“異步”中如果對同一個值進行多次 setState , setState 的批量更新策略會對其進行覆蓋,取最后一次的執行,如果是同時 setState 多個不同的值,在更新時會對其進行合并批量更新。react合成事件
1. 合成事件原理如果DOM上綁定了過多的事件處理函數,整個頁面響應以及內存占用可能都會受到影響。React為了避免這類DOM事件濫用,同時屏蔽底層不同瀏覽器之間的事件系統差異,實現了一個中間層——SyntheticEvent。當用戶在為onClick添加函數時,React并沒有將Click時間綁定在DOM上面。 而是在document處監聽所有支持的事件,當事件發生并冒泡至document處時,React將事件內容封裝交給中間層SyntheticEvent(負責所有事件合成) 所以當事件觸發的時候,對使用統一的分發函數dispatchEvent將指定函數執行。2. 與原生事件的區別React合成事件一套機制:React并不是將click事件直接綁定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React將事件封裝給正式的函數處理運行和處理。react路由傳參和讀參
1.params <Route path='/path/:name' component={Path}/> <link to="/path/2">xxx</Link> this.props.history.push({pathname:"/path/" + name}); 讀取參數用:this.props.match.params.name 優勢:刷新地址欄,參數依然存在 缺點:只能傳字符串,并且,如果傳的值太多的話,url會變得長而丑陋。2.query <Route path='/query' component={Query}/> <Link to={{ path : ' /query' , query : { name : 'sunny' }}}> this.props.history.push({pathname:"/query",query: { name : 'sunny' }}); 讀取參數用: this.props.location.query.name 優勢: 傳參優雅,傳遞參數可傳對象; 缺點: 刷新地址欄,參數丟失3.state <Route path='/sort ' component={Sort}/> <Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}> this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }}); 讀取參數用: this.props.location.query.state 優缺點同query4.search <Route path='/web/departManange ' component={DepartManange}/> <link to="web/departManange?tenantId=12121212">xxx</Link> this.props.history.push({pathname:"/web/departManange?tenantId" + row.tenantId}); 讀取參數用: this.props.location.search 優缺點同paramsredux和mobx(類似雙向數據綁定)區別
1. 組成部分actions->state->computed values->Reactions 2. 工作流在mobx中, 數據是通過加 @observable 作為可監測的被觀察者, 在view層中, 你可以通過添加@observer 將view作為觀察者,對數據進行監測, 如果要觸發改變數據,則使用@action, 事實上,你可以直接在view層改變數據, 但這種方式不便監控數據,因此不推薦直接改變數據。 而@computed可以用來計算數據, 也可以是計算多個數據之后返回新的數據, 如果其中數據改變, @computed也會觸發改變 3. 優點不同于redux的單一數據流, mobx中,你可以同時在各個地方使用同一份state, 也可以在一個頁面中使用多個store文件react組件通信5種
1.父組件向子組件通信 React數據流動是單向的,父組件向子組件通信也是最常見的;父組件通過props向子組件傳遞需要的信息2.子組件向父組件通信 利用回調函數,可以實現子組件向父組件通信:父組件將一個函數作為 props 傳遞給子組件,子組件調用該回調函數,便可以向父組件通信。3.非嵌套組件間通信 非嵌套組件,就是沒有任何包含關系的組件,包括兄弟組件以及不在同一個父級中的非兄弟組件。對于非嵌套組件,可以采用下面兩種方式:利用二者共同父組件的 context 對象進行通信使用自定義事件的方式 如果采用組件間共同的父級來進行中轉,會增加子組件和父組件之間的耦合度,如果組件層次較深的話,找到二者公共的父組件不是一件容易的事,當然還是那句話,也不是不可以。4.跨組件通信 所謂跨級組件通信,就是父組件向子組件的子組件通信,向更深層的子組件通信。跨級組件通信可以采用下面兩種方式:中間組件層層傳遞 props使用 context 對象 中間組件層層傳遞 props:如果父組件結構較深,那么中間的每一層組件都要去傳遞 props,增加了復雜度,并且這些 props 并不是這些中間組件自己所需要的。不過這種方式也是可行的,當組件層次在三層以內可以采用這種方式,當組件嵌套過深時,采用這種方式就需要斟酌了。使用 context 對象:context 相當于一個全局變量,是一個大容器,我們可以把要通信的內容放在這個容器中,這樣一來,不管嵌套有多深,都可以隨意取用。 使用 context 也很簡單,需要滿足兩個條件:上級組件要聲明自己支持 context,并提供一個函數來返回相應的 context 對象子組件要聲明自己需要使用 context5.redux 首先由view dispatch攔截action,然后執行對應reducer并更新到store中,最終views會根據store數據的改變執行界面的刷新渲染操作。1)首先先把redux相關工具安裝好 2)通過創建一個store實例createStore,接收一個rootReducer和中間件執行函數3)創建分塊的數據rootReducer,通過combineReducers打造rootReducer,里面放分塊的數據4)在組件中通過高階組件connect函數,接收store里的數據,把ActionCreators里的方法綁定到組件身上,并且可以發送動作action給reducer5)在reductor中根據action中的type動作類型,判斷動作修改數據組件按需加載
(實現方式,需要的依賴)懶加載1、vue異步組件技術vue-router配置路由,使用vue的異步組件技術,可以實現按需加載。但是,這種情況下一個組件生成一個js文件。2.import()3.webpack提供的require.ensure()4.第三方庫比如react-loadable 5.lazyload-loader組件銷毀
componentWillUnmount定義state flag:false 作為開關 定義方法if判斷是否為1,改變state flag:true將方法綁定組件上 可以用三目或者短路原則&&控制組件的顯示隱藏Ant D中input輸入框三個屬性怎么實現
onChange輸入框內容改變時候回調 value輸入的內容 defaultValue輸入框默認值input默認值在input中綁定value 定義一個state 和input雙向數據綁定 做成受控組件 定義一個事件 改變的時候獲取e.target.valueHooks
為什么使用hook不必寫class組件就可以用state和其他的React特性;自定義hook 實現組件的復用 用useEffects代替生命周期方法 代碼更加簡潔出現原因3點為了讓函數組件擁有類組件的功能。原因比如useState、useReducer 狀態定義比如useEffect、useLayoutEffect 生命周期功能比如useRef useImperativeHandle 替代了類組件的 Ref為了優化函數組件,比如useMemo、useCallback函數組件添加新的方法,如useDebugValue顯示自定義hook,自己添加hook類名自定義hooks來復用狀態優點4點 1.讓函數組件可以定義狀態 讓函數組件可以使用生命周期、監聽數據讓函數組件可以有Ref的功能(父組件獲取子組件)優化函數組件 useMemo、useCallback自定義hooks來復用狀態,代碼量比類組件更少,更清爽。 2.使用規則2點不要在循環,條件或嵌套函數中調用 Hook只在函數組件中使用 Hooks 3.常用HookuseState:定義狀態 修改狀態返回一個數組,其中第一項是狀態值,第二項是一個更新狀態的函數。狀態一旦改變,React 就會重新渲染組件,變量獲取新的狀態值。useEffect:相當于componentDidMount,componentDidUpdate,componentWillUnmount三個鉤子的組合參數一:執行的回調函數;參數二:該useEffect在哪些state發生變化時,才重新執行;第二個參數是空數組的時候執行一次,相當于componentDidMount,不加的時候執行多次第二個參數的作用就是 僅在更改時更新,實現性能的優化DOM操作 第三方實例化可以做 清除無用實例和事件useEffect傳入的回調函數本身可以有一個返回值,這個返回值是另外一個回調函數,來模擬componentWillUnmountuseLayoutEffect:布局副作用useEffect 在瀏覽器渲染完成后執行useLayoutEffect 在瀏覽器渲染前執行,在render過程中,會阻塞Dom渲染useLayoutEffect 里的任務最好影響了 Layout為了用戶體驗,優先使用 useEffect (優先渲染)useContext:跨組件通信 createContext創建一個組件 <numContext.Provider value={num}>useDebugValue:自定義 hook 的標簽 方便調試臺查看useMemo:記憶組件 動態緩存 新值和舊值一樣,不重新渲染頁面,優化作用,類似于shouldComponentUpdate useCallBack:作用和 useMemo 一樣useMemo和useCallback都會在組件第一次渲染的時候執行,之后會在其依賴的變量發生改變時再次執行并且這兩個hooks都返回緩存的值,useMemo返回緩存的變量,useCallback返回緩存的函數。useCallback(x => console.log(x), [m]) 等價于useMemo( () => x => console.log(x), [m])useRef:返回一個可變的ref對象useImperativeHandle:將組件中的方法放到外面使用搭配React.forwardRef5.自定義hook類似于高階組件 高階組件返回的一個類組件,而自定義Hook可以返回任何東西高階組件必須傳遞一個組件作為參數,而自定義Hook不需要function useFriendStatus(friendID) {const [isOnline, setIsOnline] = useState(null);// 在開發者工具中的這個 Hook 旁邊顯示標簽// e.g. "FriendStatus: Online"useDebugValue(isOnline ? 'Online' : 'Offline');return isOnline;} 可以理解為數據的操作都在hook里進行,而外部只關心自己想要的。我只要數據列表,獲取產品鉤子(可能并不需要,可通過參數變更從而觸發重新獲取數據)、刪除產品鉤子 為了封裝方法:節流;react useState() Hook
1.使用 useState() 進行狀態管理調用useState() Hook 來啟用函數組件中的狀態。useState(initialValue)的第一個參數initialValue是狀態的初始值。[state, setState] = useState(initialValue)返回一個包含2個元素的數組:狀態值和狀態更新函數。使用新值調用狀態更新器函數setState(newState)更新狀態。或者,可以使用一個回調setState(prev => next)來調用狀態更新器,該回調將返回基于先前狀態的新狀態。調用狀態更新器后,React 確保重新渲染組件,以使新狀態變為當前狀態。 2.多種狀態通過多次調用useState(),一個函數組件可以擁有多個狀態。需要注意的,要確保對useState()的多次調用在渲染之間始終保持相同的順序。 3.狀態的延遲初始化每當 React 重新渲染組件時,都會執行useState(initialState)。如果初始狀態是原始值(數字,布爾值等),則不會有性能問題。當初始狀態需要昂貴的性能方面的操作時,可以通過為useState(computeInitialState)提供一個函數來使用狀態的延遲初始化,該函數僅在初始渲染時執行一次,以獲得初始狀態。在以后的組件渲染中,不會再調用該函數,從而跳過昂貴的操作。 4.調用 useState() 在使用useState() Hook 時,必須遵循 Hook 的規則: 1.僅頂層調用Hook:不能在循環,條件,嵌套函數等中調用useState()。在多個useState()調用中,渲染之間的調用順序必須相同。 2.僅從React 函數調用 Hook:必須僅在函數組件或自定義鉤子內部調用useState()。高階組件HOC
1.名詞解釋/作用使函數復用,可以通過給組件傳遞方法來復用高階組件中的函數方法。高階組件特點高階組件是一個函數高階組件接收一個組件作為參數進行使用,且需要在render函數中return返回這個組件高階組件的目的是為了: 復用組件,將多個組件都要使用的類似邏輯放在同一個地方進行處理,類似于在Vue中封裝cookie以供重復使用2.常用高階組件4個React.memo()connect()provider() withRouter() // 可以使用 3.有自己封裝過嗎 拖拽封裝,給組件里面的標簽添加方法就可以實現拖拽,并返回標簽的x與y坐標。深對比,深復制封裝、正則封裝、頁面路由跳轉、路由數據接收解析。拖拽封裝思路
重點: 1、一定要絕對定位,脫離文檔流才可以移動。 2、綁定拖拽的元素,移動和鼠標松開后是對document的綁定,因為移動的是整個div。 3、點擊:a= 獲取當前鼠標坐標、b =div距瀏覽器距離、c = 鼠標在div內部距離=a-b。移動:通過 a - c 建立鼠標與div的關系,防止鼠標超出div。拖拽狀態 = 0鼠標在元素上按下的時候{ 拖拽狀態 = 1 記錄下鼠標的x和y坐標 記錄下元素的x和y坐標 } 鼠標在元素上移動的時候{ 如果拖拽狀態是0就什么也不做。 如果拖拽狀態是1,那么 元素y = 現在鼠標y - 原來鼠標y + 原來元素y 元素x = 現在鼠標x - 原來鼠標x + 原來元素x } 鼠標在任何時候放開的時候{ 拖拽狀態 = 0 }數據請求封裝思路
自定義hook封裝過組件嗎
1.將Hello組件和App組件中共用的邏輯放在統一的自定義hook中寫 2.自定義hook,hook名以use開頭 3.其他組件通過import引入自定義hook,就可以使用了react和vue的區別
相同點: 1.都使用了虛擬dom,如果需要改變任何元素的狀態,先改虛擬dom,當有變化產生時,會創建新的虛擬dom,通過diff算法對比新舊虛擬dom的差異,只需要渲染差異部分就行 2.都使用組件化不同點: 1.react中有新語法jsx,vue用普通的html 2.vue中父組件和子組件有通信的時候,父組件數據改變引起子組件改變,子組件會重新渲染,如果父子組件沒有通信,父組件改變子組件不會渲染,react中不管是否有數據通信,父組件改變子組件都會渲染 3.react:create-react-appvue :vue-cli 4.react中用redux管理狀態,state通過setState更新vue中數據由vuex管理react的class組件,沒有class的時候怎么寫
React.createClass 我們最早使用這個方法來構建一個組件“類”,它接受一個對象為參數, 對象中必須聲明一個render方法,render返回一個組件實例生命周期 鉤子函數用es5怎么定義
protoType.componentDidMount虛擬dom和diff算法
虛擬 dom 相當于在 js 和真實 dom 中間加了一個緩存,利用 dom diff 算法 避免了沒有必要的 dom 操作,從而提高性能 具體實現步驟如下 用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹, 插到文檔當中 當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩 棵樹差異把2所記錄的差異應用到步驟1所構建的真正的 DOM 樹上,視圖就更新1.虛擬dom是什么所謂的虛擬 dom,也就是虛擬節點。它通過JS的Object對象模擬DOM中的節點,然后再通過特定的render方法將其渲染成真實的DOM節點用js模擬一顆dom樹,放在瀏覽器內存中。當你要變更時,虛擬dom使用diff算法進行新舊虛擬dom的比較,將變更放到變更隊列中,反應到實際的dom樹,減少了dom操作。2.虛擬dom的使用基本流程(前四步驟)1.獲取數據2.創建虛擬dom3.通過render函數解析jsx,將其轉換成虛擬dom結構4.將虛擬dom渲染成真實dom5.數據更改了6.使用diff算法比對兩次虛擬dom,生成patch對象7.根據key將patch對象渲染到頁面中改變的結構上,而其他沒有改變的地方是不做任何修改的(虛擬dom的惰性原則)優點: 保證性能下限: 框架的虛擬 DOM 需要適配任何上層 API 可能產生的操作,它的一些 DOM 操作的實現必須是普適的,所以它的性能并不是最優的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虛擬 DOM 至少可以保證在你不需要手動優化的情況下,依然可以提供還不錯的性能,即保證性能的下限; 無需手動操作 DOM: 我們不再需要手動去操作 DOM,只需要寫好 View-Model 的代碼邏輯,框架會根據虛擬 DOM 和 數據雙向綁定,幫我們以可預期的方式更新視圖,極大提高我們的開發效率; 跨平臺: 虛擬 DOM 本質上是 JavaScript 對象,而 DOM 與平臺強相關,相比之下虛擬 DOM 可以進行更方便地跨平臺操作,例如服務器渲染、weex 開發等等。缺點: 無法進行極致優化: 雖然虛擬 DOM + 合理的優化,足以應對絕大部分應用的性能需求,但在一些性能要求極高的應用中虛擬 DOM 無法進行針對性的極致優化。首次渲染大量DOM時,由于多了一層虛擬DOM的計算,會比innerHTML插入慢。1.diff算法是什么Diff算法是用于比較兩個新舊虛擬dom樹的差異的,比較完之后會得到一個差異對象,我們稱之為patch補丁對象比較后會出現四種情況:1、此節點是否被移除 -> 添加新的節點2、屬性是否被改變 -> 舊屬性改為新屬性3、文本內容被改變 -> 舊內容改為新內容4、節點要被整個替換 -> 結構完全不相同 移除整個替換2.diff算法運行結束后,返回是什么返回一個keyreact Native
React Native(內特服)能在手機上創建原生應用,React在這方面處于領先位置。使用JavaScript, CSS和HTML創建原生移動應用,這是一個重要的革新。Vue社區與阿里合作開發Vue版的React Native——Weex也很不錯,但仍處于開發狀態且并沒經過實際項目的驗證。既擁有Native的用戶體驗、又保留React的開發效率React Native與React.js的主要區別還是JSX,它使用XML標記的方式去直接聲明界面,將HTML直接嵌入到JavaScript代碼中react-router(路由)原理
react-router依賴基礎 - history history是一個獨立的第三方js庫,可以用來兼容在不同瀏覽器、不同環境下對歷史記錄的管理老瀏覽器的history: 主要通過hash來實現,對應createHashHistory 高版本瀏覽器: 通過html5里面的history,對應createBrowserHistory node環境下: (不弱惹)主要存儲在歷史記錄memeory里面,對應createMemoryHistory 抽象了一個公共的文件createHistory:此時的location跟瀏覽器原生的location是不相同的,最大的區別就在于里面多了key字段,history內部通過key來進行location的操作原理: 1.執行URL前進createBrowserHistory: pushState、replaceStatecreateHashHistory: location.hash=*** location.replace()createMemoryHistory: 在內存中進行歷史記錄的存儲 1.檢測URL回退createBrowserHistory: popstatecreateHashHistory: hashchangecreateMemoryHistory: 因為是在內存中操作,跟瀏覽器沒有關系,不涉及UI層面的事情,所以可以直接進行歷史信息的回退 1.state的存儲為了維護state的狀態,將其存儲在sessionStorage里面:基本原理:實現URL與UI可視化界面的同步。其中在react-router中,URL對應Location對象,而UI是由react components來決定的,這樣就轉變成location與components之間的同步問題。在react-router中最主要的component是Router、RouterContext、Link,history庫起到了中間橋梁的作用安裝react-router-dom Link組件用于點擊鏈接跳轉其他頁面,沒有路由激活NavLink 用于有路由激活效果的react-router-dom和react-router的區別
寫法上的區別: import {Swtich, Route, Router, HashHistory, Link} from 'react-router-dom';import {Switch, Route, Router} from 'react-router'; import {HashHistory, Link} from 'react-router-dom';react-router-dom: 加入了在瀏覽器運行環境下的一些功能:BrowserRouter和HashRouter組件,前者使用pushState和popState事件構建路由,后者使用window.location.hash和hashchange事件構建路由。react-router-dom是依賴于react-router的,其中Switch、Route、Router、Redirect等組件是直接引入react-router中的react-router-dom還另外新增了Link、BrowserRouter、HashRouter組件。在引入react-router-dom后不需要顯性引入react-router, react-router-dom依賴react-router,npm都會將他們安裝。react-router3.x與react-router-dom區別react-router3.x版本下路由采用集中式配置,UI組件和路由是分開的。react-router4.x版本下路由路由采用分散式配置,路由嵌套在UI組件當中,更加契合組件化思想(組件中的路由也應該包含在組件之中)。react路由模式
我們一直在使用的路由方式是BrowserRouter,也就是瀏覽器的路由方式,其實React還有幾種路由方式:(不弱惹) 1、BrowserRouter:瀏覽器的路由方式,也就是在開發中最常使用的路由方式 2、HashRouter:在路徑前加入#號成為一個哈希值,Hash模式的好處是,再也不會因為我們刷新而找不到我們的對應路徑 3、MemoryRouter:不存儲history,所有路由過程保存在內存里,不能進行前進后退,因為地址欄沒有發生任何變化 4、NativeRouter:經常配合ReactNative使用,多用于移動端 5、StaticRouter:設置靜態路由,需要和后臺服務器配合設置,比如設置服務端渲染時使用(斯大推克)react路由配置
1、引入路由包npm install --save react-routernpm install --save react-router-domreact-router:是基本的router包,里邊函的內容較多,但是在網頁開發中有很多用不到,現在的市面上的課程講的基本都是這個包的教程。react-router-dom:隨著react生態環境的壯大,后出現的包,這個包比react-router包輕巧了很多。 2、設置路由配置文件在src目錄下新建一個Router/index.js文件用于管理路由,這里需要引入一些對應的組件和路由包文件。Router的history是必需的propsSwitch表示只渲染第一個與當前地址匹配的<Route>Route的props path為路徑,component為路徑對應的頁面exact屬性表示精確匹配,比如我們有多層路由進行嵌套時,exact可以幫助我們精確匹配到你想跳轉的路由。 exact的值為bool型,為true是表示嚴格匹配,為false時為正常匹配3、在入口文件引入路由配置文件import RouterConfig from './router/index.js';ReactDOM.render(<RouterConfig/>, document.getElementById('root'));4、在各組件中使用路由<ul className="menu"><li><NavLink to='/Page1'>第一個頁面</NavLink></li><li><NavLink to='/Page2'>第二個頁面</NavLink></li></ul>1.Switch:表示一次只渲染一個組件 2.Route:路由組件,用于展示一個組件 同router-view 3.Redirect:重定向(銳得埃克特) 4.lazy + Suspense(色斯盤絲):實現路由懶加載 5.exact:路徑完全匹配 6.fallback:組件切換時候的轉場組件react路由(router)實現異步加載
react-router,官網文檔給出的是用webpack的bundle-loaderrequire.ensure。這是webpack的舊式寫法,現在已不推薦import()符合ECMAScript提議的import()語法,該提案與普通 import 語句或 require 函數的類似,但返回一個 Promise 對象。這意味著模塊時異步加載的react原理
1. setState setState在合成事件和鉤子函數中是異步的 在原生事件和setTimeout中是同步的setState的“異步”并不是說內部由異步代碼實現,其實本身執行的過程和代碼都是同步的,只是合成事件和鉤子函數的調用順序在更新之前,導致在合成事件和鉤子函數中沒法立馬拿到更新后的值,形式了所謂的“異步”,第一個參數可以是對象或者函數 是更新state 第二個參數獲取最新的state,副作用操作 dom操作事件觸發聲明 數據獲取2. JSX語法的轉化JSX 僅僅是 createElement() 方法的語法糖(簡化語法)JSX 語法被 @babel/preset-react 插件編譯為 createElement() 方法react.createElement()React 元素:是一個對象,用來描述你希望在屏幕上看到的內容3. 組件更新機制setState() 的兩個作用: 1. 修改 state 2. 更新組件(UI)過程:父組件重新渲染時,也會重新渲染子組件。但只會渲染當前組件子樹(當前組件及其所有子組件) 4. 組件性能優化減輕 state:只存儲跟組件渲染相關的數據避免不必要的重新渲染 : shouldComponentUpdate(nextProps, nextState) 通過返回值決定該組件是否重新渲染,返回 true 表示重新渲染,false 表示不重新渲染 起到優化作用5. 純組件 PureComponentPureComponent 內部自動實現了 shouldComponentUpdate 鉤子,不需要手動比較 純組件內部通過分別 對比 前后兩次 props 和 state 的值,來決定是否重新渲染組件 純組件內部的對比是 shallow compare(淺層對比)6. 虛擬 DOM 和 Diff 算法數據改變視圖更新初次渲染時,React 會根據初始state(Model),創建一個虛擬 DOM 對象(樹)。根據虛擬 DOM 生成真正的 DOM,渲染到頁面中。當數據變化后(setState(),重新根據新的數據,創建新的虛擬DOM對象(樹)。與上一次得到的虛擬 DOM 對象,使用 Diff 算法 對比(找不同),生成patch補丁對象,得到需要更新的內容。最終,React 只將變化的內容更新(patch)到 DOM 中,重新渲染到頁面。react的connect高階組件實現, 如何在全局中取得store
連接React組件與 Redux store。 connect:connect函數的返回值是一個高階組件,通過高階組件來獲取store中的數據 connect底層原理:是閉包mapStateFromProps:從countReducer中解構出num數據,用來獲取數據 mapDispatchFromProps:將ActionCreators中的方法綁定到組件上,并且發送actionconnect調用的結果是返回一個高階組件 connect方法利用了合并分發的原理來幫助我們完成store內容的獲取合并: 將store中的所有數據拿到手 分發: 將我們UI需要的數據派發出去原理 合并分發 :合并的意思是:(我們項目中)redux的數據是集中在一處的 分發的意思是:給的是所有數據中的分塊的數據react的connect實現原理
首先connect之所以會成功,是因為Provider組件: 在原應用組件上包裹一層,使原來整個應用成為Provider的子組件 接收Redux的store作為props,通過context對象傳遞給子孫組件上的connect那connect做了些什么呢? 它真正連接 Redux 和 React,它包在我們的容器組件的外一層, 它接收上面 Provider 提供的 store 里面的 state 和 dispatch, 傳給一個構造函數,返回一個對象,以屬性形式傳給我們的容器組件。關于它的源碼 connect是一個高階函數,首先傳入mapStateFromProps、mapDispatchFromProps, 然后返回一個生產Component的函數(wrapWithConnect), 然后再將真正的Component作為參數傳入wrapWithConnect, 這樣就生產出一個經過包裹的Connect組件,該組件具有如下特點:通過props.store獲取祖先Component的store props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作為props傳給真正的Component componentDidMount時,添加事件this.store.subscribe(this.handleChange),實現頁面交互 shouldComponentUpdate時判斷是否有避免進行渲染,提升頁面性能,并得到nextState componentWillUnmount時移除注冊的事件this.handleChangereact-router3和react-router4 的區別
一、V3或者說V早期版本是把router 和 layout components 分開在V4中是:集中式 router通過 <Route> 嵌套,實現 Layout 和 page 嵌套Layout 和 page 組件 是作為 router 的一部分 二、在V3中,我們是將整個龐大的router直接丟給Dom在V4中,除了BrowserRouter,我們丟給DOM的我們的程序本身另外,V4 中,我們不再使用 {props.children} 來嵌套組件了,替代的 <Route>,當 route 匹配時,子組件會被渲染到 <Route> 書寫的地方三、在V3 中的 routing 規則是 exclusive,意思就是最終只獲取一個 route而 V4 中的 routes 默認是 inclusive 的,這就意味著多個 <Route>可以同時匹配和呈現如果只想匹配一個路由,可以使用Switch,在 <Switch> 中只有一個 <Route> 會被渲染,同時可以再在每個路由添加exact,做到精準匹配Redirect,瀏覽器重定向,當多有都不匹配的時候,進行匹配react中獲取真實的dom節點
使用ref屬性獲取Dom元素后,再使用原生javascript獲取內容react是什么層面上的框架
React框架本身和我們常用的JavaScript MVC框架,如:AngularJS,Backbone,Ember等,沒有直接的可比性。 React的官方博客中明確闡述了React不是一個MVC框架, 而是一個用于構建組件化UI的庫,是一個前端界面開發工具。所以頂多算是MVC中的V(view)。react數據流
React遵循從上到下的數據流向,即單向數據流。單向數據流并非‘單向綁定’,甚至單向數據流與綁定沒有‘任何關系’。 對于React來說,單向數據流(從上到下)與單一數據源這兩個原則,限定了React中要想在一個組件中更新另一個組件的狀態(類似于Vue的平行組件傳參,或者是子組件向父組件傳遞參數) ,需要進行狀態提升。即將狀態提升到他們最近的祖先組件中。子組件中Change了狀態,觸發父組件狀態的變更,父組件狀態的變更, 影響到了另一個組件的顯示(因為傳遞給另一個組件的狀態變化了,這一點與Vue子組件的$emit()方法很相似)。react數據一定要在DidMount里獲取更新的原因
componentDidMount方法中的代碼,是在組件已經完全掛載到網頁上才會調用被執行,所以可以保證數據的加載。 在這方法中調用setState方法,會觸發重渲染。這個方法就是用來加載外部數據用的,或處理其他的副作用代碼。constructor()constructor()中獲取數據的話,如果時間太長,或者出錯,組件就渲染不出來,整個頁面都沒法渲染了。constructor是作組件state初紿化工作,并不是設計來作加載數據的。componentWillMount()如果使用SSR(服務端渲染),componentWillMount會執行2次,一次在服務端,一次在客戶端。而componentDidMount不會。constructor可以完成state初始化,componentWillMount使用的很少,目前16版本加入了UNSAFE來標識 componentWillMount,新的生命周期static getDerivedStateFromProps() 也會替代這個。React16之后采用了Fiber架構,只有componentDidMount聲明周期函數是確定被執行一次的,類似ComponentWillMount的生命周期鉤子都有可能執行多次,所以不加以在這些生命周期中做有副作用的操作,比如請求數據之類。render()無限rendercomponentDidMount()確保已經render過一次。提醒我們正確地設置初始狀態,這樣就不會得到導致錯誤的"undefined"狀態。react中的受控組件和非受控組件
受控組件HTML中的表單元素是可輸入的,也就是有自己的可變狀態而React中可變狀態通常保存在state中,并且只能通過setState()方法來修改React講state與表單元素值value綁定在一起,有state的值來控制表單元素的值簡單來說,值受到react控制的表單元素非受控組件調用 React.createRef() 方法創建ref對象將創建好的 ref 對象添加到文本框中通過ref對象獲取到文本框的值簡單來說,表單組件沒有value prop就可以稱為非受控組件react中的ref的3種方式
方式1: string類型綁定 類似于vue中的ref綁定方式,可以通過this.refs.綁定的ref的名字獲取到節點dom 注意的是 這種方式已經不被最新版的react推薦使用,有可能會在未來版本中遺棄方式2: react.CreateRef() 通過在class中使用React.createRef()方法創建一些變量,可以將這些變量綁定到標簽的ref中 那么該變量的current則指向綁定的標簽dom方式3: 函數形式 在class中聲明函數,在函數中綁定ref 使用這種方法可以將子組件暴露給父組件以使得父組件能夠調用子組件的方法 通過函數的方法綁定ref可以將整個子組件暴露給父組件當在子組件中調用onRef函數時,正在調用從父組件傳遞的函數。this.props.onRef(this)這里的參數指向子組件本身,父組件接收該引用作為第一個參數:onRef = {ref =>(this.child = ref)}然后它使用this.child保存引用。之后,可以在父組件內訪問整個子組件實例,并且可以調用子組件函數。react中的static(靜態方法)
靜態方法和 React 沒有直接關系,React 的組件都是繼承自 React.Component 這個類,靜態方法屬于類本身。static并不是react定義的,而加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用。這里涉及到了ES6的class,我們定義一個組件的時候通常是定義了一個類, 而static則是創建了一個屬于這個類的屬性或者方法。 組件則是這個類的一個實例,component的props和state是屬于這個實例的,react的props與state的區別
props: 一般用于父組件向子組件通信,在組件之間通信使用。 state: 一般用于組件內部的狀態維護,更新組建內部的數據,狀態,更新子組件的props等。混合開發
1. 混合開發是介于webapp和原生app之間的一種應用,它同時具有webapp可以跨平臺的特性,也具備原生app可以進行安裝使用的特性 2. webApp 1. 優點: 跨平臺 、 維護更新、項目迭代快2. 缺點: 交互體驗不好 、進入應用的方式麻煩 3. 原生app1.案例: 美團、餓了嗎、微信、QQ 2.安裝在手機中使用的 3.優點: 手機安裝、交互體驗好 4.缺點: 維護更新、項目迭代很慢、成本太高了 4. 混合開發: 擇中方案跨平臺維護更新快 成本低手機安裝,交互體驗好為什么混合開發會興起呢? 1. 混合開發的興起是偶然的混合開發方式 1. h5 主導- 開發思維: H5【 vue/ react/ angular 】 + 第三方可以訪問原生設備的庫- 微信公眾號: h5網頁 + 微信JSSDK - 歷史1. PhoneGap + cordva.js 淘汰2. vue/react/angular + ioinc.js 3. vue - uni-app 4. h5 + h5plus.js h5 + h5+5. 微信公眾號: webapp + js-jdk 6. vue/react + weex.js[ 阿里內部 ] 2. React Native1. facebook 團隊項目 16 - 18年很熱火,18年后半年開始熱度下降,facebook覺得這個框架對于開發者而言開發難度太大,維護成本也高,Facebook決定不再更新它了、2. 典型應用: 餓了嗎3. React Native開發出來項目 - 原生app 4. React Native = React + 原生js5. 構建React Native項目 - 腳手架 1. 構建項目環境: create-react-native-app 2. 手機調試:expo expo-cli3. 目錄解釋1. __test__ expo手機調試的測試文件夾,不用管2. .expo 臨時文件,運行項目3. .expo-shared 分享4. assets 靜態資源5. components 公共組件6. constants 項目公用的常量7. navigation 底部tabbar欄組件8. node_modules 依賴包9. screens 頁面小程序
對于路由的觸發方式以及頁面生命周期函數如下:
| 初始化 | 小程序打開的第一個頁面 | onLoad, onSHow | |
| 打開新頁面 | 調用 API wx.navigateTo 或使用組件 | onHide | onLoad, onShow |
| 頁面重定向 | 調用 API wx.redirectTo 或使用組件 | onUnload | onLoad, onShow |
| 頁面返回 | 調用 API wx.navigateBack 或使用組件或用戶按左上角返回按鈕 | onUnload | onShow |
| Tab 切換 | 調用 API wx.navigateBack 或使用組件或用戶按調用 API wx.switchTab 或使用組件 或用戶切換 Tab | 各種情況請參考下表 | |
| 重啟動 | 調用 API wx.reLaunch 或使用組件 | onUnload | onLoad, onShow |
頁面跳轉觸發的生命周期,其實還是存在問題的,并非官方所說的那樣。
SwitchTab的跳轉BUG 首頁跳轉到子頁面后,在子頁面上使用: <navigator type='switchTab' url="/pages/index/index" ><view>跳轉首頁</button> </navigator> 這種方式有問題,解決的辦法是通過JS來實現跳轉,代碼如下: <view class="weui-btn-area"><button class="weui-btn" bindtap="backIndex" type="default">返回主頁</button> </view> 跳轉成功后,重新調用onload方法,JS代碼如下: backIndex:function(){wx.switchTab({url: '/pages/index/index',success: function (e) {var page = getCurrentPages().pop();if (page == undefined || page == null) return;page.onLoad();}})}get與post的區別
1.提交方式 get: get會將接收到的數據拼接到url地址中,以"?"問號劃分,問號后面是接收到的數據,多個數據之間用&連接。用戶可以很直觀的看見。 post: post會將接收到的數據放置在html header中一起發送到指定的url地址內。用戶看不到這個過程。2.傳遞數據大小 get: get傳遞數據的大小因為受到瀏覽器地址欄的限制,所以一般在2k-8k,這要據瀏覽器而定,比如谷歌瀏覽器就是8k。 post: post傳遞數據的大小最小是2M,但理論上是無上限的。3.應用范圍 get: get一般用于獲取/查詢資源信息.多用于a標簽的href屬性中,也常用于location.href屬性中。 post: post一般是用于更新數據信息.多用于表單提交。4.安全性 get的安全性比post較差。react父組件通過ref獲取不到子組件的解決方案
在子組件中 this.customfunction = this.customfunction.bind(this); 即可React PureComponent 和 Component 區別
React.PureComponent 與 React.Component 幾乎完全相同,但 React.PureComponent 通過prop和state的淺對比來實現 shouldComponentUpate()。如果React組件的 render() 函數在給定相同的props和state下渲染為相同的結果,在某些場景下你可以使用 React.PureComponent 來提升性能。React.PureComponent 的 shouldComponentUpdate() 只會對對象進行淺對比。如果對象包含復雜的數據結構,它可能會因深層的數據不一致而產生錯誤的否定判斷(表現為對象深層的數據已改變視圖卻沒有更新, 原文:false-negatives)。當你期望只擁有簡單的props和state時,才去繼承 PureComponent ,或者在你知道深層的數據結構已經發生改變時使用 forceUpate() 。或者,考慮使用 不可變對象 來促進嵌套數據的快速比較。此外,React.PureComponent 的 shouldComponentUpate() 會忽略整個組件的子級。請確保所有的子級組件也是”Pure”的。PureComponent的作用:PureComponent 其實是在內部幫我們簡單實現了一下shouldComponentUpdate的功能,以便提供組件的性能;這里的簡單指是:對prop和state做淺比較,若淺比較結果相同,則該組件以及其子組件不做render;否則,render。使用PureComponent注意事項:PureComponent主要針對prop和state為基本數據類型,如bool、string、number;對于數組和對象等引用類型,則要引用不同,才會渲染;如果引用相同,則PureComponent淺比較返回結果相同,不做render;PureComponent 中不建議再另外重寫shouldComponentUpdate方法,否則會報warning信息:PureComponent的最好作為展示組件,如果prop和state每次都會變,PureComponent做淺比較也會影響性能,可以考慮直接用Component;對于prop和state數據結構比較復雜的情況,可以考慮自己重寫shouldComponentUpdate方法來做優化;react中調用setState之后發生
React會將當前傳入的參數對象與組件當前的狀態合并,然后觸發調和過程,在調和的過程中,React會以相對高效的方式根據新的狀態構建React元素樹并且重新渲染整個UI界面.React得到的元素樹之后,React會自動計算出新的樹與老的樹的節點的差異,然后根據差異對界面進行最小化的渲染,在React的差異算法中,React能夠精確的知道在哪些位置發生看改變以及應該如何去改變,這樣就保證了UI是按需更新的而不是重新渲染整個界面SPA和MPA的異同
單頁應用(SinglePage Application,SPA)指只有一個主頁面的應用,一開始只需加載一次 js,css 等相關資源。所有的內容都包含在主頁面,對每一個功能模塊組件化。單頁應用跳轉,就是切換相關組件,僅刷新局部資源。多頁應用(MultiPage Application,MPA)指有多個獨立的頁面的應用,每個頁面必須重復加載 js,css 等相關資源。多頁應用跳轉,需要整頁資源刷新。兩者對比表格:SPA ||| MPA 結構:一個主頁面 + 許多模塊的組件 ||| 許多完整的頁面 體驗:頁面切換快,體驗佳;當初次加載文件過多時,需要做相關的調優。 ||| 頁面切換慢,網速慢的時候,體驗尤其不好 資源文件:組件公用的資源只需要加載一次 ||| 每個頁面都要自己加載公用的資源 適用場景:對體驗度和流暢度有較高要求的應用,不利于 SEO(可借助 SSR 優化 SEO) ||| 適用于對 SEO 要求較高的應用 過渡動畫:Vue 提供了 transition 的封裝組件,容易實現 ||| 很難實現 內容更新:相關組件的切換,即局部更新 ||| 整體 HTML 的切換,費錢(重復 HTTP 請求) 路由模式:可以使用 hash ,也可以使用 history ||| 普通鏈接跳轉 數據傳遞:因為單頁面,使用全局變量就好(Vuex) ||| cookie 、localStorage 等緩存方案,URL 參數,調用接口保存等 相關成本:前期開發成本較高,后期維護較為容易 ||| 前期開發成本低,后期維護就比較麻煩,因為可能一個功能需要改很多地方單頁應用實現核心:前端路由 前端路由的核心:改變視圖的同時不會向后端發出請求。TS
TS好處: 1、強類型 2、不需要去瀏覽器中瀏覽效果,就能知道編譯錯誤靜態類型檢查可以做到early fail,即你編寫的代碼即使沒有被執行到,一旦你編寫代碼時發生類型不匹配,語言在編譯階段(解釋執行也一樣,可以在運行前)即可發現 4、類型就是最好的注釋,看類型我們就知道這個是什么 3、即使ts中有編譯報錯,tsc依舊可以將其編譯成js學習TS的基本數據類型 定類型是為了安全,規矩多就安全 1、基礎數據類型 :number \string\boolean\null\undefinedany 表示任意類型 void 表示空類型,空類型是針對函數的,表示函數沒有返回值。返回空 2、內置對象類型 : Array \ Boolean \ HTMLElement 3、自定義類型 : 接口 類 泛型 枚舉類型TS 中 interface 和 type 的區別
在ts中,定義類型由兩種方式:接口(interface)和類型別名(type alias) interface只能定義對象類型, type聲明的方式可以定義組合類型,交叉類型和原始類型如果用type alias 聲明的方式,會導致一些功能的缺失1.interface方式可以實現接口的extends/implements,而type 不行2.interface可以實現接口的merge,但是type不行Webpack
webpack打包react vue,與自己的源代碼分離使用splitchunks webpack熱更新:不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。webpack會分析每個入口文件,解析包依賴關系的各個文件,每個模塊都打包到bundle.js。webpack給每個模塊分配一個唯一的ID并通過這個ID索引和訪問模塊。頁面運行時,先啟動entry.js,其他模塊會在運行require時候執行。1.Webpack Loader Plugin(loader ,plugin分別什么作用,哪個配置可以把依賴包抽離出來,不打包進去) 【Loader】:用于對模塊源碼的轉換,loader描述了webpack如何處理非javascript模塊,并且在buld中引入這些依賴。loader可以將文件從不同的語言(如TypeScript)轉換為JavaScript,或者將內聯圖像轉換為data URL。比如說:CSS-Loader,Style-Loader等。babel-loader優雅降級配置ES高版本轉成低版本【Plugin】:是用于在webpack打包編譯過程里,在對應的事件節點里執行自定義操作,比如資源管理、bundle文件優化等操作,依賴包抽離 const ExtractTextWebapckPlugin= require("extract-text-webpack-plugin") module exclude node_modules排除excloude排除node_modulesloader的使用很簡單:在webpack.config.js中指定loader。module.rules可以指定多個loader,對項目中的各個loader有個全局概覽。loader是運行在NodeJS中,可以用options對象進行配置。plugin可以為loader帶來更多特性。loader可以進行壓縮,打包,語言翻譯等等。loader從模板路徑解析,npm install node_modules。也可以自定義loader,命名XXX-loader。語言類的處理器loader:CoffeeScript,TypeScript,ESNext(Bable),Sass,Less,Stylus。任何開發技術棧都可以使用webpack。webpack常用的loader樣式:style-loader、css-loader、less-loader、sass-loader等 文件:raw-loader、file-loader 、url-loader等 編譯:babel-loader、coffee-loader 、ts-loader等 校驗測試:mocha-loader、jshint-loader 、eslint-loader等目的在于解決loader無法實現的其他事,從打包優化和壓縮,到重新定義環境變量,功能強大到可以用來處理各種各樣的任務。webpack提供了很多開箱即用的插件:CommonChunkPlugin主要用于提取第三方庫和公共模塊,避免首屏加載的bundle文件,或者按需加載的bundle文件體積過大,導致加載時間過長,是一把優化的利器。而在多頁面應用中,更是能夠為每個頁面間的應用程序共享代碼創建bundle。webpack功能強大,難點在于它的配置文件,webpack4默認不需要配置文件,可以通過mode選項為webpack指定了一些默認的配置,mode分為:development/production,默認是production。插件可以攜帶參數,所以在plugins屬性傳入new實例。webpack常用的plugin webpack內置UglifyJsPlugin,壓縮和混淆代碼。 webpack內置CommonsChunkPlugin,提高打包效率,將第三方庫和業務代碼分開打包。 ProvidePlugin:自動加載模塊,代替require和importhtml-webpack-plugin可以根據模板自動生成html代碼,并自動引用css和js文件extract-text-webpack-plugin 將js文件中引用的樣式單獨抽離成css文件DefinePlugin 編譯時配置全局變量,這對開發模式和發布模式的構建允許不同的行為非常有用。【Mode】可以在config文件里面配置,也可以在CLI參數中配置:webpack--mode=production(一般會選擇在CLI,也就是npm scripts里面進行配置)。在webpack4以下版本,webpack3.XX,通過plugins進行環境變量的配置。【resolve】模塊,resolver是個庫,幫助webpack找到bundle需要引入的模塊代碼,打包時,webpack使用enhanced-resolve來解析路徑。 2.webpack優化 多進程打包 安裝插件thread-loader parallel-webpack HappyPack多進程壓縮 parallel-uglify-plugin terser-webpack-plugin 資源CDN 公用代碼提取,使用 CDN 加載 動態polyfill 動態 polyfill 指的是根據不同的瀏覽器,動態載入需要的 polyfillflex布局
flex是由 flex-grow:1父容器在主軸上還有多少剩余空間,flex-shrink當父元素的寬度大于所有子元素的寬度的和時(即父元素會有剩余空間), 子元素如何分配父元素的剩余空間flex-basis基準值組成flex 怎么實現1個盒子垂直居中 如何實現四個盒子水平均勻分布父容器 display:flex; justify-content: center; align-items: center;display: flex; justify-content:space-evenly; align-items: center;實現導航的吸頂效果
設置css:fixed固定定位 判斷滾動條滾動的距離大于導航條距頂部的距離,來判斷是否實現吸頂,然后addClass添加樣式less的hover簡寫
a{&:hover {} //這里&代表它的上一級就是a }CSS偽類 ::after,before的應用場景
::before和::after必須配合content屬性來使用, content用來定義插入的內容,content必須有值,至少是空。 默認情況下,偽類元素的display是默認值inline,可以通過設置display:block來改變其顯示。1.清除浮動: 在浮動元素后面添加一個空的Div標簽,然后在設置它的清除浮動要是,使用after偽元素2.常見消息框 : 偽類content:' ' 偽類4條邊必須寬度相同,而且其他三條邊為transparent 可以通過設置定位元素left,top值為50%,translate(-50%,-50%) 來使任意寬高的元素居中。div::before{content:' ';3.陰影 : 通過設置before,after不同位置,不同旋轉角度,要保證偽類的顏色及z-indexdiv.outer::before,div.outer::after{content:'';z-index:1;width:50%;height:3px;position:absolute;left:10px;bottom:7px;background-color:transparent;box-shadow:5px 5px 10px rgba(0,0,0,0.5);-webkit-transform:rotate(-3deg);4.做出各種圖形效果#star-five:before {border-bottom: 80px solid red;border-left: 30px solid transparent;border-right: 30px solid transparent;position: absolute;height: 0;width: 0;top: -45px;left: -65px;content: '';transform: rotate(-35deg);}#star-five:after {width: 0;height: 0;border-left: 100px solid transparent;border-right: 100px solid transparent;border-bottom: 70px solid yellow;top: 7px;left: -110px;position: absolute;display: block;content: '';transform: rotate(-70deg);}CSS權重的計算
權重疊加 0,0,0,5 + 0,0,0,5 =0,0,0,10 而不是 0,0,1,0,所以不會存在10個div能趕上一個類選擇器的情況繼承的權重是0 1)如果選中了,那么以上面的公式來計權重。誰大聽誰的。 2)如果沒有選中,那么權重是0,因為繼承的權重為0當選擇器沖突時,權重高的生效;當權重相同時,寫在后頭的會把前面的覆蓋。http
http2.0,https連接,http概述:超文本傳輸協議,是互聯網上應用最為廣泛的一種網絡協議http的缺點 1.通信使用明文可能會被竊聽。 2.不驗證通信方的身份可能遭遇偽裝。 3.無法證明報文的完整性,可能已遭篡改。https就是在安全的傳輸層上發送的http。它在將http報文發送給TCP之前,先將其發送給了一個安全層 ,對其進行加密。http安全層是通過ssl及其現代替代協議TSL來實現的。https的優點 (1)使用HTTPS協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器; (2)HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程中不被竊取、改變,確保數據的完整性。https的缺點 但是https因為加了層ssl,所以在效率方面比較低,會使頁面加載的時長延長近50%,也會增加10-20%的耗電。 需要安裝證書,在一定基礎上增加部署費用,并且報文加密解密對數據傳遞有一點的效率影響。http/2.0的目標是改善用戶加載頁面的時候更快 HTTP/2采用二進制格式而非文本格式 HTTP/2是完全多路復用的,而非有序并阻塞的——只需一個連接即可實現并行http對稱加密非對稱加密
對稱密鑰加密是指加密和解密使用同一個密鑰的方式,一方通過密鑰將信息加密后,把密文傳給另一方,另一方通過這個相同的密鑰將密文解密,轉換成可以理解的明文非對稱加密是加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。指使用一對非對稱密鑰,即公鑰和私鑰,公鑰可以隨意發布,但私鑰只有自己知道。發送密文的一方使用對方的公鑰進行加密處理,對方接收到加密信息后,使用自己的私鑰進行解密。WebSocket和http有什么區別
socket是傳輸控制層協議,webSocket是應用層協議WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信(full-duplex)。 一開始的握手需要借助HTTP請求完成。HTTP請求缺點: 會導致過多不必要的請求,浪費流量和服務器資源,每一次請求、應答,都浪費了一定流量在相同的頭部信息上然而WebSocket的出現可以彌補這一缺點。 在WebSocket中,只需要服務器和瀏覽器通過HTTP協議進行一個握 手的動作,然后單獨建立一條TCP的通信通道進行數據的傳送。原理:(webSocket) WebSocket同HTTP一樣也是應用層的協議,但是它是一種雙向通信協議,是建立在TCP之上的。1. 瀏覽器、服務器建立TCP連接,三次握手。這是通信的基礎,傳輸控制層,若失敗后續都不執行。 2. TCP連接成功后,瀏覽器通過HTTP協議向服務器傳送WebSocket支持的版本號等信息。(開始前的HTTP握手) 3. 服務器收到客戶端的握手請求后,同樣采用HTTP協議回饋數據。 4. 當收到了連接成功的消息后,通過TCP通道進行傳輸通信。WebSocket與HTTP的關系 相同點: 都是一樣基于TCP的,都是可靠性傳輸協議。 都是應用層協議不同點: WebSocket是雙向通信協議,模擬Socket協議,可以雙向發送或接受信息。HTTP是單向的。 WebSocket是需要握手進行建立連接的。錯誤調試工具
F12 斷點 錯誤附近輸出打印 火狐中的firebug IE開發者工具 Emmethttp狀態碼
200 OK 請求成功。一般用于GET與POST請求 3開頭 重定向 300 多種選擇。請求的資源可包括多個位置,相應可返回一個資源特征與地址的列表用于用戶終端(例如:瀏覽器)選擇 301 永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今后任何新的請求都應使用新的URI代替 302 臨時移動。與301類似。但資源只是臨時被移動。客戶端應繼續使用原有URI 303 查看其它地址。與301類似。使用GET和POST請求查看 304 未修改。所請求的資源未修改,服務器返回此狀態碼時,不會返回任何資源。客戶端通常會緩存訪問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之后修改的資源 305 使用代理。所請求的資源必須通過代理訪問 306 已經被廢棄的HTTP狀態碼 307 臨時重定向。與302類似。使用GET請求重定向 400 客戶端請求的語法錯誤,服務器無法理解 401 請求要求用戶的身份認證 402 保留,將來使用 403 服務器理解請求客戶端的請求,但是拒絕執行此請求 404 服務器無法根據客戶端的請求找到資源(網頁)。通過此代碼,網站設計人員可設置"您所請求的資源無法找到"的個性頁面 405 客戶端請求中的方法被禁止 406 N服務器無法根據客戶端請求的內容特性完成請求 407 請求要求代理的身份認證,與401類似,但請求者應當使用代理進行授權 408 服務器等待客戶端發送的請求時間過長,超時 409 服務器完成客戶端的 PUT 請求時可能返回此代碼,服務器處理請求時發生了沖突 410 客戶端請求的資源已經不存在。410不同于404,如果資源以前有現在被永久刪除了可使用410代碼,網站設計人員可通過301代碼指定資源的新位置 411 服務器無法處理客戶端發送的不帶Content-Length的請求信息 412 客戶端請求信息的先決條件錯誤 413 由于請求的實體過大,服務器無法處理,因此拒絕請求。為防止客戶端的連續請求,服務器可能會關閉連接。如果只是服務器暫時無法處理,則會包含一個Retry-After的響應信息 414 請求的URI過長(URI通常為網址),服務器無法處理 415 服務器無法處理請求附帶的媒體格式 416 客戶端請求的范圍無效 417 服務器無法滿足Expect的請求頭信息 500 服務器內部錯誤,無法完成請求 501 服務器不支持請求的功能,無法完成請求 502 作為網關或者代理工作的服務器嘗試執行請求時,從遠程服務器接收到了一個無效的響應 503 由于超載或系統維護,服務器暫時的無法處理客戶端的請求。延時的長度可包含在服務器的Retry-After頭信息中 504 充當網關或代理的服務器,未及時從遠端服務器獲取請求 505 服務器不支持請求的HTTP協議的版本,無法完成處理HTTP和HTTPS的區別
HTTP是超文本傳輸協議,信息是明文傳輸的,HTTPS是具有ssl/tls加密傳輸協議。默認端口不同,前者是80,后者是443。HTTPS比HTTP安全HTTPS協議需要到CA申請證書,需要一定費用瀏覽器的緩存機制
什么是瀏覽器緩存 Web緩存是指一個Web資源(如html頁面,圖片,js,數據等)存在于Web服務器和客戶端(瀏覽器)之間的副本。緩存會根據進來的請求保存輸出內容的副本;當下一個請求來到的時候,如果是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,還是向源服務器再次發送請求。比較常見的就是瀏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,如果網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。只有當網站明確標識資源已經更新,瀏覽器才會再次下載網頁。瀏覽器和網站服務器是根據緩存機制進行緩存的非HTTP協議定義的緩存機制瀏覽器緩存機制,其實主要就是HTTP協議定義的緩存機制(如: Expires; Cache-control等)。但是也有非HTTP協議定義的緩存機制,如使用HTML Meta 標簽,Web開發者可以在HTML頁面的<head>節點中加入<meta>標簽<meta http-equiv="Pragma" content="no-cache">上述代碼的作用是告訴瀏覽器當前頁面不被緩存,每次訪問都需要去服務器拉取。使用上很簡單,但只有部分瀏覽器可以支持,而且所有緩存代理服務器都不支持,因為代理不解析HTML內容本身。瀏覽器在第一次請求發生后,再次請求時:瀏覽器會先獲取該資源緩存的header信息,根據其中的expires和cache-control判斷是否命中強緩存),若命中則直接從緩存中獲取資源,包括緩存的header信息,本次請求不會與服務器進行通信; 如果沒有命中強緩存,瀏覽器會發送請求到服務器,該請求會攜帶第一次請求返回的有關緩存的header字段信息(Last-Modified/IF-Modified-Since、Etag/IF-None-Match),由服務器根據請求中的相關header信息來對比結果是否命中協商緩存,若命中,則服務器返回新的響應header信息更新緩存中的對應header信息,但是并不返回資源內容,它會告知瀏覽器可以直接從緩存獲取;否則返回最新的資源內容瀏覽器的強緩存和協商緩存
這里說的緩存是指瀏覽器(客戶端)在本地磁盤中對訪問過的資源保存的副本文件。瀏覽器緩存主要有以下幾個優點: 1. 減少重復數據請求,避免通過網絡再次加載資源,節省流量。 2. 降低服務器的壓力,提升網站性能。 3. 加快客戶端加載網頁的速度,提升用戶體驗。瀏覽器緩存分為強緩存和協商緩存,兩者有兩個比較明顯的區別: 1. 如果瀏覽器命中強緩存,則不需要給服務器發請求;而協商緩存最終由服務器來決定是否使用緩存,即客戶端與服務器之間存在一次通信。 2. 在chrome中強緩存(雖然沒有發出真實的http請求)的請求狀態碼返回是200(from cache);而協商緩存如果命中走緩存的話,請求的狀態碼是304(not modified)。不同瀏覽器的策略不同,在Fire Fox中,from cache狀態碼是304.強緩存 強緩存是利用http的返回頭中的Expires或者Cache-Control兩個字段來控制的,用來表示資源的緩存時間。 Expires:該字段是http1.0時的規范,它的值為一個絕對時間的GMT格式的時間字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。這個時間代表著這個資源的失效時間,在此時間之前,即命中緩存。這種方式有一個明顯的缺點,由于失效時間是一個絕對時間,所以當服務器與客戶端時間偏差較大時,就會導致緩存混亂。 Cache-Control:Cache-Control是http1.1時出現的header信息,主要是利用該字段的max-age值來進行判斷,它是一個相對時間,例如Cache-Control:max-age=3600,代表著資源的有效期是3600秒。cache-control除了該字段外,還有下面幾個比較常用的設置值:no-cache:不使用本地緩存。需要使用緩存協商,先與服務器確認返回的響應是否被更改,如果之前的響應中存ETag,那么請求的時候會與服務端驗證,如果資源未被更改,則可以避免重新下載。 no-store:直接禁止游覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源。 public:可以被所有的用戶緩存,包括終端用戶和CDN等中間代理服務器。 private:只能被終端用戶的瀏覽器緩存,不允許CDN等中繼緩存服務器對其緩存。Cache-Control與Expires可以在服務端配置同時啟用,同時啟用的時候Cache-Control優先級高。為什么要有Etag HTTP1.1中Etag的出現主要是為了解決幾個Last-Modified比較難解決的問題:1.一些文件也許會周期性的更改,但是他的內容并不改變(僅僅改變的修改時間)這個時候我們并不希望客戶端認為這個文件被修改了,而重新GET 2.某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒); 3.某些服務器不能精確的得到文件的最后修改時間。Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最后才決定是否返回304。200 OK(from cache)與304 Not Modified的區別200 OK( from cache )不向服務器發送請求,直接使用本地緩存文件。304 Not Modified則向服務器詢問,若服務器認為瀏覽器的緩存版本還可用,那么便會返回304。緩存類型 獲取資源形式 狀態碼 發送請求到服務器 強緩存 從緩存取 200(from cache) 否,直接從緩存取 協商緩存 從緩存取 304(Not Modified) 否,通過服務器來告知緩存是否可用用戶行為對緩存的影響 用戶操作 Expires/Cache-Control Last-Modied/Etag 地址欄回車 有效 有效 頁面鏈接跳轉 有效 有效 新開窗口 有效 有效 前進回退 有效 有效 F5刷新 無效 有效 Ctrl+F5強制刷新 無效 無效不能被緩存的請求
1. HTTP信息頭中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告訴瀏覽器不用緩存的請求 2. 需要根據Cookie,認證信息等決定輸入內容的動態請求是不能被緩存的 3. 經過HTTPS安全加密的請求 4. POST請求無法被緩存 5. HTTP響應頭中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的請求無法被緩存用戶行為對緩存的影響
qq、fire fox 、safari 、chrome 這幾個瀏覽器的訪問同一個頁面,不同的瀏覽器在 F5 刷新的時候 ,同一個文件 qq 、fire fox 瀏覽器會返回 `304 Not Nodified`,在請求頭中不攜帶 `Expires/Cache-Control`; 而 chrome 和 safari 刷新的時候,會返回 `200 from cache`, 沒有真正發起請求,走強緩存。可見不同的瀏覽器反饋是不一致的,所以下面表格中"F5刷新"時 `Expires/Cache-Control` 會無效我認為是存在一定爭議的。而 Ctrl + F5 強制刷新的時候,會暫時禁用強緩存和協商緩存。eslint規則
Eslint 是一個JavaScript驗證工具,有了它可以讓你的編輯器像ide一樣進行一些靜態的錯誤提示功能.npm install eslint -g某些文件關閉eslint檢測 在文件的最頂端加上注釋 /*eslint-disable*/關閉某一行代碼的eslint檢查 // eslint-disable-next-line.eslintrc.json配置rules選項git
(版本回退是什么命令,哪個命令查看已刪除的提交commitId)git-reset 版本回退git reset --hard xxx 回到上一個版本git reset --soft xxx 該命令將最近一次提交節點的提交記錄回退到暫存區git reset --mixed xxx 是將最近一次提交節點記錄回退到工作區git log 與 git reflog 查看歷史記錄(被刪除的歷史commit ID)git場景問題 提交暫存區git add 出錯 git reset HEAD <文件名> 回退提交本地倉庫 git commit出錯: 1.更改 commit 信息:git commit --amend -m“新提交消息” 2.漏提交:git add missed-file // missed-file 為遺漏提交文件git commit --amend --no-edit //--no-edit提交消息不會更改 3.git reset --hard commit_id git log查看提交的版本git revert 是提交一個新的版本 git fetch 將遠程主機的更新全部放到本地中git revert 和 git reset 的區別:(1)git revert是用一次新的commit來回滾之前的commit,git reset是直接刪除指定的commit。 (2)git revert是用一次逆向的commit“中和”之前的提交 ,合并的時候回滾的變化不會出現git reset是之間把某些commit在某個branch上刪除,合并時候回滾的commit會被引入node.js
1.Node不是一個后端語言,但是它可以做類似后端語言的功能 2.Node是使用谷歌V8引擎 3.Node是js的一個運行環境 4.Node具有非阻塞I/O 特點 5.Node采用了Common.js規范 node+koa2 node+express用于快速構建Node.js項目node.js 是一個基于 Chrome V8 引擎的 JavaScirpt 運行環境。Node.js使用了一個事件驅動、非阻塞式I/O的模型,使其輕量又高效**Node.js基于commonjs規范事件驅動: 任務執行,發布者,訂閱者,事件驅動 . 異步(非阻塞): 執行某一個任務的同時也可以執行其他任務 同步(阻塞): 執行某一個任務,這個任務如果沒有執行完成,其他任務必須等待 I/O: 輸入/輸出( 數據庫操作,文件系統操作等 ) - 服務器的環境 非阻塞I/O模型: 當使用Node.js來實現數據庫操作、文件系統等操作時,要進行的異步操作,異步操作的核心傳統實現方式就是回調函數和事件。Node.js的包管理工具npm優點:Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,異步編程,使其輕量又高效。 缺點:單進程,單線程,只支持單核cpu,不能充分的利用多核cpu服務器。一旦這個進程崩掉,那么整個web服務就崩掉了。內置模塊 http 是用于創建一個能夠處理和響應 http 響應的服務fs 用于對系統文件及目錄進行讀寫操作。 path 提供了一些用于處理文件路徑的小工具 Url:幫助我們對提交上來的url進行解析處理 querystring 提供用于解析和格式化 URL 查詢字符串的工具。qs.parse() qs.stringify()TS語法
TypeScript具有類型系統,且是JavaScript的超集。它可以編譯成普通的JavaScript代碼。 TypeScript支持任意瀏覽器,任意環境,任意系統并且是開源的。npm install -g typescripttsc --init 生成tsconfig.json配置文件基礎數據類型 number、string、boolean、null 、undefined any 表示任意類型 void 表示空類型 內置對象類型Array BooleanHTMLElementHTMLDivElement 自定義類型 接口 interface 類 泛型 未來的類型定義的時候不知道是什么類型,調用的時候才知道元組 1、數組中的數據類型必須和規定的類型順序對應起來 2、當使用越界索引給數組賦值的時候,會使用聯合類型(只要值是規定類型的某一種即可)。枚舉 enum類型是對JavaScript標準數據類型的一個補充never類型表示的是那些永不存在的值的類型。readonly:只讀屬性,不可修改sex? :表示sex是一個可傳屬性,可以有也可以沒有[propName: string]: any;表示新增的屬性可以是任意類型arr3: Array<number> 數組類型定義arr2: (number | string)[]fn (a: number, b: number) : number 函數類型定義linux命令
pwd:輸入pwd命令,Linux會輸出當前目錄。ls命令用來查看目錄的內容。cd命令用來改變所在目錄。cat命令可以用來合并文件,也可以用來在屏幕上顯示整個文件的內容。grep命令的最大功能是在一堆文件中查找一個特定的字符串。touch命令用來創建新文件cp命令用來拷貝文件mv命令用來移動文件rm命令用來刪除文件。 mkdir 創建文件夾創建目錄CSS3新特性
1 圓角邊框:border-radius 2 多背景圖:background 3 顏色和透明度:background: rgba(0,0,0,.5) 4 多列布局和彈性盒:display: flex 5 盒子的變幻(2D、3D)transform: translate(50px,100px);//移動 transform: rotate(); //旋轉 transform: scale(); //縮放transform: skew(); //傾斜 6 過渡 transition: width 1s linear 2s; 動畫:animation: myfirst 5s; @keyframes myfirst { 0% {background: block;} 25% {background: red;} 50% {background: yellow;} 100% {background: green;} } 7 引入web字體(在服務器端存儲) 8 媒體查詢 9 陰影 h 10 文字陰影 text-shadow div 11 盒子陰影 box-shadowHTML5 h5新特性
1 語義化標簽 section aside header nav 2 表單新特性:autofocus 自動獲取焦點placeholder 占位multipleautocomplete 自動補全,是否自動記錄之前提交的數據,以用于下一次輸入建議required 在表單提交時會驗證是否有輸入,沒有則彈出提示消息。min:限定輸入數字的最小值。max:限定輸入數字的最大值 3 video(視頻)和audio(音頻) 4 canvas畫布 5 webworker 就是為 JavaScript 創造多線程環境,允許主線程創建 Worker 線程,將一些任務分配給后者運行。 6 webscoket 服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。 7 拖拽apidragstart:源對象開始拖放。 drag:源對象拖放過程中。 dragend:源對象拖放結束。 過程對象: dragenter:源對象開始進入過程對象范圍內。 dragover:源對象在過程對象范圍內移動。 dragleave:源對象離開過程對象標準盒模型與怪異盒模型區別
標準盒模型一個塊的總寬度= width + margin(左右) + padding(左右) + border(左右) 怪異盒模型一個塊的總寬度= width + margin(左右)(即width已經包含了padding和 border值)CSS3彈性盒
彈性盒 display:flex(父元素添加) 彈性盒:控制子元素按主軸方向排列 彈性盒可以設置單獨內容水平垂直居中 父元素:display:flex 子元素:margin:auto 靈活元素:靈活元素即使是內聯元素也能設置寬高加父元素身上 1.flex-direction 屬性指定了彈性子元素在父容器中的位置。 row:橫向從左到右排列(左對齊),默認的排列方式。row-reverse:反轉橫向排列(右對齊,從后往前排,最后一項排在最前面。column:縱向排列。olumn-reverse:反轉縱向排列,從后往前排,最后一項排在最上面。 2.justify-content:flex-start/flex-end/space-between/space-around 3.align-items: 設置或檢索彈性盒子元素在側軸(縱軸)方向上的對齊方式。 center/flex-start/flex-end/baseline/stretch 4.flex-wrap:屬性用于指定彈性盒子的子元素換行方式。nowrap/wrap/wrap-reverse 5.align-content:設置各個行的對齊: stretch - 默認。各行將會伸展以占用剩余的空間。flex-start - 各行向彈性盒容器的起始位置堆疊。flex-end - 各行向彈性盒容器的結束位置堆疊。center -各行向彈性盒容器的中間位置堆疊。space-between -各行在彈性盒容器中平均分布。space-around 加子元素身 1、align-self:屬性用于設置彈性元素自身在側軸(縱軸)方向上的對齊方式。align-self: auto | flex-start | flex-end | center | baseline | stretchflex 屬性用于指定彈性子元素如何分配空間。1: 計算值為 1 1 autoinitial: 計算值為 0 1 autonone:計算值為 0 0 auto inherit:從父元素繼承 2、第一個參數表示: flex-grow 定義項目的放大比例,默認為0,即如果存在剩余空間,也不放大 3、第二個參數表示: flex-shrink 定義了項目的縮小比例,默認為1,即如果空間不足,該項目將縮小 4、第三個參數表示: flex-basis給上面兩個屬性分配多余空間之前, 計算項目是否有多余空間, 默認值為 auto, 即項目本身的大小CSS元素居中
1.使用margin進行固定長度的偏移 2.使用絕對定位并進行偏移(已知寬高) #father{ position:relative; } #son{ position: absolute; left:50%; top:50%; margin-left: -子元素的寬/2; margin-top: -子元素的高/2; } 3.使用絕對定位并margin自適應進行居中 #father{ position:relative;} #son{position: absolute; left: 0; top: 0; right: 0; bottom: 0; margin:auto; }(啊不斯陸特) 4.使用彈性盒子來實現居中 #father{ display: flex; justify-content: center; align-items: center; }(加斯特佛) (額來) (哎特木) 5.使用定位 + transform #father{ position:relative;} #son{ position: absolute; left: 50%; top: 50%; transform:translate(-50% -50%) }6.table-cell布局 因為table-cell相當與表格的td,td為行內元素,無法設置寬和高,所以嵌套一層,嵌套一層必須設置display: inline-block;CSS幾種定位的區別 relative, absolute, fixed
1、相對定位position:relative;參考物是自己,不脫離文檔流(初始位置仍然占據空 間),top:100px; 給正值是向該容器的中心點移動;2、絕對定位position:absolute; 參考物是外層具有position屬性的元素, 如果向外 都么有找到最后會參考body/html做定位3、固定定位position:fixed; 參考物是可視窗口 4、粘性定位(了解)position:sticky; 是絕對定位+固定定位div外邊距重疊的原因及解決辦法
情況一:兩個div垂直邊界相鄰,margin會等于二者中margin較大的值 解決方案: 1.position:absolute 2.float:left 情況二:子元素在父元素內,子元素的margin-top會與父元素的margin-top重疊,值等于二者中較大的,如果只有子元素設置了margin-top,則顯示為父元素的margin-top 解決方案: 1.給父元素設置border(給子元素設置邊框沒有用) 2.給父元素設置padding值 3.給父元素或子元素添加float:left 4.給父元素或子元素添加position:absolute 5.給父元素添加overflow:hidden 6.給子元素添加display:inline-block 情況三:一個空白元素自身的margin-top和margin-bottom會重疊,值為而這種較大的 解決方案: 1.設置透明borderpx,em,rem,pt的區別
1、px實際上就是像素,用px設置字體大小時,比較穩定和精確 2、em就是根據基準來縮放字體的大小 3、rem是相對于根元素字體大小來顯示的 4、pt的大小等于1英寸的1/72 瀏覽器的兼容性除了IE6-IE8,其他的瀏覽器都支持em和rem,px所有瀏覽器都支持CSS的BFC
1、什么是BFC BFC(Block formatting context)直譯為“塊級格式化上下文”。 他是一個獨立的渲染區域,也可以理解成一個獨立的容器,并且這個容器里box的布局,與這個容器外的毫不相干。 2、BFC渲染規則 a.內部的box會在垂直方向,一個接一個的放置 b.box垂直方向的距離由margin決定。屬于同一個BFC的兩個相鄰box的margin會發生重 疊 c.每個元素的margin box的左邊,與包含塊border box的左邊相接觸(對于從左往右的格 式化,否則相反)。 即使存在浮動也是如此 d.BFC的區域不會與float box重疊 e.BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素。反之 也如此 f.計算BFC的高度時,浮動元素也參與計算 3、如何產生BFC a.根元素 b.float屬性不為none c.position為absolute或fixed d.display為inline-block, table-cell,table-caption,flex,inline-flex e.overflow不為visible 4、BFC的作用 a.自適應兩欄布局 b.清除內部浮動 c.防止垂直margin重疊(放在兩個BFC里)兼容問題
1)css瀏覽器兼容問題(比如設置元素透明度,ie瀏覽器使用濾鏡實現,filter :progid:DXlmage Transform.Microsoft.Alpha(style=0,opacity=50);非IE瀏覽器 opacity:0.5) 解決方法:現在前端開發已經出現了非常多的框架和類庫用于瀏覽器的兼容問題,比如jq類 庫,解決獲取元素中包含的所有文本內容兼容性問題,$(“element”).text(“element text”) 2)css3瀏覽器前綴問題 -ms-:ie瀏覽器 -o-:opera歐朋瀏覽器 -webkit-:谷歌瀏覽器 -moz-:火狐瀏覽器工作中遇到的困難 1)IE6中高度不對問題 在div中給定了高度為1px,其它瀏覽器顯示正常,可是ie6中顯示的高度就不對了,這時我 給樣式表中加 了個font-size:0px;line-height:0px;就好了 2)把border設為“0”像素雖然在頁面上看不見,但按border默認值理解,瀏覽器依然對 border- width/border-color進行了渲染,即已經占用了內存值把border設為“none”即沒有,瀏覽器解析“none”時將不作出渲染動作,即不會消耗內存移動端適配
1.Media Queries 通過查詢設備的寬度來執行不同的 css 代碼,最終達到界面 的配置 2.Flex彈性布局 3.rem + viewport 縮放 實現原理 根據rem將頁面放大dpr倍, 然后viewport設置為1/dpr. 4、rem實現 移動端適配方案: 1)viewport(scale=1/dpr) dpr:備像素比 2)rem 3)flex 4)vm/vh以iphone8為例,iphone8的CSS像素為375px*677px,DPR是2,所以其設備像素為750px*1354px750(px) / 375(px) = 2什么是CSS預處理器?優點是什么
css預處理器用一種專門的編程語言,進行web頁面樣式設計,然后在編譯成正常的css文件, 以供項目使用 在css中使用變量、簡單的邏輯程序、函數。可以讓你的css更加簡潔、適應性更強、可讀性更佳、更易于代碼的維護0.5px線怎么實現(單邊框0.5px)
方式一:border + border - img + 線性漸變linear-gradient 方式二:定位 + 偽元素 + background + 線性漸變linear-gradient 方式三:定位 + 偽元素 + transform縮放(scale)CSS布局 - 左側寬度固定,右側自適應
方法一: 設置絕對定位寬度固定區域設置 position:absolute+ left/right+ top + width自適應區域設置 margin-left/margin-right: 固定寬度區域的寬度。注意:(1)若左側固定的高度大于右側自適應區域高度頁面布局就變成這樣了:(測試布局區域緊挨著自適應區域的下方,蓋住了部分固定區域)簡單粗暴的就是測試布局區域定位的top值直接設置為兩個區域最高的高度值(2)若左側固定的高度大于右側自適應區域高度,且測試區域不進行定位 方法二:浮動布局左側固定區域浮動+寬度,右側自適應區域 設置margin-left :左側寬度值。 方法三:BFC規則左側固定區域浮動+寬度,右側自適應區域(非浮動元素)設置overflow:hidden。CSS布局 - 左右側寬度固定,中間自適應
1、絕對定位布局:position + margin 缺點: 如果中間欄含有最小寬度限制,或是含有寬度的內部元素,當瀏覽器寬度小到一定程度,會發生層重疊的情況。 2、浮動布局: float + margin 3、flex布局高度由內容決定。 4、table布局高度由內容決定。 5、Grid網格布局 6、圣杯布局 7、雙飛翼布局 8、對比圣杯布局和雙飛翼布局 (1)都是左右欄定寬,中間欄自適應的三欄布局,中間欄都放到文檔流前面,保證先行渲染。 (2)解決方案基本相似:都是三欄全部設置左浮動float:left,然后分別結局中間欄內容被覆蓋的問題。 (3)解決中間欄內容被覆蓋問題時,圣杯布局設置父元素的padding,雙飛翼布局在中間欄嵌套一個div,內容放到新的 div中,并設置margin,實際上,雙飛翼布局就是圣杯布局的改進方案。webpack 打包優化 怎么減少打包時間
多進程打包 - 速度分析 多進程壓縮 - 體積分析 資源CDN 動態polyfill - 根據不同瀏覽器,動態載入需要的polyfill,大幅度減少構建體積split-thunk 前端構建項目中,為了提高打包效率,往往將第三庫與業務邏輯代碼分開打包,因為第三方庫往往不需要經常打包更新。webpack建議使用CommonsChunk 來單獨打包第三方庫webpack loader(轉換器)和plugin(插件)有什么區別:loader它是一個轉換器,將A文件進行編譯形成B文件,這里操作的是文件,比如將A.scss轉換為A.css,單純的文件轉換過程plugin是一個擴展器,它豐富了webpack本身,針對是loader結束后,webpack打包的整個過程,它并不直接操作文件,而是基于事件機制工作,會監聽webpack打包過程中的某些節點,執行廣泛的任務loader:優雅降級,圖片打包 plugin:html產出:把public下面的html文件打包到build里面的index.html并自動引入app.jscss抽離靜態資源拷貝繼承的6種方式
1.原型鏈繼承重點:讓新實例的原型等于父類的實例。特點:1、實例可繼承的屬性有:實例的構造函數的屬性,父類構造函數屬性,父類原型的屬性。(新實例不會繼承父類實例的屬性!)缺點:1、新實例無法向父類構造函數傳參。2、繼承單一。3、所有新實例都會共享父類實例的屬性。(原型上的屬性是共享的,一個實例修改了原型屬性,另一個實例的原型屬性也會被修改!) 2.借用構造函數繼承重點:用.call()和.apply()將父類構造函數引入子類函數(在子類函數中做了父類函數的自執行(復制))特點:1、只繼承了父類構造函數的屬性,沒有繼承父類原型的屬性。2、解決了原型鏈繼承缺點1、2、3。3、可以繼承多個構造函數屬性(call多個)。4、在子實例中可向父實例傳參。缺點:1、只能繼承父類構造函數的屬性。2、無法實現構造函數的復用。(每次用每次都要重新調用)3、每個新實例都有父類構造函數的副本,臃腫。 3.組合繼承(組合原型鏈繼承和借用構造函數繼承) 重點:結合了兩種模式的優點,傳參和復用特點:1、可以繼承父類原型上的屬性,可以傳參,可復用。2、每個新實例引入的構造函數屬性是私有的。缺點:調用了兩次父類構造函數(耗內存),子類的構造函數會代替原型上的那個父類構造函數。 4.原型式繼承重點:用一個函數包裝一個對象,然后返回這個函數的調用,這個函數就變成了個可以隨意增添屬性的實例或對象。 object.create()就是這個原理。特點:類似于復制一個對象,用函數來包裝。缺點:1、所有實例都會繼承原型上的屬性。2、無法實現復用。(新實例屬性都是后面添加的) 5.寄生式繼承重點:就是給原型式繼承外面套了個殼子。優點:沒有創建自定義類型,因為只是套了個殼子返回對象(這個),這個函數順理成章就成了創建的新對象。缺點:沒用到原型,無法復用。 6.寄生組合式繼承(常用)重點:修復了組合繼承的問題寄生:在函數內返回對象然后調用組合:1、函數的原型等于另一個實例。2、在函數中用apply或者call引入另一個構造函數,可傳參阻止冒泡和取消默認事件(默認行為)
防止事件捕獲和冒泡: w3c的方法是e.stopPropagation() IE則是使用e.cancelBubble = true取消默認事件 w3c的方法是e.preventDefault() IE則是使用e.returnValue = falsejQuery用法 阻止默認事件 return false (不停止冒泡)作用域和作用域鏈
變量的作用域無非就是兩種: 全局變量和局部變量。javascript的作用域是相對函數而言的,可以稱為函數作用域全局作用域: 最外層函數定義的變量擁有全局作用域,即對任何內部函數來說,都是可以訪問的局部作用域: 局部作用域一般只在固定的代碼片段內可訪問到,而對于函數外部是無法訪問的作用域鏈: 根據在內部函數可以訪問外部函數變量的這種機制,用鏈式查找決定哪些數據能被內部函數訪問。作用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象作用域鏈中的下一個對象來自于外部環境,而在下一個變量對象則來自下一個外部環境,一直到全局執行環境全局執行環境的變量對象始終都是作用域鏈上的最后一個對象遍歷數組的方式
1.for循環 使用臨時變量,將長度緩存起來,避免重復獲取數組長度,當數組較大時優化效果才會比較明顯。2.foreach循環 遍歷數組中的每一項,沒有返回值,對原數組沒有影響,不支持IE。 有一些局限,不能continue跳過或者break終止循環3.map循環 有返回值,可以return出來 map的回調函數中支持return返回值 并不影響原來的數組,return的是新數組4.for of遍歷 可以正確響應break、continue和return語句5.filter遍歷 不會改變原始數組,返回新數組6.every遍歷 every()是對數組中的每一項運行給定函數,如果該函數對每一項返回true,則返回true。7.some遍歷 some()是對數組中每一項運行指定函數,如果該函數對任一項返回true,則返回true。8.reduce reduce()方法接收一個函數作為累加器(accumulator),數組中的每個值(從左到右)開始縮減,最終為一個值。9.reduceRight reduceRight()方法的功能和reduce()功能是一樣的, 不同的是reduceRight()從數組的末尾向前將數組中的數組項做累加。10.find find()方法返回數組中符合測試函數條件的第一個元素。否則返回undefined 11.findIndex 對于數組中的每個元素,findIndex方法都會調用一次回調函數(采用升序索引順序),直到有元素返回 true。 只要有一個元素返回 true,findIndex立即返回該返回 true 的元素的索引值。 如果數組中沒有任何元素返回 true,則 findIndex 返回 -1。 findIndex 不會改變數組對象。12.keys,values,entries ES6 提供三個新的方法 —— entries(),keys()和values() —— 用于遍歷數組。 它們都返回一個遍歷器對象,可以用for...of循環進行遍歷, 唯一的區別是keys()是對鍵名的遍歷、values()是對鍵值的遍歷,entries()是對鍵值對的遍歷數據分頁
前端的話,定義一個新的數組for循環判斷,有個公式,計算起始頁和終止頁的。 符合條件push僅數組中,后端就是用limt判斷數組排序
1. 普通數組排序 js中用方法sort()為數組排序。sort()方法有一個可選參數,是用來確定元素順序的函數。如果這個參數被省略,那么數組中的元素將按照ASCII字符順序進行排序。 2. 冒泡排序 (1)比較相鄰的元素。如果第一個比第二個大,就交換他們兩個位置。 (2)對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。在這一點,最后的元素應該會是最大的數。 (3)針對所有的元素重復以上的步驟,除了最后一個。 (4)持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。 3. 快速排序:遞歸思想,兩邊快速的排序,冒泡排序的改進 (1)選擇數組中間數作為基數,并從數組中取出此基數; (2)準備兩個數組容器,遍歷數組,逐個與基數比對,較小的放左邊容器,較大的放右邊容器; (3)進行相同的操作,直到數組中只有一個元素時,返回該數組。 4. 插入排序 (1)從第一個元素開始,該元素可以認為已經被排序 (2)取出下一個元素,在已經排序的元素序列中掃描 (3)如果該元素(已排序)大于新元素,將該元素移到下一位置 (4)重復步驟3,直到找到已排序的元素小于或者等于新元素的位置 (5)將新元素插入到下一位置中 (6)重復步驟2 5. 選擇排序 (1)在未排序序列中找到最小(大)元素 (2)并存放到排序序列的起始位置 (3)然后,再從剩余未排序元素中繼續尋找最小(大)元素 (4)然后放到已排序序列的末尾。 (5)以此類推數組合并
1、concatjs的Array對象提供了一個叫concat()方法,連接兩個或更多的數組,并返回結果。var c = a.concat(b); //c=[1,2,3,4,5,6];這里有一個問題,concat方法連接a、b兩個數組后,a、b兩個數組的數據不變,同時會返回一個新的數組。這樣當我們需要進行多次的數組合并時,會造成很大的內存浪費,如果是數據量比較小的時候,還可以勉強用,如果數據量大的時候,這個就不妥了,所以這個方法肯定不是最好的。2、for循環 大概的思路是:遍歷其中一個數組,把該數組中的所有元素依次添加到另外一個數組中。直接上代碼:for(var i in b) { a.push ( b[i] );}3、apply函數的apply方法有一個特性,那就是func.apply(obj,argv),argv是一個數組。a.push.apply(a,b);調用a.push這個函數實例的apply方法,同時把,b當作參數傳入,這樣a.push這個方法就會遍歷b數組的所有元素,達到合并的效果。這里可能有點繞,我們可以把b看成[4,5,6],變成這樣:a.push.apply(a,[4,5,6]);然后上面的操作就等同于:a.push(4,5,6);這樣就很清楚了!數組方法
push,在數組末尾添加一位或多位元素 pop,刪除數組最后一位元素 unshift,在數組的開頭添加一位或多位元素 shift,刪除數組的第一位元素 join,將數組轉換為字符串 reserve,反轉數組元素的順序 sort,對數組進行排序 concat,連接兩個或多個數組 splice,添加或刪除數組中的元素 slice,從已有的數組中返回選定的元素 indexOf、lastIndexOf,查找數組中的元素 forEach,對數組進行遍歷循環,對數組中每一項運行指定的函數 map,迭代數組 filter,對數組中的元素進行指定的檢查返回符合條件的元素放入一個新數組中 every,測試所有元素是否都符合指定條件 some,測試某些元素是否符合指定條件 reduce,接收一個函數作為累加器,數組中的每個值開始縮減,最終計算為一個值 toString,將數組轉換為字符串數組去重
使用ES6 Setvar arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];arr = Array.from(new Set(arr)); [...new Set(arr)]console.log(arr);//[1, 4, 2, 3, 6]使用indexOfvar arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];var newArr = [];arr.forEach((item) => {newArr.indexOf(item) === -1 ? newArr.push(item) : "";});console.log(newArr);//[1, 4, 2, 3, 6]使用lastIndexOfvar arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];var newArr = [];arr.forEach((item) => {newArr.lastIndexOf(item) === -1 ? newArr.push(item) : "";});console.log(newArr);//[1, 4, 2, 3, 6]使用雙重for循環加splice方法var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];for (var i = 0; i < arr.length; i++) {for (var j = i + 1; j < arr.length; j++) {if (arr[i] == arr[j]) {arr.splice(j,1);j--;}}}console.log(arr);//[1, 4, 2, 3, 6]使用forEach和includes方法var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];var newArr = [];arr.forEach((item) => {newArr.includes(item) ? "" : newArr.push(item);});console.log(newArr);//[1, 4, 2, 3, 6]使用fliter和includes方法var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];var newArr = [];arr.filter((item) => {newArr.includes(item) ? "" : newArr.push(item);});console.log(newArr);//[1, 4, 2, 3, 6]for…of 原理
for...of 是ES6引入用來遍歷所有數據結構的統一方法。這里的所有數據結構只指具有iterator接口的數據。 一個數據只要部署了 Symbol.iterator,就具有了 iterator接口,就可以使用 for...of 循環遍歷它的成員。 也就是說,for...of循環內部調用的數據結構為Symbol.iterator方法。 部署在 Symbol.iterator 屬性,或者說,一個數據結構只要具有 Symbol.iterator 屬性,就認為是"可遍歷的"。Iterator(伊特瑞特):遍歷器(Iterator)就是這樣一種機制。它是一種接口,為各種不同的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 接口,就可以完成遍歷操作(即依次處理該數據結構的所有成員)。通俗點理解就是為了解決不同數據結構遍歷的問題,引入了Iterator.Iterator的特點:各種數據結構,提供一個統一的、簡便的訪問接口使得數據結構的成員能夠按某種次序排列ES6 創造了一種新的遍歷命令for...of循環,Iterator 接口主要供for...of消費原生具備 Iterator 接口的數據結構如下。ArrayMapSetString:字符串是一個類似數組的對象,也原生具有 Iterator 接口。TypedArray:通俗理解:ArrayBuffer是一片內存空間,不能直接引用里面的數據,可以通過TypedArray類型引用,用戶只能通過TypedArray使用這片內存,不能直接通過ArrayBuffer使用這片內存函數的 arguments 對象NodeList 對象除了原生具備Iterator 接口的數據之外,其他數據結構(主要是對象)的 Iterator 接口, 都需要自己在Symbol.iterator屬性上面部署,這樣才會被for...of循環遍歷。對象(Object)之所以沒有默認部署 Iterator 接口,是因為對象的哪個屬性先遍歷,哪個屬性后遍歷是不確定的,需要開發者手動指定。本質上,遍歷器是一種線性處理,對于任何非線性的數據結構,部署遍歷器接口,就等于部署一種線性轉換。不過,嚴格地說,對象部署遍歷器接口并不是很必要,因為這時對象實際上被當作 Map 結構使用,ES5 沒有 Map 結構,而 ES6 原生提供了。一個對象如果要具備可被for...of循環調用的 Iterator 接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法(原型鏈上的對象具有該方法也可)。遍歷對象的方式
第一種: for...in第二種: 1)Object.keys(obj) 2)Object.values(obj) 參數:obj:要返回其枚舉自身屬性的對象 返回值:一個表示給定對象的所有可枚舉屬性的字符串數組。第三種: 使用Object.getOwnPropertyNames(obj) 返回一個數組,包含對象自身的所有屬性(包含不可枚舉屬性) 遍歷可以獲取key和valuemap與filter和forEach的區別
map 與 filter 區別:相同點:filter 和 map 都是對數組的操作,均返回一個新的數組不同點:filter是滿足條件的留下,是對原數組的過濾;map則是對原數組的加工,映射成一對一映射的新數組map 與 forEach 區別:map()會分配內存空間存儲新數組并返回,forEach()不會返回數據(undefined)。forEach()允許callback更改原始數組的元素。map()返回新的數組。面向對象編程
面向對象編程: 將所需要做的功能抽象成一個“對象”,然后一遍遍地調用這個對象來完成你想要的功能。面向對象的三大特征: 1.封裝 我們平時所用的方法和類都是一種封裝,當我們在項目開發中,遇到一段功能的代碼在好多地方重復使用的時候,我們可以把他單獨封裝成一個功能的方法,這樣在我們需要使用的地方直接調用就可以了。2.繼承 繼承在我們的項目開發中主要使用為子類繼承父類,繼承會繼承父類的實例屬性和實例方法,并不會繼承靜態屬性和靜態方法,并且靜態方法只能通過類名去調用。3.多態 多態的具體表現為方法重載和方法重寫: 方法重載: 重載是指不同的函數使用相同的函數名,但是函數的參數個數或類型不同。調用的時候根據函數的參數來區別不同的函數 方法重寫: 重寫(也叫覆蓋)是指在派生類中重新對基類中的虛函數(注意是虛函數)重新實現。即函數名和參數都一樣,只是函數的實現體不一樣三大特征的優點: 封裝: 封裝的優勢在于定義只可以在類內部進行對屬性的操作,外部無法對這些屬性指手畫腳,要想修改,也只能通過你定義的封裝方法;繼承: 繼承減少了代碼的冗余,省略了很多重復代碼,開發者可以從父類底層定義所有子類必須有的屬性和方法,以達到耦合的目的;多態: 多態實現了方法的個性化,不同的子類根據具體狀況可以實現不同的方法,光有父類定義的方法不夠靈活,遇見特殊狀況就捉襟見肘了window.onload與document.ready的區別
1.執行時間window.onload必須等到頁面內包括圖片的所有元素加載完畢后才能執行。 $(document).ready()是DOM結構繪制完畢后就執行,不必等到加載完畢。2.編寫個數不同window.onload不能同時編寫多個,如果有多個window.onload方法,只會執行一個 $(document).ready()可以同時編寫多個,并且都可以得到執行3.簡化寫法window.onload沒有簡化寫法 $(document).ready(function(){})可以簡寫成$(function(){});this
this代表函數運行時,自動生成的一個內部對象,只能在函數內部使用, 隨著函數使用場合的不同,this的值會發生變化。指向: 1.在方法中,this 表示該方法所屬的對象。 2.如果單獨使用,this 表示全局對象。 3.函數中,this 表示全局對象。 4.嚴格模式下,this 是未定義的(undefined)。 5.在事件中,this 表示接收事件的元素。 6.類似 call() 和 apply() 方法可以將 this 引用到任何對象。 7.箭頭函數本身是沒有this和arguments的,引用的this實際上是調用的是定義時的上一層作用域的this。<!DOCTYPE>
<!DOCTYPE> 聲明位于文檔中的最前面的位置,處于 <html> 標簽之前。<!DOCTYPE> 聲明不是一個 HTML 標簽;它是用來告知 Web 瀏覽器頁面使用了哪種 HTML 版本。在 HTML 4.01 中,<!DOCTYPE> 聲明需引用 DTD (文檔類型聲明), 因為 HTML 4.01 是基于 SGML (Standard Generalized Markup Language 標準通用標記語言)。 DTD 指定了標記語言的規則,確保了瀏覽器能夠正確的渲染內容。HTML5 不是基于 SGML,因此不要求引用 DTD。給您 HTML 文檔添加 <!DOCTYPE> 聲明,確保瀏覽器能夠預先知道文檔類型。CSS position屬性
absolute:生成絕對定位的元素,相對于 static 定位以外的第一個父元素進行定位。 fixed :生成固定定位的元素,相對于瀏覽器窗口進行定位。 relative:生成相對定位的元素,相對于其正常位置進行定位。 static :默認值。沒有定位。 sticky :粘性定位,該定位基于用戶滾動的位置。 inherit :規定應該從父元素繼承 position 屬性的值。js的解構
解構定義:允許按照一定模式,從數組和對象中提取值,對變量進行賦值。 解構必須滿足的條件:(模式匹配),只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。 主要介紹2種解構常用的類型:數組解構和對象解構。數組解構:1.數組中的變量個數比賦值的數組中個數少的解構:2.數組中的變量個數比賦值的數組中個數多的解構:3.數組中的變量中有空字符的解構:上面的3種數組解構,賦值的數組的數值按位賦值給另外一方數組中的變量4.數組中的變量中有不定參數(有些時候也叫擴展運算符)的解構:需要注意的是不定參數必須放最后。5.數組中的變量中有默認值的解構:如果賦值的數組個數沒有另外一方數組變量個數多,并且變量數組有默認,沒有進行賦值用默認,進行賦值用賦值的對象的解構:兩方也需要相同類型的括號,對象結構使用大括號{} 普通對象解構:對象跟數值解構不同的一點,對象解構不是按位去賦值,是根據鍵名(屬性名) 來進行賦值 有默認值的對象解構跟數組的默認值差不多,有賦值就用賦值的,沒有就用默認值 有不定參數的對象解構跟數組的不定參數差不多,不定參數放在最后,不定參數創建一個對象接受的剩下的鍵名鍵值(屬性名屬性值) 有嵌套的對象解構主要注意嵌套層次是不是賦值一方對象的嵌套層次相同。js實現輪播圖思路
1.圖片移動實現原理: 利用浮動將所有所有照片依次排成一行,給這一長串圖片添加一個父級的遮罩,每次只顯示一張圖,其余的都隱藏起來。對圖片添加絕對定位,通過控制left屬性,實現照片的移動。2.圖片移動動畫原理: 從a位置移動到b位置,需要先計算兩點之間的差值,通過差值和時間間隔,計算出每次移動的步長,通過添加定時器,每次移動相同的步長,實現動畫效果。3.圖片定位停止原理: 每一張照片都有相同的寬度,每張照片都有一個絕對的定位數值,通過檢測定每次移動后,照片當前位置和需要到達位置之間的距離是否小于步長,如果小于,說明已經移動到位,可以將定時器清除,來停止動畫。4圖片切換原理: 在全局設置一個變量,記錄當前圖片的位置,每次切換或跳轉時,只需要將數值修改,并調用圖片頁數轉像素位置函數,再調用像素運動函數即可。5.自動輪播原理: 設置定時器,一定時間間隔后,將照片標記加1,然后開始切換。6.左右點擊切換原理: 修改當前位置標記,開始切換。這里需要注意與自動輪播之間的沖突。當點擊事件觸發之后,停止自動輪播計時器,開始切換。當動畫結束后再次添加自動輪播計時器。7.無縫銜接原理: 需要無縫銜接,難度在于最后一頁向后翻到第一頁,和第一頁向前翻到最后一頁。由于圖片的基本移動原理。要想實現無縫銜接,兩張圖片就必須緊貼在一起。所以在第一張的前面需要添加最后一張,最后一張的后面需要添加第一張。首先判斷圖片的位置,是否移動到位。當滿足當前位置,與預定位置之間的距離小于一步時,認定為移動到位,并把圖片直接定位到預定位置。然后判斷,圖片的位置是否需要跳轉。 ps:這里一定要在圖片運動函數結束后,在進行跳轉。8.預防鬼畜原理: 始終保證輪播圖的運動動畫只有一個,從底層杜絕鬼畜。需要在每次動畫開始之前,嘗試停止動畫定時器,然后開始為新的動畫添加定時器。輪播圖鬼畜的本質原因就是,同一時間多個定時器添加在圖片上,這些定時器直接相互沖突,造成圖片的抖動。 解決方法:每次執行運動函數之前,先嘗試清除一下,上一個輪播圖的定時器。確保同時觸發運動函數時,只有一個定時器在工作。9.預防暴力點擊原理: 如果用戶快速點擊觸發事件,會在短時間內多次調用切換函數,雖然動畫函數可以保證,不會發生鬼畜,但在照片從最后一張到第一張的切換過程,不會按照正常的輪播,而是實現了跳轉。所以需要通過添加口令的方式來,限制用戶的點擊。當用戶點擊完成后,口令銷毀,動畫結束后恢復口令。10.小圓點的位置顯示原理: 每次觸發動畫時,通過全局變量標記,獲取當前頁數,操作清除所有小圓點,然后指定一頁添加樣式。11.點擊觸發跳轉的原理: 類似于左右點擊觸發,只是這是將全局頁面標記,直接修改,后執行動畫。需要避免與自動輪播定時器的沖突。js數組和對象的擴展
1.Array.from()方法用于將對象轉為真正的數組(類數組轉數組) 2.Array.of()方法用于將一組值,轉換為數組。console.log(Array.of(1,2,3,4,4,50));//[1, 2, 3, 4, 4, 50] 3.Object.assign(目標對象,對象1,對象2)用于對象的合并,將源對象的所有可枚舉屬性,復制到目標對象。(淺拷貝)js提升
一、提升(Hosting) 簡單說就是在js代碼執行前引擎會先進行預編譯,預編譯期間會將變量聲明與函數聲明提升至其對應作用域的最頂端。二、變量提升 在ES6之前,JavaScript沒有塊級作用域(一對花括號{}即為一個塊級作用域),只有全局作用域和函數作用域。 變量提升即將變量聲明提升到它所在作用域的最開始的部分。 變量聲明的提升是以變量所處的第一層詞法作用域為“單位”的,即全局作用域中聲明的變量會提升至全局最頂層,函數內聲明的三、函數提升 即函數提升只會提升函數聲明,而不會提升函數表達式。四、為什么會有提升? 函數提升就是為了解決相互遞歸的問題,大體上可以解決像ML語言這樣自下而上的順序問題。 大概是說,變量提升是人為實現的問題,而函數提升在當初設計時是有目的的。比較redux和vuex的區別
redux和vuex的區別1)vuex是redux的基礎上進行改變,對倉庫的管理更加明確2)使用mutation來替換redux中的reducer3)vuex有自動渲染的功能,所以不需要更新redux和flux的區別1)redux是flux中的一個實現2))在redux中我們只能定義一個store,在flux中我們可以定義多個3)在redux中,store和dispatch都放到了store,結構更加清晰4)在redux中本身就內置State對象,對倉庫的管理更加明確CSS display 屬性
| block | 此元素將顯示為塊級元素,此元素前后會帶有換行符。 | |
| inline | 默認。此元素會被顯示為內聯元素,元素前后沒有換行符。 | |
| inline-block | 行內塊元素。(CSS2.1 新增的值) | |
| list-item | 此元素會作為列表顯示。 | |
| run-in | 此元素會根據上下文作為塊級元素或內聯元素顯示。 | |
| compact | CSS 中有值 compact,不過由于缺乏廣泛支持,已經從 CSS2.1 中刪除。 | |
| marker | CSS 中有值 marker,不過由于缺乏廣泛支持,已經從 CSS2.1 中刪除。 | |
| table | 此元素會作為塊級表格來顯示(類似 ),表格前后帶有換行符。 | |
| inline-table | 此元素會作為內聯表格來顯示(類似 ),表格前后沒有換行符。 | |
| table-row-group | 此元素會作為一個或多個行的分組來顯示(類似 | |
| table-header-group | 此元素會作為一個或多個行的分組來顯示(類似 | |
| table-footer-group | 此元素會作為一個或多個行的分組來顯示(類似 | |
| table-row | 此元素會作為一個表格行顯示(類似 | |
| table-column-group | 此元素會作為一個或多個列的分組來顯示(類似 | |
| table-column | 此元素會作為一個單元格列顯示(類似 | |
| table-cell | 此元素會作為一個表格單元格顯示(類似 | 和 | )
| table-caption | 此元素會作為一個表格標題顯示(類似 | |
| inherit | 規定應該從父元素繼承 display 屬性的值。 |
CSS選擇符
CSS選擇符id選擇器(#myid)類選擇器(.myclassname)標簽選擇器(div)相鄰選擇器(h1+p)子選擇器(ul>li)后代選擇器(li a)群組選擇器(div,p{})通配符選擇器(*)屬性選擇器(a[title=""])偽類選擇器(a:hover{}或者li:nth-child{})CSS中link和@import的區別
link屬于HTML標簽,@import是CSS提供的頁面被加載時,link引用的css文件會同時被加載,而@import引用的css文件要等到頁面被加載完畢再加載import只在IE5以上才能識別,link是HTML標簽,無兼容問題link 引入樣式的權重大于@import 的引用CSS中display:none、visibility:hidden和opacity:0;的區別
display:none;隱藏對應的元素,在文檔布局中不再給它分配空間,它各邊的元素會合攏。visibility:hidden;隱藏對應的元素,但在文檔布局中仍保留原來的空間。opacity:0;內容不可見,占據空間。CSS中rgba()和opacity的透明效果區別
rgba()和 opacity 都能實現透明效果,但最大的不同是 opacity 作用于元素,以及元素內的所有內容的透明度;rgba()只作用于元素的顏色或其背景色(設置 rgba 透明的元素的子元素不會繼承透明效果)。CSS的外邊距重疊
在 CSS 當中,相鄰的兩個盒子(可能是兄弟關系也可能是祖先關系)的外邊距可以結合成一個單獨的外邊距。這種合并外邊距的方式被稱為折疊,并且因而所結合成的外邊距稱為折疊外邊距。折疊結果遵循下列計算規則如下兩個相鄰的外邊距都是正數時,折疊結果是它們兩者之間較大的值。兩個相鄰的外邊距都是負數時,折疊結果是兩者絕對值的較大值。兩個外邊距一正一負時,折疊結果是兩者之和。CSS清除浮動
清除浮動主要是為了解決父元素因為子元素浮動引起的內部高度為0的問題。 常見清除浮動的方法額外標簽法。在最后浮動元素后加一個標簽,設置clear:both;給父級元素設置高度給父級元素添加浮動給父級元素設置overflow屬性為hidden或者auto使用after偽元素清除.clearfix:after {/*偽元素是行內元素 正常瀏覽器清除浮動方法*/content: "";display: block;height: 0;clear: both;visibility: hidden;}/*ie6清除浮動的方式 *號只有IE6-IE7執行,其他瀏覽器不執行*/.clearfix {*zoom: 1;}使用after和before雙偽元素清除.clearfix:before,.clearfix:after {content: "";display: block;clear: both;}.clearfix {zoom: 1;}CSS3transition過渡和animation動畫的區別
animation屬性類似于transition,他們都是隨著時間改變元素的屬性值,其主要區別在于: transition需要觸發一個事件才會隨著時間改變其CSS屬性; animation在不需要觸發任何事件的情況下,也可以顯式的隨時間變化來改變元素CSS屬性,達到一種動畫的效果1)動畫不需要事件觸發,過渡需要。 2)過渡只有一組(兩個:開始-結束) 關鍵幀,動畫可以設置多個。前后端開發中數據是怎么交互的
web后端和前端是怎么連接的?網站數據處理主要分為三層。 第一層,表示層,這部分可以用HTML代碼,CSS/Javascript代碼來實現等。通過前端代碼可以實現網頁的布局和設計。這層又可以稱為顯示層。也就是你用瀏覽器打開能看到的網頁。 第二層,是業務層,這層是負責處理數據的。常用的代碼語言有PHP,JSP,Java等。通過這些后臺處理語言的算法來處理前臺傳回的數據。必要的時候進行操作數據庫,然后把結果返回給前端網頁。 第三層,是數據層,這個就是數據庫,用來存儲數據的。通過業務層的操作可以實現增刪改數據庫的操作。在網頁上填一個表格然后提交會有以下幾種數據傳輸經過: ①你接觸到的是這個網頁是屬于表示層,這個網頁一般由HTML標簽結合CSS/JAVASCRIPT來實現的。這時候你要先填入數據。 ②然后你按提交觸發后臺處理機制,這時候數據會傳到后臺的代碼進行處理。這部分代碼根據不同網站可以使PHP,JSP,JAVA等。代碼根據程序員預設的算法將收到的數據進行處理之后會相應的對數據庫進行操作,存儲數據等。 ③成功操作完數據庫之后,業務層的代碼會再向表示層也就是顯示器端傳回一個指令通知你表格填寫成功從前端向后臺傳遞參數方法一、通過表單傳遞參數 1.前端部分,在前端jsp頁面設置form表單,確定需要傳遞的參數name讓用戶輸入,通過點擊按鈕后submit()提交到后臺 2.后臺對前端請求的反應,接收數據,處理數據以及返回數據。二.通過ajax傳遞參數(有post和get寫法) 1.ajax是如何將前端數據傳到后臺的type: "POST",//type是ajax的方法url : "<%=path%>/resource/usermenus",//參數url,要把參數傳到什么地方data : {parentid:parentid,parentpath:parentpath},//傳遞什么數據success : function(data){//sucess表示,當數據返回成功后要怎么做,返回的數據存儲在data 2.后臺對前端請求的反應,接收數據 3.前端接收到后端返回的數據進行處理的cookie的理解
cookie又叫會話跟蹤技術,是由web服務器保存在用戶瀏覽器上的小文本文件,它可以記錄用戶ID、密碼、瀏覽過的網頁、停留的時間等信息。當用戶再次來到該網站時,網站通過讀取cookie,得知用戶相關信息,就可以做出相應的動作,如在頁面顯示歡迎用戶標語,或者讓用戶不用輸入ID、密碼就直接登錄等等。如果用戶清理了cookie,那么用戶曾登錄過的網站信息就沒有了。優點極高的擴展性和可用性通過良好的編程,可以控制保存在cookie中的session對象的大小通過加密技術和安全傳輸技術,減少cookie被破解的可能只在cookie中存放不敏感數據,即使被盜也不會有重大的損失控制cookie的生命周期,使之不會永久有效。偷盜者可能拿到一個過期的cookie缺點cookie有數量和長度的限制。每個domain最多有20條cookie,長度不能超過4KB,否則會被裁掉。安全性問題。如果cookie被人攔截了,那個人就可以取得所有的session信息。即使加密也于事無補,因為攔截者不需要知道cookie的意義,他只需要原樣轉發就能達到目的。有些狀態不可能保存在客戶端。輸入網址到呈現網頁發生的過程
a.域名解析DNS解析,每一臺連上網計算機都有一個唯一標識即它的IP地址,DNS解析就將輸入的網址解析成IP地址。 DNS解析是一個遞歸查詢的過程,例如要解析“www.baidu.com”時,過程如下:在本地域名服務器中查詢IP地址,未找到域名;本地域名服務器會向根域名服務器發送請求,未找到域名;本地域名服務器向.com頂級域名服務器發送請求,未找到域名;本地域名服務器向.baidu.com域名服務器發送請求,找到該域名,將相應的IP返回給本地域名服務器;b.發起TCP連接的三次握手HTTP協議是使用TCP協議作為其傳輸層協議的,在拿到服務器的IP地址后,客戶端瀏覽器會與服務器建立TCP連接,該過程包括三次握手:第一次握手:建立連接時,客戶端向服務端發送請求報文(SYN)第二次握手:服務器收到請求報文后,如同意連接,則向客戶端發送確認報文(SYN/ACK)第三次握手:客戶端收到服務器的確認后,再次向服務器發送確認報文,完成連接(ACK) 三次握手主要是為了防止已經失效的請求報文字段發送給服務器,浪費資源。c.建立TCP連接后瀏覽器發起HTTP請求瀏覽器構建HTTP請求報文,并通過TCP協議傳送到服務器的指定端口。HTTP請求報文一共有三個部分:報文首部(請求行+各種首部字段+其他)空行(它的作用是通過一個空行,告訴服務器請求頭部到此為止。)報文主體(應被發送的數據)通常并不一定要有報文主體d.服務端響應http請求,返回響應報文 HTTP響應報文由四部分組成:響應行、響應頭、空行、響應體 響應行響應行一般由協議版本、狀態碼及其描述組成響應頭響應頭用于描述服務器的基本信息,以及數據的描述,服務器通過這些數據的描述信息,可以通知客戶端如何處理等一會兒它回送的數據。 常見的響應頭字段含義:Allow:服務器支持哪些請求方法(如GET、POST等)。Content-Encoding:文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE4、IE5才支持它。因此,Servlet應該通過查看Accept-Encoding頭(即request.getHeader(“Accept- Encoding”))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。Content-Length:表示內容長度。只有當瀏覽器使用持久HTTP連接時才需要這個數據。如果你想要利用持久連接的優勢,可以把輸出文檔寫入 ByteArrayOutputStram,完成后查看其大小,然后把該值放入Content-Length頭,最后通過byteArrayStream.writeTo(response.getOutputStream()發送內容。Content- Type:表示后面的文檔屬于什么MIME類型。Servlet默認為text/plain,但通常需要顯式地指定為text/html。由于經常要設置 Content-Type,因此HttpServletResponse提供了一個專用的方法setContentType。Date:當前的GMT時間,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的時間表示世界標準時,換算成本地時間,需要知道用戶所在的時區。你可以用setDateHeader來設置這個頭以避免轉換時間格式的麻煩。Expires:告訴瀏覽器把回送的資源緩存多長時間,-1或0則是不緩存。Last-Modified:文檔的最后改動時間。客戶可以通過If-Modified-Since請求頭提供一個日期,該請求將被視為一個條件GET,只有改動時間遲于指定時間的文檔才會返回,否則返回一個304(Not Modified)狀態。Last-Modified也可用setDateHeader方法來設置。Location:這個頭配合302狀態碼使用,用于重定向接收者到一個新URI地址。表示客戶應當到哪里去提取文檔。Location通常不是直接設置的,而是通過HttpServletResponse的sendRedirect方法,該方法同時設置狀態代碼為302。Refresh:告訴瀏覽器隔多久刷新一次,以秒計。Server:服務器通過這個頭告訴瀏覽器服務器的類型。Server響應頭包含處理請求的原始服務器的軟件信息。此域能包含多個產品標識和注釋,產品標識一般按照重要性排序。Servlet一般不設置這個值,而是由Web服務器自己設置。Set-Cookie:設置和頁面關聯的Cookie。Servlet不應使用response.setHeader(“Set-Cookie”, …),而是應使用HttpServletResponse提供的專用方法addCookie。Transfer-Encoding:告訴瀏覽器數據的傳送格式。WWW-Authenticate:客戶應該在Authorization頭中提供什么類型的授權信息?在包含401(Unauthorized)狀態行的應答中這個頭是必需的。例如,response.setHeader(“WWW-Authenticate”, “BASIC realm=\”executives\”“)。注意Servlet一般不進行這方面的處理,而是讓Web服務器的專門機制來控制受密碼保護頁面的訪問。注:設置應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個參數,分別表示應答頭的名字和值。和設置狀態代碼相似,設置應答頭應該在發送任何文檔內容之前進行。setDateHeader方法和setIntHeader方法專門用來設置包含日期和整數值的應答頭,前者避免了把Java時間轉換為GMT時間字符串的麻煩,后者則避免了把整數轉換為字符串的麻煩。HttpServletResponse還提供了許多設置setContentType:設置Content-Type頭。大多數Servlet都要用到這個方法。setContentLength:設置Content-Length頭。對于支持持久HTTP連接的瀏覽器來說,這個函數是很有用的。addCookie:設置一個Cookie(Servlet API中沒有setCookie方法,因為應答往往包含多個Set-Cookie頭)。響應體 響應體就是響應的消息體,如果是純數據就是返回純數據,如果請求的是HTML頁面,那么返回的就是HTML代碼,如果是JS就是JS代碼,如此之類。e.瀏覽器頁面渲染解析文檔構建DOM樹構建渲染樹布局和繪制渲染樹f.斷開TCP連接第一次揮手:客戶端想分手,發送消息(FIN)給服務器第二次揮手:服務器通知客戶端已經接受的揮手請求,返回確認消息(ACK),但還沒做好分手準備第三次揮手:服務器已經做好分手準備,通知客戶端(FIN)第四次揮手:客戶端發送消息給服務器(ACK),確認分手,服務器關閉連接。瀏覽器渲染原理及流程
1. 瀏覽器會將HTML解析成一個DOM樹,DOM 樹的構建過程是一個深度遍歷過程:當前節點的所有子節點都構建好后才會去構建當前節點的下一個兄弟節點。2. 將CSS解析成 CSS Rule Tree 。3. 根據DOM樹和CSSOM來構造 Rendering Tree。注意:Rendering Tree 渲染樹并不等同于 DOM 樹,因為一些像Header或display:none的東西就沒必要放在渲染樹中了。4. 有了Render Tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關系。下一步操作稱之為layout,顧名思義就是計算出每個節點在屏幕中的位置。5. 再下一步就是繪制,即遍歷render樹,并使用UI后端層繪制每個節點。瀏覽器本地存儲
HTML5中的Web Storage包含了兩種存儲方式,sessionStorage和localStorage。還有indexedDB(適用于存儲字典,人工AI)sessionStorage用于本地存儲一個會話中的數據,這些數據只有在同一個會話中的頁面才能訪問并且當會話結束后數據也隨之銷毀。因此,sessionStorage不是一種持久化的本地存儲,僅僅是會話級別的存儲。localStorage用于持久化的本地存儲,除非主動刪除數據,否則數據永遠不會過期首先總的來說,三者都是用于持久化數據存儲的手段,都是存儲在瀏覽器端,且同源.localStorage和sessionStorage都是Web存儲,大小5M左右,完全存儲在客戶端,它們是因為本地存儲數據而存在.cookies也是存儲在瀏覽器端的,大小不超過4k,由服務器端存儲在客戶端。localStorage屬于永久性存儲,數據存儲量大,而sessionStorage屬于當會話結束的時候,存儲的值會被清空,而cookie是通過設置過期時間來存儲的。cookie,localStorage,sessionStorage區別
介紹 1.cookie又叫會話跟蹤技術,是由web服務器保存在用戶瀏覽器上的小文本文件,它可以記錄用戶ID、密碼、瀏覽過的網頁、停留的時間等信息。當用戶再次來到該網站時,網站通過讀取cookie,得知用戶相關信息,如果用戶清理了cookie,那么用戶曾登錄過的網站信息就沒有了。 2.sessionStorage和localStorage是H5新增的本地存儲區別 1.存儲大小的不同localStorage的大小一般為5MsessionStorage的大小一般為5Mcookies的大小一般為4K 2.有效期不同:localStorage的有效期為永久有效,除非你進行手動刪除。sessionStorage在當前會話下有效,關閉頁面或者瀏覽器時會被清空。cookies在設置的有效之前有效,當超過有效期便會失效。 3.與服務器端的通信localStorage不參與服務器端的通信。sessionStorage不參與服務器端的通信。cookies參與服務器端通信,每次都會攜帶http的頭信息中。(如果使用cookie保存過多數據會帶來性能問題)應用場景 1.因為考慮到每個 HTTP 請求都會帶著 Cookie 的信息,比較常用的一個應用場景就是判斷用戶是否登錄。針對登錄過的用戶,服務器端會在他登錄時往 Cookie 中插入一段加密過的唯一辨識單一用戶的辨識碼,下次只要讀取這個值就可以判斷當前用戶是否登錄啦。曾經還使用 Cookie 來保存用戶在電商網站的購物車信息,如今有了 localStorage,現在基本更加方便 2.sessionStorage:可以用來統計當前頁面元素的點擊次數。 3.localStoragese:常用于長期登錄(判斷用戶是否已登錄),適合長期保存在本地的數據。sessionStorage:敏感賬號一次性登錄;登陸信息用cookie好還是localStorage好?1.建議登陸信息用 cookie。即設置過期時間的cookie,看法是 cookie 默認會發送回到后端,這樣方便后端讀取,而使用localStorage,你需要在每次請求的時候,都手動帶上這個信息,這大大增加了開發過程中帶來的困難,非常麻煩,而且還要手動維護過期時間。2.cookie有時效,而localStorage如果不手動清理則永久保存。3.如果要設置關閉網頁/標簽就失效,請用SessionStorage。 這個類似你設置“不帶時間的cookie”。hash值獲取方式
可以通過window.location.hash獲取hash值document.write和innerHTML的區別
document.write會重繪整個頁面innerHTML重繪頁面的一部分進程和線程的區別
一個程序至少有一個進程,一個進程至少有一個線程線程的劃分尺度小于進程,使得多線程程序的并發性高進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大提高了程序的運行效率每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制 從邏輯角度來看,多線程的意義在于一個應用程序中,有多個執行部分可以同時執行。但操作系統并沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別babel原理
Babel 是一個通用的多功能 JavaScript 編譯器,但與一般編譯器不同的是它只是把同種語言的高版本規則轉換為低版本規則,而不是輸出另一種低級機器可識別的代碼,并且在依賴不同的拓展插件下可用于不同形式的靜態分析。(靜態分析:指在不需要執行代碼的前提下對代碼進行分析以及相應處理的一個過程,主要應用于語法檢查、編譯、代碼高亮、代碼轉換、優化、壓縮等等)babel 做了什么 和編譯器類似,babel 的轉譯過程也分為三個階段,這三步具體是:1.解析 Parse 將代碼解析生成抽象語法樹( 即AST ),也就是計算機理解我們代碼的方式(擴展:一般來說每個 js 引擎都有自己的 AST,比如熟知的 v8,chrome 瀏覽器會把 js 源碼轉換為抽象語法樹,再進一步轉換為字節碼或機器代碼),而 babel 則是通過 babylon 實現的 。簡單來說就是一個對于 JS 代碼的一個編譯過程,進行了詞法分析與語法分析的過程。 2.轉換 Transform 對于 AST 進行變換一系列的操作,babel 接受得到 AST 并通過 babel-traverse 對其進行遍歷,在此過程中進行添加、更新及移除等操作。 3.生成 Generate 將變換后的 AST 再轉換為 JS 代碼, 使用到的模塊是 babel-generator。而 babel-core 模塊則是將三者結合使得對外提供的API做了一個簡化。此外需要注意的是,babel 只是轉譯新標準引入的語法,比如ES6箭頭函數:而新標準引入的新的原生對象,部分原生對象新增的原型方法,新增的 API 等(Proxy、Set 等), 這些事不會轉譯的,需要引入對應的 polyfill 來解決。DVA工作流程
總結
- 上一篇: 利用计算机设计轴对称图案,“轴对称图形”
- 下一篇: HTML 教程:基础标签