變數型別
前置知識
-
值型別 vs 參考型別
// 值型別 let a = 100; let b = a; a = 200; console.log(b); //100// 參考型別 let a = { age: 20 }; let b = a; b.age = 21; console.log(a.age); //21

// 常見值型別 let a // undefined const s = 'abc' const n = 100 const b = true const m = Symbol('m');// 常見參考型別 const obj = { x: 100 }; const arr = ['a', 'b', 'c']; const n = null // 特殊參考型別 指標指向空地址 // 特殊參考型別 因為不用于存盤資料,所以沒有“拷貝、復制函式”一說 function fn(){} -
邏輯運算
-
truthy變數:!!a === true 的變數
let a = 100; !a; //false !!a; //true -
falsy變數:!!a === false 的變數
在 JavaScript 中只有 8 個 falsy 值,
// 以下是falsely變數 除此之外都是truely變數 !!0 === false !!-0 ===false !!NaN === false !!0n ===false (bigInt) !!'' === false !!null === false !!undefined === false !!false === false
-
if 陳述句 判斷的是否為truthy或者falsy,
-
與或非同樣判斷的是 truthy或者falsy
console.log(10&&0); //0 console.log(''||'abc') //'abc' console.log(!window.abc) //true
-
題目
-
typeof 能判斷哪些型別
// typeof 可以判斷所有值型別 let a; typeof a; //undefined let str = 'abc'; typeof str; // string const n = 100; typeof n; // number const b = true; typeof b; // boolean const s = Symbol('s'); typeof s; // symbol let big = BigInt(10e15); typeof big; // bigint// 能判斷參考型別 typeof console.log // function typeof function(){} // function // 能識別參考型別 typeof null; // object typeof [1, 2, 3]; // object typeof {x:100}; // object -
何時使用 === 何時使用 ==
// 除了 == null以外,其他一律用 ===, 例如 const obj = {x:100} if(obj.a == null) {} // 相當于 if(obj.a === null || obj===undefined){} -
值型別和參考型別的區別
值型別的值直接存盤在堆疊中,而參考型別在堆疊中存盤的是地址,地址指向其在堆中對應的值,
-
手寫深拷貝
const obj = { age: 20, name: '張三', address: { city: 'beijing' }, arr: [1, 2, 3, [4, 5, 6]] } /** * 深拷貝 * @param {Object} obj 要拷貝的物件 */ function deepClone(obj) { if (typeof obj !== 'object' || obj === undefined) { // 如果obj不是object型別或者為undefined return obj; } // 初始化回傳結果 let result; if (obj instanceof Array) { result = []; } else { result = {}; } for(let key in obj){ // 保證key 不為原型的屬性 if(obj.hasOwnProperty(key)){ // 遞回 如果是陣列,此時的key為索引 result[key] = deepClone(obj[key]); } } return result; } const obj2 = deepClone(obj);
類
前置知識
-
class
- constructor
- 屬性
- 方法
class Student{ constructor(name,number){ this.name = name; this.number = number; } sayHi(){ console.log(`姓名${this.name} 學號:${this.number}`); } } // 實體化物件 const Alex = new Student('Alex','001'); console.log(Alex.name); console.log(Alex.number); Alex.sayHi(); -
繼承
- extends
- super
- 執行
super.method(...)來呼叫一個父類方法, - 執行
super(...)來呼叫一個父類 constructor(只能在我們的 constructor 中),
- 執行
// 父類 class People{ constructor(name){ this.name = name; } eat(){ console.log(`${this.name} can eat`); } } // 子類 class Student extends People{ constructor(name,number){ super(name); this.number = number; } sayHi(){ super.eat(); console.log(`姓名${this.name} 學號:${this.number}`); } } const Alex = new Student('Alex','001'); console.log(Alex.name); console.log(Alex.number); Alex.sayHi();
題目
-
如何準確判斷一個變數是否為陣列?
Array.isArray(xx)或者xx instanceof Array -
手寫一個簡易的jQuery,考慮插件和拓展性?
class jQuery{ constructor(selector){ this.selector = selector; const result = document.querySelectorAll(selector); for(let i =0; i<result.length;i++){ this[i] = result[i]; } this.length = result.length; } get(index){ return this[index]; } each(fn){ for(let i=0;i<this.length;i++){ fn(this[i]) } } on(type,fn){ return this.each(elem=>{ elem.addEventListener(type,fn,false); }) } } // 插件 jQuery.prototype.dialog =function(info){ alert(info); } // 復寫 class myJQuery extends jQuery{ constructor(selector){ super(selector); } getLenth(){ console.log(this.length); } } new myJQuery('p').getLenth(); -
如何理解class的原型本質
人們常說
class是一個語法糖,因為我們實際上可以在沒有class的情況下宣告相同的內容,盡管,它們之間存在著重大差異:
-
首先,通過
class創建的函式具有特殊的內部屬性標記[[IsClassConstructor]]: true,因此,它與手動創建并不完全相同,編程語言會在許多地方檢查該屬性,例如,與普通函式不同,必須使用
new來呼叫它: -
類方法不可列舉, 類定義將
"prototype"中的所有方法的enumerable標志設定為false,這很好,因為如果我們對一個物件呼叫
for..in方法,我們通常不希望 class 方法出現, -
類總是使用
use strict, 在類構造中的所有代碼都將自動進入嚴格模式,
-
作用域和閉包
前置知識
-
自由變數
- 一個變數在當前作用域沒有定義,但是被使用了
- 向上一級作用域,一層一層依次尋找,直至找到為止
- 如果到全域作用域都沒有找到,則報錯
xx is not defined
-
作用域
- 全域作用域
- 函式作用域
- 塊級作用域
-
閉包
-
作用域應用的特殊情況,有兩種表現:①函式作為引數傳遞 ②函式作為回傳值被回傳
-
最關鍵的地方:在函式定義的位置找!
-
所有的自由變數的查找,是在函式定義的地方,向上級作用域查找,不是在執行的地方,
// 函式作為回傳值 function create() { let a = 100; return function () { console.log(a); } } let fn = create(); let a = 200; fn(); //100// 函式作為引數 function print(fn){ let a = 200; fn(); } let a =100; function fn(){ console.log(a); } print(fn); //100
-
-
this
this的值是在函式呼叫時確定的,不是在函式定義時確定的,
-
作為普通函式
function fn1(){ console.log(this); } fn1(); // window -
使用call apply bind
fn1.call({x:100}); // this指向 {x:100} const fn2 = fn1.bind({x:200}); fn2(); //{x:200} -
作為物件方法被呼叫
const zhangsan = { name: '張三', sayHi(){ // this 即當前物件 console.log(this); }, wait(){ setTimeout(function(){ // this指向window console.log(this); },10); }, waitAbitLonger(){ setTimeout(() => { console.log(this); }, 100); } } zhangsan.sayHi(); zhangsan.wait(); //window zhangsan.waitAbitLonger(); //指向物件張三 const wait = zhangsan.waitAbitLonger; wait(); // window -
在class方法中被呼叫
class People{ constructor(name){ this.name = name; this.age = 20; } sayHi(){ console.log(this); } } const zhangsan = new People('張三'); zhangsan.sayHi(); // zhangsan 物件 -
箭頭函式
-
題目
-
this的不同應用場景,如何取值? -
手寫
bind函式function fn1(...args){ console.log('this',this); console.log(...args); return 'this is fn1' } // const fn2 = fn1.bind({x:200},10,20,30); 原生bind // const res = fn2(); // console.log(res); // 手寫bind Function.prototype.bind1= function(){ // 將引數變為陣列 const args = [...arguments]; // 獲取this const t = args.shift(); // 此時的this指向呼叫bind1的函式 比如fn1.bind1() 則bind1()中的this指向fn1 const self = this; //回傳一個函式 return function(){ return self.apply(t,args); } } let test = fn1.bind1({x:200},10,20,30); console.log(test());// 手寫apply function fn(...args) { console.log(this); //(**) console.log('I got called with ' + [...args].join(' ')); return [...args].reduce((total, curr) => total + curr, 0); } Function.prototype.applyTest = function (t, args) { // 此時的this 指向呼叫applyTest的函式 // t為需要被指定的背景關系 t.__proto__.fn = this; // 為什么要在原型鏈上添加,因為如果不在原型鏈添加 在(**)中列印this時就多了這個函式 let result = t.fn(...args); delete t.__proto__.fn; return result } let result = fn.apply({ zs: 100 }, [2, 3, 4]); console.log(result); // 瞎寫補充一點 Function.prototype.applyTest = function (t, args) { if (t == undefined) { if (args == undefined) { // 此時沒有背景關系 也沒有引數 直接呼叫函式即可 return this(args); } else { // 展開引數 return this(...args); } } t.__proto__.fn = this; let result; if (args == undefined) { result = t.fn(args); } else { result = t.fn(...args); } delete t.__proto__.fn; return result; } -
閉包在實際開發中的應用場景,舉例說明
// 隱藏閉包中的資料 快取資料 // 例子1 function createCache(){ const data = {}; // 閉包中的資料被隱藏 不被外界訪問 return { set: function(key,val){ data[key] = val; }, get:function(key){ return data[key]; } } } const c = createCache(); c.set('a',100); console.log(c.get('a')); // 例子2 function slow(x) { // 這里可能會有重負載的 CPU 密集型作業 alert(`Called with ${x}`); return x; } function cachingDecorator(func) { let cache = new Map(); return function(x) { if (cache.has(x)) { // 如果快取中有對應的結果 return cache.get(x); // 從快取中讀取結果 } let result = func(x); // 否則就呼叫 func cache.set(x, result); // 然后將結果快取(記住)下來 return result; }; } slow = cachingDecorator(slow); alert( slow(1) ); // slow(1) 被快取下來了 alert( "Again: " + slow(1) ); // 一樣的 -
創建10個
<a>標簽,點擊的時候彈出對應的序號,這個題目和這里一模一樣:
// 創建10個a標簽 點擊的時候彈出對應的序號 // 方法一 for(let i = 0; i<10;i++){ a = document.createElement('a'); a.innerHTML = i +' '; a.addEventListener('click',(e)=>{ e.preventDefault(); alert(i); }) document.body.appendChild(a); } // 方法二 for (i = 0; i < 10; i++) { (function (i) { a = document.createElement('a'); a.innerHTML = i + ' '; a.addEventListener('click', (e) => { e.preventDefault(); alert(i); }) document.body.appendChild(a); })(i) }const div = document.querySelector('div'); // 創建一個檔案片段,還沒有插入到檔案片段中 const frag = document.createDocumentFragment(); for(let i = 0; i<10;i++){ const a = document.createElement('a'); a.innerHTML = `list item ${i}`; // 將a標簽插入到檔案片段中 frag.appendChild(a); a.addEventListener('click',()=>{ console.log(i); }) } div.appendChild(frag);
異步和單執行緒
前置知識
- 單執行緒和異步
- 單執行緒:js是單執行緒語言,只能同時做一件事情,因為js可以修改DOM結構,所以js和dom渲染必須共用同一個執行緒,
- 異步:遇到等待(網路請求,定時任務)不能卡住,因此需要異步,異步是基于callback函式形式,當存在許多callback時,容易導致回呼地獄,因此又誕生了promise,
- 因為js是單執行緒語言,異步不會阻塞代碼執行,同步會阻塞代碼執行
- 應用場景:
- 網路請求:如ajax加載圖片
- 定時任務:如setTimeOut
題目
-
同步和異步的區別是什么?
- 基于Js是單執行緒語言,異步不會阻塞代碼執行,同步會阻塞代碼執行,
-
用
promise加載一張圖片const url = 'https://gitee.com/zyxbj/image-warehouse/raw/master/pics/202109101448581.png'; function loadImg(url){ return new Promise((resolve,reject)=>{ const img = document.createElement('img'); img.src = url; img.onload= ()=>{ resolve(img); } img.onerror=()=>{ reject(new Error(`圖片加載失敗 ${src}`)) } }) } loadImg(url).then((img)=>{ document.body.appendChild(img); }).catch(err=>console.log(err)); -
前端使用異步的場景有哪些?
- 網路請求:如ajax加載圖片
- 定時任務:如setTimeOut
DOM
前置知識
-
DOM 本質
- 檔案物件模型(Document Object Model),簡稱 DOM,將所有頁面內容表示為可以修改的物件,DOM 將 HTML 表示為標簽的樹形結構,
-
-
DOM 節點的操作
-
獲取DOM節點
方法名 搜索方式 可以在元素上呼叫? 實時的? querySelectorCSS-selector ? - querySelectorAllCSS-selector ? - getElementByIdid- - getElementsByNamename- ? getElementsByTagNametag or '*'? ? getElementsByClassNameclass ? ? elem.getElementsByTagName(tag)查找具有給定標簽的元素,并回傳它們的集合,tag引數也可以是對于“任何標簽”的星號"*",elem.getElementsByClassName(className)回傳具有給定CSS類的元素,document.getElementsByName(name)回傳在檔案范圍內具有給定name特性的元素,很少使用,
-
attribute
-
attribute是HTML標簽上的特性,它的值只能夠是字串;修改標簽的屬性,會改變html結構,
const span = document.querySelector('span'); span.setAttribute('data-name','hello'); console.log(span.getAttribute('data-name')); //hello span.setAttribute('class','hello')
-
-
property
-
property是DOM中的屬性,是JavaScript里的物件;修改物件屬性,不會體現到html結構中,
const span = document.querySelector('span'); console.log(span.style.width); console.log(span.className); // hello work 字串 console.log(span.classList);// ['hello', 'work', length: 2 value: 'hello work'] console.log(span.parentNode); console.log(span.nodeName); //SPAN console.log(span.nodeType); //1property和attribute兩者都可能導致重新渲染dom,
-
-
-
DOM 結構操作
-
新增節點
-
appenChild:
target.appendChild(newChild)
newChild作為target的子節點插入最后的一子節點之后
const box = document.querySelector('.box'); // 新建節點 const p = document.createElement('p'); p.innerHTML = 'this is p'; // 插入節點 box.appendChild(p); -
insertBefore
target.insertBefore(newChild,existingChild)
newChild作為target的子節點插入到existingChild節點之前
existingChild為可選項引數,當為null時其效果與appendChild一樣
const box = document.querySelector('.box'); const ul = document.querySelector('ul'); const p = document.createElement('p'); p.innerHTML = 'hello world'; // box為父盒子 p為新增元素 ul為已經存在的元素 box.insertBefore(p,ul)
-
-
移動節點
如果元素已經存在,使用
insertBefore或者appendChild即可移動元素, -
獲取子元素或者父元素
功能 獲取節點 獲取純元素 獲取父節點 parentElement parentNode 獲取上一個節點(元素) previousSibling previousElementSibling 獲取下一個節點(元素) nextSibling nextElementSibling 獲取第一個節點(元素) firstChild firstElementChild 獲取最后一個節點(元素) lastChild lastElementChild 獲取子節點(元素) childNodes children -
洗掉子元素:
const box = document.querySelector('.box'); const ul = document.querySelector('ul'); box.removeChild(ul);
-
-
DOM 性能
-
Dom操作非常昂貴,避免頻繁的DOM操作
-
對DOM查詢做快取

-
將頻繁操作改為一次性操作
const list = document.querySelector('ul'); // 創建一個檔案片段,還沒有插入到檔案片段中 const frag = document.createDocumentFragment(); for(let i = 0; i<10;i++){ const li = document.createElement('li'); li.innerHTML = `list item ${i}`; // 將li標簽插入到檔案片段中 frag.appendChild(li); } list.appendChild(frag);
-
題目
-
DOM是哪種資料結構?檔案物件模型(Document Object Model),簡稱 DOM,將所有頁面內容表示為可以修改的物件,DOM 將 HTML 表示為標簽的樹形結構,(樹)
-
DOM操作的常用API? -
attribute和property的區別?- attribute是HTML標簽上的特性,它的值只能夠是字串;修改標簽的屬性,會改變html結構,
- property是DOM中的屬性,是JavaScript里的物件;修改物件屬性,不會體現到html結構中,
- 兩者都可能引起DOM重新渲染,
-
一次性插入多個
DOM節點,考慮性能const list = document.querySelector('ul'); // 創建一個檔案片段,還沒有插入到檔案片段中 const frag = document.createDocumentFragment(); for(let i = 0; i<10;i++){ const li = document.createElement('li'); li.innerHTML = `list item ${i}`; // 將li標簽插入到檔案片段中 frag.appendChild(li); } list.appendChild(frag);
BOM 操作
前置知識
-
navigator
navigator 物件提供了有關瀏覽器和作業系統的背景資訊,navigator 有許多屬性,但是最廣為人知的兩個屬性是:
navigator.userAgent— 關于當前瀏覽器,navigator.platform— 關于平臺(可以幫助區分 Windows/Linux/Mac 等),console.log(navigator.userAgent); // Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 console.log(navigator.platform); // Win32 -
location
// 在resume.jiaqicoder.com測驗 location.href //'https://resume.jiaqicoder.com/#about' location.protocol //'https:' location.host //'resume.jiaqicoder.com' location.search //'?a=100&b=200' location.hash //'#about' location.pathname // '/' -
history
history.back(); // history.go(-1); history.forward();//history.go(1);
題目
- 如何識別瀏覽器的型別?
- 分析拆解url各個部分?
事件
前置知識
-
事件系結
const button = document.querySelector('button'); // 通用的事件系結函式 function bindEvent(elem,type,fn){ elem.addEventListener(type,fn); } bindEvent(button,'click',(e)=>{ e.preventDefault(); console.log(e.target); }) -
事件冒泡
event.stopPropagation();阻止事件冒泡,event.stopImmediatePropagation();阻止事件冒泡并且阻止該元素之后的相同事件型別的監聽器觸發, -
事件代理
<div class="box"> <a href="#">1</a> <a href="#">2</a> <a href="#">3</a> <a href="#">4</a> <button>加載更多...</button> </div> <script> const box = document.querySelector('.box'); box.addEventListener('click',e=>{ e.preventDefault(); if(e.target.nodeName= 'A'){ console.log(e.target.innerHTML); } }) </script>
題目
-
撰寫一個通用的事件監聽函式
<div class="box"> <a href="#">1</a> <a href="#">2</a> <a href="#">3</a> <a href="#">4</a> <button>加載更多...</button> </div> <script> // elem:添加事件監聽的元素 type 事件監聽的型別 // seletor:被事件代理的元素(可選)fn:觸發監聽后執行的回呼函式 function bindEvent(elem, type, selector, fn) { if (fn == undefined) { // 說明是三個引數的這種情況 selector的值為傳入的fn // 交換fn和selector的值 [fn, selector] = [selector, fn]; console.log(3); } elem.addEventListener(type, e => { if (selector) { // 需要被代理 // matches它檢查 elem 是否與給定的 CSS 選擇器匹配,它回傳 true 或 false, if (e.target.matches(selector)) { fn.call(e.target, e); // 讓this指向觸發的元素 } } else { // 普通系結 fn.call(e.target, e); } }) } const box = document.querySelector('.box'); bindEvent(box, 'click', 'a', function (e) { e.preventDefault(); console.log(this.innerHTML) //因為要使用this此時無法使用箭頭函式 }) </script> -
描述事件冒泡的流程
事件冒泡基于DOM樹形結構,會順著觸發元素往上冒泡,
-
無線下拉的圖片串列,如何監聽每個圖片的點擊
- 通過事件代理
- 用e.target 獲取觸發元素
- 用matches來判斷是否為觸發元素
ajax
前置知識
-
fetch
fetch('https://reqres.in/api/users/',{ method:'POST', headers:{ 'Content-Type':'applicaton/json' }, body:JSON.stringify( { name:'User 21' } ) }).then(res=>{ return res.json(); }).then(data=>{ console.log(data); }) -
XMLHttpRequest
// get 請求 const xhr = new XMLHttpRequest(); xhr.open('GET', './0.data.json', true); //代表異步 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) { // console.log(xhr.responseText); // 決議為json格式 console.log(JSON.parse(xhr.responseText)) } } } xhr.send(null); // send 請求 const xhr = new XMLHttpRequest(); xhr.open('POST','./0.data.json',true); xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ if(xhr.status >= 200 &&xhr.status<300 ||xhr.status===304){ console.log(xhr.responseText); } } } const postData ={ userName:'zhangsan', age:32 }; xhr.send(JSON.stringify(postData));-
xhr.readyState
- 0 - (未初始化) 還沒有呼叫send()方法
- 1 - (載入)已經呼叫send()方法,正在發送請求
- 2 - (載入完成)send()方法,已經接收到全部回應內容
- 3 - (互動)正在決議回應內容
- 4 - (完成) 回應內容決議完成,可以在客戶端呼叫
-
xhr.status
- 2xx - 表示成功處理請求 如200
- 3xx - 需要重新定向,瀏覽器直接跳轉,如301,302,304
- 4xx - 客戶端請求錯誤,如404,403
- 5xx - 服務器端錯誤
-
-
同源策略
-
ajax請求時,瀏覽器要求當前網頁必須和server端同源
-
同源:協議、域名、埠,三者必須一致
-
加載圖片、css、js可以無視同源策略
<img src=''/>可以用于統計打點,使用第三方統計服務<link/><script/>可以使用CDN,CDN一般都是外域<script>可以實作JSONP
-
-
跨域
- 所有的跨域,都必須經過server端運行和配合
- 未經server端運行就實作跨域,說明瀏覽器有漏洞,危險信號
-
JSONP
<script>可以繞過跨域限制,服務器可以任意動態拼接資料回傳,所以,<script>就可以獲得跨域的資料,只要服務端愿意回傳,<script> // 在 這個頁面http://127.0.0.1:5500/24.jsonp.html window.callback = function (data) { console.log(data); } </script> <!-- 訪問不同埠的服務器的資料 --> <!-- 該服務器的回傳結果為callback({name:'zhangsan'}) --> <script src="http://localhost/24.jsonp.js"></script> <!--或者說這樣寫--> <script> const jsonp = document.createElement('script'); jsonp.src ='http://localhost/24.jsonp.js' document.body.appendChild(jsonp); const callback = function (data) { console.log(data); } </script> -
服務器設定header
const express = require('express') const bodyParser = require('body-parser') const app = express() // 處理引數 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // 設定允許跨域訪問該服務 app.all('*', function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS'); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); }); // 啟動監聽 app.listen(3000, () => { console.log('running...') })
題目
-
手寫一個簡易的
ajaxfunction ajax(url) { const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status > 199 && xhr.status < 300 || xhr.status === 304) { resolve(xhr.responseText); } else { reject('someting went wrong'); } } } xhr.send(null); }); return p; } ajax('https://reqres.in/api/users/').then(data => console.log(JSON.parse(data))).catch(err => console.log(err)); -
跨域的常見方式
-
jsonp
-
cors
存盤
前置知識
-
cookie
cookie全稱為HTTP cookie,簡稱cookie,是瀏覽器存盤資料的一種方式,cookie是本地存盤,一般會自動隨著瀏覽器發送請求時發送到服務器端,本身用于瀏覽器和服務器通訊,一般最大為4kb,
document.cookie = 'username=zs'; document.cookie = `user=${encodeURIComponent('張三')}`; //中文需要用到encodeURIComponent // 告知失效時間 如果不設定,默認會是session document.cookie = `hobby=sleep;expires=${new Date('2022-09-09')}` // 還可以設定domain path 當domain、path以及name的值完全相同時,下一個cookie才會覆寫上一個 document.cookie = `hobby=eat;path='/info';domain='jiaqicoder.com;max-age=100 `; // 該cookie只能在 jiaqicoder.com/info下讀寫 且100s后cookie被洗掉 // 一個一個的設定但是會一起列印 console.log(document.cookie); //username=zs; user=%E5%BC%A0%E4%B8%89; hobby=sleep -
localStorage和sessionStorage
localStorage也是一種瀏覽器存盤資料的方式(本地存盤),它只是存盤在本地,不會發送到服務器端,而cookie會隨著瀏覽器向服務器發送請求時發送到服務器,localStorage中的鍵值對總是以字串的形式存盤,localStorage.setItem('name','jiaqii'); localStorage.setItem('age',332); console.log(localStorage.getItem('age')); localStorage.removeItem('age'); localStorage.clear();//清空所有的localStorage是持久化本地存盤,除非手動清除(比如通過JavaScript洗掉,或者清除瀏覽器快取),否則資料是永遠不會過期的,但是當會話結束(比如關閉瀏覽器)的時候,
sessionStorage中的資料會被清空,它的方法和localStorage完全一樣,
題目
- 描述
cookie、localStorage、sessionStorage的區別
HTTP
前置知識
-
http狀態碼
- 狀態碼分類
- 1xx 服務器收到請求
- 2xx 請求成功
- 3xx 重定向
- 4xx 客戶端錯誤
- 5xx 服務端錯誤
- 常見的狀態碼
- 200 成功
- 301 永久重定向 (配合location,瀏覽器自動處理)
- 302 臨時重定向 (配合location,瀏覽器自動處理)
- 304 資源未被修改,從快取中讀取資料
- 403 沒有權限
- 404 資源不存在
- 500 服務器錯誤
- 504 網關超時
- 狀態碼分類
-
http方法
-
傳統的 methods
- get 獲取服務器的資料
- post 向服務器提交資料
-
現在的methods
-
get 獲取資料
-
post 新建資料
-
patch/put 更新資料
-
delete 洗掉資料
這些方法只是一個規范,比如get可以用來新建資料,但是盡量遵守規范
-
-
Restful API
-
傳統的api設計:把每個url當做一個功能
-
restful api設計:把每個url當做一個唯一的資源(標識)
-
如何將url設定為資源?
-
盡量不用url引數
傳統的api設計:/api/list?pageIndex=2
restful api設計:/api/list/2
-
用 method 表示操作型別
傳統的api:
- post請求 /api/create-blog
- put請求 /api/update-blog?id=100
- get請求 /api/get-blog?id=100
restful api:用method 表示操作型別
- post請求 /api/blog 如
axios.post('/api/blog',{name:12,age:18}) - put請求 /api/blog/100 如
axios.put('/api/blog/100',{age:12}) - get請求 /api/blog/100 如
axio.get('/api/blog/100')
-
-
-
-
http headers
- 常見的request headers
- Accept 瀏覽器可接收的資料格式
- Accept-Encoding 瀏覽器可接收的壓縮演算法,如gzip
- Accept-Language 瀏覽器可接收的語言,如zh-CN
- Connection: keep-alive 一次TCP連接重復使用
- cookie 同域一般瀏覽器會自動發送cookie
- Host 域名
- UserAgent 瀏覽器資訊
- Content-Type 發送資料的格式,如果application/json
- 常見的response headers
- Content-Type 回傳資料的格式,如果application/json
- Content-Length 回傳的資料的大小
- Content-Encoding 回傳資料的壓縮演算法,如gzip
- Set-Cookie 設定cookie
- 快取相關的headers:
- Cache-Control:Expires
- Last-Modified:If-Modified-Since
- Etag:If-None-Match
- 常見的request headers
-
http 快取
https://juejin.cn/post/6844903763665240072
-
關于快取的介紹
-
什么是快取?
-
為什么需要快取?
部分資料可以直接從快取中讀取,減少網路請求的資料,加快頁面加載速度,
-
-
http快取策略(強制快取 + 協商快取)
-
強制快取
簡單粗暴,如果資源沒過期,就取快取,如果過期了,則請求服務器,

Cache-Control 在Response-Headers中,控制強制快取的邏輯,
Cache-Control 的幾個取值含義:
private: 僅瀏覽器可以快取
public: 瀏覽器和代理服務器都可以快取(對于private和public,前端可以認為一樣,不用深究)
max-age=xxx 過期時間(重要)
no-cache 不進行強快取(重要)
no-store 不強快取,也不協商快取,基本不用,快取越多才越好呢
注意:規則可以同時多個,
-
協商快取
觸發條件:
- Cache-Control 的值為 no-cache (不強快取)
- 或者 max-age 過期了 (強快取,但總有過期的時候)
也就是說,不管怎樣,都可能最后要進行協商快取(no-store除外)
服務器端判斷客戶端資源,是否和服務端資源一樣,如果判斷一直則回傳304,否則回傳200和最新的資源,

response header里面的設定
etag: '5c20abbd-e2e8' last-modified: Mon, 24 Dec 2018 09:49:49 GMTetag:每個檔案有一個,改動檔案了就變了,就是個檔案hash,每個檔案唯一,
last-modified:檔案的修改時間,精確到秒,
也就是說,每次請求回傳來
response header中的etag和last-modified,在下次請求時在request header就把這兩個帶上,服務端把你帶過來的標識進行對比,然后判斷資源是否更改了,如果更改就直接回傳新的資源,和更新對應的response header的標識etag、last-modified,如果資源沒有變,那就不變etag、last-modified,這時候對客戶端來說,每次請求都是要進行協商快取了,即:發請求–>看資源是否過期–>過期–>請求服務器–>服務器對比資源是否真的過期–>沒過期–>回傳304狀態碼–>客戶端用快取的老資源,這就是一條完整的協商快取的程序,
-
-
重繪操作方式,對快取的影響
-
題目
-
http 常見的狀態碼有哪些?
-
http 常見的header有哪些?
-
什么是Restful Api?
-
描述http的快取機制?(重要)
手寫
防抖
- 監聽輸入框,文字變化后會觸發change事件
- 直接用keyup事件,則會頻繁觸發change事件
- 防抖:用戶輸入結束或暫停時,才會觸發change事件
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303035.html
標籤:java
上一篇:javaSE初階 String
