文章目錄
- 32.【算法與數據結構】僞代碼與流程圖
- 33.【算法與數據結構】排序算法(上)
- 34.【算法與數據結構】排序算法(下)
- 35.【算法與數據結構】僞代碼與流程圖
- 36.【JS編程接口】DOM 編程
- 37.【JS編程接口】手寫 DOM 庫
- 38 【JS編程接口】jQuery 中的設計模式(下)
- 39.【JS編程接口】DOM事件和事件委託
- 40.【項目】前航項目介紹
- 41.【項目】前端導航站點-上
- 42.【項目】前端導航站點(下)
- 43. 打console.log
- 44.【前後分離】AJAX 的原理
- 45.【前後分離】異步與Promise
- 46.【前後分離】跨域、CORS、JSONP
- 47.【前後分離】靜態服務器
- 48【前後分離】Ajax 實戰:Cookie、Session
32.【算法與數據結構】僞代碼與流程圖
32.1 視頻:1
抽象能力: 越高級的程序員, 抽象能力越強
JS, Python, Java和PHP都有:
- 聲明
- if… else…
- while, for循環
- 函數
- 對象
32.2視頻:2
- 對編程的熱愛
- 邏輯
推薦使用MIndjet畫流程圖
32.3 視頻:3
畫流程圖
32.4 視頻:4
數據結構 = 數據形式 + 操作
用哈希表來解決該問題
33.【算法與數據結構】排序算法(上)
33.1 視頻:minOf2的實現
數據結構: 數組
找出較小的那個數
let minOf2 = ([a, b]) => a > b?a: b
//高手調用函數方法
minOf2.call(null, [1, 2])
這種寫法叫做析構賦值, 之後的課程會反覆使用.
現成min的JS的API
Math.min.call(null, 1, 2)
Math.min.apply(null, [1, 2])
@@@
Math看起來像Object一樣是構造函數, 實際上Math只是一個普通對象, 這是唯一的特例: 首字母大寫是構造函數.
@@細節@
33.2 視頻:minOf4的實現
33.3 視頻:min的實現
找出給出數組的最小值
let min = (numbers) =>{
if(numbers.length > 2){
return min([numbers[0], min(numbers.slice(1))])
}else{
return Math.min.apply(null, numbers)
}
}
33.4 視頻:實現sort排序
任意長度的數組排序
let min = (numbers) =>{
if(numbers.length > 2){
return min([numbers[0], min(numbers.slice(1))])
}else{
return Math.min.apply(null, numbers)
}
}
let minIndex = (numbers) => numbers.indexOf(min(numbers))
let sort = (numbers) => {
if(numbers.length > 2){
let index = minIndex(numbers)
let min = numbers[index]
numbers.splice(index, 1)
return [min].concat(sort(numbers))
}else{
return numbers[0]>numbers[1]? numbers.reverse(): numbers
}
}
33.5 視頻:如何調試代碼
console大法:俗稱print大法
34.【算法與數據結構】排序算法(下)
34.1 視頻:選擇排序的循環寫法
let minIndex = numbers =>{
let index = 0
for(let i = 1; i< numbers.length; i++){
if(numbers[index] > numbers[i]){
index = i
}
}
return index
}
let swap = (array, i, j) => {
let temp = array[i]
array[i] = array[j]
array[j] = temp
}
let selectSort = numbers =>{
let index = 0
for(let i = 0; i<numbers.length - 1; i++){
//不改變原數組,即可找出逐漸遞減的數組中最小值的index
index = minIndex(numbers.slice(i)) + i
if(index !==i ){
swap(numbers, index, i)
}
}
return numbers
}
@@@
所有遞歸都可以改成循環
@@細節@
34.2 視頻:快速排序
let quickSort = numbers => {
if(numbers.length <= 1){
return numbers
}
let pivotIndex = Math.floor(numbers.length / 2)
let pivot = numbers.splice(pivotIndex, 1)[0]
let left = []
let right = []
for(let i = 0; i< numbers.length; i++){
if(numbers[i] < pivot){
left.push(numbers[i])
}else{
right.push(numbers[i])
}
}
return quickSort(left).concat([pivot], quickSort(right))
}
34.3 視頻:歸併排序
let merge = (a, b) => {
if(a.length === 0) return b
if(b.length === 0) return a
return a[0] > b[0] ? [b[0]].concat(merge(a, b.slice(1))) : [a[0]].concat(merge(a.slice(1), b))
}
let mergeSort = numbers => {
let len = numbers.length
if(len === 1){
return numbers
}
let left = numbers.slice(0, Math.floor(len/2))
let right = numbers.slice(Math.floor(len/2))
return merge(mergeSort(left),mergeSort(right))
}
34.4 視頻:計數排序
數據結構:哈希表(key:value這種類型)
let countSort = numbers => {
let hashTable = {}, max = 0, result = []
for(let i=0; i<numbers.length; i++){
if(!(numbers[i] in hashTable)){
if(numbers[i] > max){
max = numbers[i]
}
hashTable[numbers[i]] = 1
}else{
hashTable[numbers[i]] += 1
}
}
for(let j=0; j<=max; j++){
if(j in hashTable){
for(let k=0; k<hashTable[j]; k++){
result.push(j)
}
}
}
return result
}
34.5 視頻:四種排序的時間複雜度
34.6 視頻:其他的排序算法
35.【算法與數據結構】僞代碼與流程圖
35.1 視頻:隊列 & 棧
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>隊列</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="screen"></div>
<div id="action">
<button id="createNumber">取號</button>
<button id="callNumber">叫號</button>
</div>
<div>
當前號碼: <span id="newNumber"></span>
</div>
<div>
當前隊列: <span id="queue"></span>
</div>
<script src="./main.js"></script>
</body>
</html>
#screen {
border: 1px solid #000;
width: 200px;
height: 200px;
}
const divScreen = document.querySelector('#screen')
const btnCreateNumber = document.querySelector('#createNumber')
const btnCallNumber = document.querySelector('#callNumber')
const spanNewNumber = document.querySelector('#newNumber')
const spanQueue = document.querySelector('#queue')
let n = 0
let queueList = []
btnCreateNumber.onclick = () => {
n += 1
queueList.push.call(queueList, n)
spanNewNumber.innerHTML = n;
spanQueue.innerHTML = JSON.stringify(queueList);
console.log(queueList)
}
btnCallNumber.onclick = () => {
if (queueList.length == 0) {
divScreen.innerHTML = ''
return
}
const now = queueList.shift.call(queueList)
divScreen.innerHTML = `請 ${now} 號, 取餐,祝您用餐愉快!`
spanQueue.innerHTML = JSON.stringify(queueList);
}
35.2 視頻:鏈表
35.3 視頻:哈希表
35.4 視頻:樹
36.【JS編程接口】DOM 編程
36.1 視頻:DOM(Document )介紹
DOM很難用, 所有後面纔會出現JQuery, Vue和React等
獲取元素, 也叫標籤:
window.idxxx
或者會直接誒idxxx
document.getElementById('idxxx')
document.getElementsByTagName('div')[0]
document.getElementsByClassName('red')[0]
document.querySelector('#idxxx')
document.querySelector('.red')[0]
用哪一個: 工作中使用querySelector和querySelectorAll, 做demo直接使用idxxx(千萬別被人發現了), 要做兼容IE的可憐蟲才用getElement(s)ByXXX
36.2 視頻:獲取元素的API
獲取特定元素:
- html元素
document.documentElement - head元素
document.head - body元素
document.body - 窗口(窗口不是元素)
- window
- 所有蒜素
document.all
document.all是個奇葩, 第6個falsy值
36.3 視頻:元素的6層原型鏈
獲取的元素是對象:
div完整原型鏈:
節點(Node):
36.4 視頻:創建元素的API
- 增
1 創建一個標籤節點
let div1 = document.createElement('div')
document.createElement('style')
document.createElement('script')
document.createElement('li')
2 創建一個文本節點
text = document.createTextNode('你好')
3 標籤裏面插入文本
div1.appendChild(text1)
//法一(IE)
div1.innerText = '你好'
//法二(標準)
div1.textContent = '你好'
//不能用div1.appendChild('你好')
4 插入頁面中
創建的標籤默認處於JS線程中,必須把它插入到head(默認看不見)或者body中, 它纔會生效
document.body.appendChild(div)
已經在頁面中的元素.appendChild(div)
- appendChild
let div = document.createElement('div')
test1.appendChild(div)
test2.appendChild(div)
@@@
最終div出現在test2中, 一個元素不能出現在兩個地方, 除非複製一份(let div2 = div1.cloneNode(true)
)
@@細節@
- 刪
1 兩種方法
//舊方法
parentNode.removeChild(ChildNode)
//新方法(不兼容IE)
childNode.remove()
2 如果一個node被移除頁面(DOM樹), 那麼它還可以再次回到頁面中嗎?
div1.parentNode.removeChild(div1)
div1.remove()
document.body.appendChild(div1)
可以再次回到頁面, 刪除只是將node從頁面(DOM樹)移除, 回到了內存(線程)中, 當然可以再次回到頁面(DOM樹)中.
- 改
1 寫標準屬性
//改calss
div.className = 'red'//全覆蓋
div.className += ' blue'//追加
div.calssList.add('red')//追加
//改style
div.style = ''//全覆蓋
div.style.屬性 = ''//修改對應屬性
//大小寫
//background-color
div.style.backgroundColor = 'black'
div.style['background-color'] = 'black'
//增加自定義屬性
div.setAttribute('data-x', 'text')
//改data-*屬性
div.dataset.x = 'frank'
2 讀標準屬性
//常規
div.style
div.className
div.id
//特殊
div.calssList
div.getAttribute('class')
a.href
a.getAttribute('href')
- 改事件處理函數
1 div.onclick默認是爲null
默認點擊div不會有任何響應, 但是如果把div.onclick
改爲一個函數fn, 那麼點擊div的時候, 瀏覽器就會調用這個函數, 並且是這樣調用的fn.call(div, event)
. div會被當做this, event則包含了點擊事件的所有信息, 如座標.
2 div.addEventListener
div.onclick升級版後面講
- 改內容
1 改文本內容
div.innerText = 'xxx'
div.textContent = 'xxx'
2 改HTML內容(內容過長影響網站性能)
div.innerHTML = '<strong>重要內容<strong>'
3 改標籤
div.innerHTML = ''//先清空
div.appendChild(div2)//再添加內容
- 改爸爸
newParent.appendChild(div)
div2.appendChild(div)
36.5 視頻:查看元素的API
- 查
1 查爸爸
node.parentNode
node.parentElement
2 查爺爺
node.parentNode.parentNode
3 查子代
node.childNodes
node.children//推薦
用node.childNodes
, 如果有空格的話會算進去
想要正確表達子代個數, 第一種不能打空格用node.childNodes
第二種用node.children
- 查看兄弟姐妹
node.parentNode.childNodes //還要排除自己(for循環)
node.parentNode.children //還要排除自己(for循環)
排除自己,實現代碼:
let sibling = []
let c2 = div.parentElement.children
for(let i=0; i< c2.length; i++){
console.log(i)
if(c2[i] !== div){
sibling.push(c2[i])
}
}
- 查看老大
node.firstChild
- 查看老幺
node.lastChild
- 查看上一個哥哥/姐姐
node.previoussibling
- 查看下一個弟弟/妹妹
node.nextSibling
- 遍歷一個div裏面的所有元素
travel = (node, fn) => {
fn(node)
if(node.children){
for(let i=0; i<node.children.length; i++){
travel(node.children[i], fn)
}
}
}
travel(div1, (node)=> console.log(node))
36.6 視頻:DOM操作跨線程
DOM操作是跨線程的
- 瀏覽器功能分爲:
渲染引擎
和JS引擎
1 各線程各司其職
JS引擎不能操作頁面, 只能操作JS. 渲染引擎不能操作JS, 只能操作頁面.
那麼document.body.appendChild(div1), 是如何改變頁面的.
2 跨線程通訊
當瀏覽器發現JS在body裏面加了個div1對象, 瀏覽器就會通知渲染引擎在頁面裏也新增一個div元素, 新增的div元素所有屬性都照抄div1對象.
- 插入新標籤完整過程
1 在div1放入頁面之前
對div1所有的操作都屬於JS線程內的操作
2 把div1放入頁面之時
瀏覽器會發現JS的意圖, 就會通知渲染線程在頁面中渲染div1對應的元素.
3 把div1放入頁面之後
對div1的操作都有可能會觸發重新渲染
div1.id = 'newId'
可能會重新渲染, 也可能不會
div1.title = 'new'
可能會重新渲染, 也可能不會
如果連續對div1多次操作, 瀏覽器可能會合併成一次操作, 也可能不會
合併了
加入test.clientWidth
後, 不合並了.
- 屬性同步
1 標準屬性
對div1的標準屬性的修改, 會被瀏覽器同步到頁面中, 比如id, className, title等
2 data-*屬性
同上
3 非標準屬性
對非標準屬性的修改, 則只會停留在JS線程中, 不會同步到頁面裏.
- Property v.s. Attribute
1 property屬性
JS線程中div1的所有屬性, 叫做div1的property
2 attribute也是屬性
渲染引擎中div1對應標籤的屬性, 叫做attribute
3 區別
大部分時候, 同名的property和attribute值相等, 但是如果不是標準屬性, 那麼他們只會一開始時相等.同時注意attribute只支持字符串, 而property支持字符串, 布爾等類型.
36 測試
37.【JS編程接口】手寫 DOM 庫
37.1 視頻:什麼是封裝
- 什麼是封裝
封裝: 通俗來說電腦筆記本就是CPU, 內存, 硬盤, 主板, 顯卡的封裝, 用戶只需要接觸顯示器, 鍵盤, 鼠標, 觸控板等設備即可操作複雜的計算機.
接口: 被封裝的東西需要暴露在一些功能給外部, 這些功能就是接口, 如USB接口, HDMI接口.設備只要支持這些接口, 即可與被封裝的東西通訊, 比如鍵盤, 鼠標支持USB接口, 顯示器支持HDMI接口
- 術語
1 庫
我們把提供給其他人用的工具代碼叫做庫, 比如JQuery, Underscore
2 API
庫暴露出來的函數或屬性叫做API(應用程序接口 Application Programming Interface)
3 框架
當你的庫變得很大, 並且需要學習才能看懂, 那麼這個庫就叫做框架, 比如Vue/React
37.2 視頻:硬核寫DOM庫
- 對象風格
1 也叫做命名空間風格
window.dom
是我們提供的全局對象
2 增
window.dom = {
//創建節點
create(string) {
const container = document.createElement("template")
//trim(): 清除string左右兩邊空格
container.innerHTML = string.trim()
return container.content.firstChild
},
//新增弟弟
//因爲沒有insertAfter(), 所以思路: 通過獲取最後的下一個插入之前, 相當於最後一個插入之後(如果沒有下一個節點, 那麼默認爲text或者null, 最終也能實現)
after(node, node2) {
node.parentNode.insertBefore(node2, node.nextSibling)
},
//新增哥哥
before(node, node2) {
node.parentNode.insertBefore(node2, node)
},
//新增兒子
append(parent, node) {
parent.appendChild(node)
},
//新增爸爸
wrap(node, parent) {
dom.before(node, parent)
dom.append(parent, node)
}
};
VScode打開設置快捷鍵: command
+,
自動格式化代碼:
@@@
-
爲啥test直接就是對應的id爲test的div
因爲window.test是直接獲取id名爲test的方式, 可簡寫爲test. -
運行的before, after和append爲什麼只執行一次
@@問題@
3 刪除
//刪除節點, 考慮到最新語法node.remove()會不兼容, 採用: 找到node父節點然後刪除其子節點, 並返回node
remove(node) {
node.parentNode.removeChild(node)
//保留節點引用
return node
},
//刪除後代(下一級)
empty(node) {
const array = []
let x = node.firstChild
while (x) {
array.push(dom.remove(node.firstChild))
x = node.firstChild
}
return array
}
4 改
//用於讀寫屬性
//重載
attr(node, name, value) {
if (arguments.length === 3) {
node.setAttribute(name, value)
} else if (arguments.length === 2) {
return node.getAttribute(name)
}
},
//用於讀寫文本內容
//適配
text(node, string) {
if (arguments.length === 2) {
if ("innerText" in node) {
//IE方式
node.innerText = string
} else {
//firefox/chrome
node.textContent = string
}
} else if (arguments.length === 1) {
if ("innerText" in node) {
//IE方式
return node.innerText
} else {
//firefox/chrome
return node.textContent
}
}
},
//用於讀寫HTML內容
html(node, string) {
if (arguments.length === 2) {
node.innerHTML = string
} else if (arguments.length === 1) {
return node.innerHTML
}
},
//用於修改style樣式
style(node, name, value) {
if (arguments.length === 3) {
node.style[name] = value
} else if (arguments.length === 2) {
if (typeof name === 'string') {
return node.style[name]
} else if (name instanceof Object) {
const object = name
for (let key in object) {
node.style[key] = object[key]
}
}
}
},
//class的添加/刪除
class: {
add(node, className) {
node.classList.add(className)
},
remove(node, className) {
node.classList.remove(className)
},
has(node, className) {
return node.classList.contains(className)
}
},
//添加數據監聽
on(node, eventName, fn) {
node.addEventListener(eventName, fn)
},
off(node, eventName, fn) {
node.removeEventListener(eventName, fn)
}
5 查
//獲取單個/多個標籤
find(selector, scope) {
return (scope || document).querySelectorAll(selector)
},
//獲取父元素
parent(node) {
return node.parentNode
},
//獲取子元素
children(node) {
return node.children
},
//用於獲取兄弟姐妹元素
siblings(node) {
return Array.from(node.parentNode.children).filter(n => n !== node)
},
//獲取弟弟
next(node) {
let x = node.nextSibling
while (x && x.nodeType === 3) {
x = x.nextSibling
}
return x
},
//獲取哥哥
previous(node) {
let x = node.previousSibling
while (x && x.nodeType === 3) {
x = x.previousSibling
}
return x
},
//遍歷所有節點
each(NodeList, fn) {
for (let i = 0; i < NodeList.length; i++) {
fn.call(null, NodeList[i])
}
},
//獲取排名第幾
index(node) {
let list = dom.children(node.parentNode)
let i
for (i = 0; i < list.length; i++) {
if (list[i] === node) {
break
}
}
return i
}
37.3 視頻:總結
vscode打開多個窗口: ctrl
+shift
+n
38. 【JS編程接口】jQuery 中的設計模式(上)
38.1 創建項目
38.2 閉包 & 鏈式操作
38.3 實現find函數
- jQuery是構造函數嗎?
1 是
因爲jQuery函數確實構造了一個對象
2 不是
因爲不需要寫new jQuery就能構造一個對象(以前講的構造函數都要結合new纔行)
3 結論
jQuery是一個不需要加new的構造函數
jQuery不是常規意義上的構造函數, 這是因爲jQuery用了一些技巧(目前沒必要講)
(口頭上)jQuery對象是指jQuery函數構造出來的對象, jQuery是一個函數.
38.4 $div.find返回新的api對象
定義const必須要賦值.
38.5 實現end函數
38.6 實現each/parent/ children
38 【JS編程接口】jQuery 中的設計模式(下)
39.1 window.$ = window.jQuery
多等號是從右向左執行
39.2 $div v.s. div
變量使用$開頭, 則表示該變量爲jQuery對象, 正常寫的話一般來說是DOM對象.
39.3 jQuery.prototype
原型的本意就是節約內存
JS中只有淺複製, 沒有深複製.
39.4 jQuery.prototype 續
- 構造prototype:
1 變量問題
2 添加constructor
39.5 設計模式是什麼
39.【JS編程接口】DOM事件和事件委託
39.1 視頻:捕獲與冒泡
2002年, W3C發佈標準, 文檔名爲DOM Level 2 Events Specification, 規定瀏覽器應該同時支持兩種調用順序, 首先 爺爺->爸爸->兒子(由外到內找監聽函數, 叫事件捕獲), 然後按兒子->爸爸->爺爺(由內到外找監聽函數, 叫事件冒泡).有監聽函數就調用, 並提供時間信息, 沒有就跳過.
開發者自己選擇事件放在捕獲階段還是冒泡階段.
39.2 視頻:W3C事件模型
39.3 視頻:target, currentTarget, 取消冒泡
39.4 視頻:如何阻止滾動
39.5 視頻:自定義事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id=div1>
<button id=button1>點擊觸發 frank 事件
</button>
</div>
</body>
</html>
button1.addEventListener('click', ()=>{
//創建自定義時間frank
const event = new CustomEvent("frank", {"detail":{name:'frank', age: 18}})
button1.dispatchEvent(event)
})
button1.addEventListener('frank', (e)=>{
console.log('frank')
console.log(e)
})
39.6 視頻:事件委託
39.7 視頻:擴展內容(玄學)
40.【項目】前航項目介紹
41.【項目】前端導航站點-上
41.1 視頻:項目介紹
41.2 視頻:製作手機頁面
41.3 視頻:製作PC頁面
41.4 視頻:寫HTML和CSS
41.5 視頻:使用Icon
41.6 視頻:導入圖片
41.7 視頻:創建站點
- 引入jQuery
1通過bootcdn, 選擇min.js的鏈接到index.html的main.js之前.
2 判斷是否引入成功jQuery
console.log($)
console.log(jQuery)
- 尋找ul中的最後一個li標籤
//li.last失效, 改用li:last
const $lastLi = $siteList.find('li:last')
41.8 視頻:使用hashMap和localStorage
- 爲什麼header和main等標籤都需要加class.
防止以後有人來寫該項目代碼的時候, 直接用header等標籤來添加樣式, 這樣會使得疊加了之間其他地方的樣式.
const hashMap = []
正常情況下會是一個全局變量, 因爲在parcel中所以就多了一層作用域使得hashMap不是全局變量, 在parcel中全局變量寫法window.hashMap
- 清除除了最後一個li的所有li
// li:not(.last)失效, 改用li:not(:last)
$siteList.find('li:not(:last)').remove()
- 勾選chrome瀏覽器中的Preserve log可以保留上個網站的console
- localStorage存儲數據
@@@
1 localStorage中的數據什麼情況下會消失
第一種情況(常見): 清除遊覽器的cookie
第二種情況:電腦的硬盤滿了, 然後chrome會智能刪除一些緩存文件.
第三種情況: chrome的無痕窗口模式
@@細節@
2 存儲數據
localStorage只接受string類型
//轉爲string
const string = JSON.stringify(hashMap)
//數據存入localStorage
localStorage.setItem('x', string)
3 獲取數據
//取localStorage數據
const x = localStorage.getItem('x')
//轉爲object
const xObject = JSON.parse(x)
42.【項目】前端導航站點(下)
42.1 視頻:定一個小目標
@@@
1 定一個目標, 實現它
2 沒有完美, 做到看不出bug
@@箴言@
42.2 視頻: 處理logo
處理英文字母變爲大寫:
- js方法
.toUpperCase() - css方法
text-transform: uppercase;
42.3 視頻: 簡化URL
42.4 視頻: 刪除功能
42.5 視頻: PC網頁(媒體查詢)
42.6 視頻: PC網頁樣式優化
42.7 視頻: PC樣式影響了手機樣式
42.8 視頻: 鍵盤事件
42.9 視頻: 發佈到github
- parcel build錯誤:
/Users/bens/Documents/selfStudy/jiRenGu/fangFang-FrontEndSystem/41-FrontEndNavigationSite(1)/navigation/src/index.html: Error in parsing SVG: Unbound namespace prefix: "xlink"
Line: 0
Column: 66
Char: >
添加–no-minify
parcel build src/index.html --no-minify
- 調整parcel生成的index.html下的路徑
先查找命令
parcel build --help
然後找到命令
記得清空dist目錄後再執行命令
parcel build src/index.html --no-minify --public-url ./
./
可以用網站絕對路徑來替代
42.10視頻: yarn build 一鍵發佈
首先
yarn init -y
在文件package.json添加
{
"scripts": {
"build": "rm -rf dist && parcel build src/index.html --no-minify --public-url ./"
},
"devDependencies": {
"cssnano": "^4.1.10"
},
"name": "navigation",
"version": "1.0.0",
"main": "index.js",
"repository": "https://github.com/bens1320/Navigation.git",
"author": "bens1320 <[email protected]>",
"license": "MIT"
}
42.11 文章: 優秀的項目 = 用心的項目
很多同學認爲前航是一個小項目,不能放在簡歷裏。
這是一個錯誤的觀念。能不能放在簡歷裏完全取決你你有多用心。
比如有一個前端就把導航網頁做成了這樣:https://www.vipbic.com/rank.html
代碼很簡單,但是你就是能看出他的用心,不是麼?
當然我不是讓你也花費大量時間把前航做成他那樣,但是我喜歡你在做項目的時候能夠「用心」。
就說這些,自己體會一下~
43. 打console.log
44.【前後分離】AJAX 的原理
44.1 視頻:下載server.js
AJAX(Async JavaScript And XML): 用JS發送請求和接收響應.
- AJAX是瀏覽器的功能(由微軟IE5推出)
原本是瀏覽器的功能(發請求和收響應), 後面瀏覽器開放出來, 在window上加了個XMLHttpRequest函數, 用這個構造函數(類)可以構造出一個對象, JS通過它實現發請求和收響應.
- node-dev: 自動刷新代碼
安裝
yarn global add node-dev
44.2 視頻:複習server.js的用法
44.3 視頻:挑戰1 - 加載CSS
44.4 視頻:挑戰2 - 加載JS
44.5 視頻:挑戰3 - 加載HTML
動態加載html. 一般不用iframe了, 比較臃腫.用ajax來請求, 比較輕量.
44.6 視頻: onreadystatechange事件
專業的前端: 不會用onload和onerror(圖片, css, js等, 沒想到監聽ajax)事件( 因爲歷史原因:沒有很好匹配ajax,先發明這2個事件, 然後再發明的ajax, 因此報錯監聽不到404錯誤).
因此用onreadystatechange來替代上面2個事件函數.
44.7 視頻: 挑戰4 - 加載XML
DOM不僅僅可以操作HTML還可以操作XML.
44.8 視頻: 挑戰5 - 加載JSON
JSON(JavaScript Object Notation): 是一門語言, 它不是編程語言, 而是標記語言(HTML, XML, Markdown).
- 支持的數據類型
string - 只支持雙引號, 不支持單引號和無引號
number - 支持科學計數法
bool - true和false
null - 沒有undefined
array
object - 比較常用
就只有6種, 注意跟JS的7種數據類型區別開來. 不支持函數, 也不支持變量(所以也不支持引用)
JSON是借鑑JS發明的.
-
JSON.parse
-
JSON.stringify
由於JS的數據類型比JSON多, 所以不一定能成功.
44.9 視頻: 加載分頁
44.10 視頻: 總結
45.【前後分離】異步與Promise
45.1 視頻:異步?回調?
打電話叫外賣是異步加回調.
回調是一個名詞.
回調: 寫了卻不用, 給別人調用的函數, 就是回調「回頭你調用一下唄」, 有將來的含義, 類似我回頭請你喫飯.
1 沒有調用f1
2 將f1傳給f2(別人)
傳的方式1(常見):
function f1 (){}
function f2 (){}
f2(f1)
傳的方式2:
f2.f1 = ()=>{}
例子: AJAX中
request.onreadystatechange = () => {}
//等價於
function onreadystatechange(){}
request.setCallback(onreadystatechange)
3 f2調用了f1
45.2 視頻:異步函數的例子
一個函數裏面可能有2個函數, 不要看見return認爲是該函數的return.
這樣得不到搖色子的返回值,需要用回調函數.
面試題:
45.3 視頻:Promise的用法
如果異步任務有兩個結果, 成功或失敗, 怎麼辦?
Promise/A+規範
析構賦值
const {success, fail} = options
//等價於
const success = options.success
const fail = options.fail
function縮寫有this, 箭頭函數沒有this
success(response){}
//等價於
success: function (response){}
以前用jQuery.ajax
然後.done是因爲前端promise規定沒制定之前, jQuery作者自己對比promise規範來自己設定的. 目前來看應該用.then
現在用axios
參考鏈接
45.4 視頻:總結
Promise不可以取消.
Axios發明canceltoken(編號)來終止ajax請求.來達到Promise可以取消的效果.
Promise是前端解決異步問題的統一方案.
46.【前後分離】跨域、CORS、JSONP
46.1 視頻:同源策略
跨域: 面試必必必問,菜逼必定不會答.
可用window.origin
或location.origin
可查看當前網站的源
同源策略是瀏覽器的功能: 不同源的頁面之間, 不準互相訪問數據. 目的是爲了保護用戶隱私.
referer不同. 可通過開發者工具查看.
46.2 視頻:創建兩個server.js
46.3 視頻:修改hosts
46.4 視頻:演示跨域被阻止
通過ajax訪問外網資源都會被阻止.
46.5 視頻:解決方法一:CORS
header中加入: Access-Control-Allow-Origin: 允許指定網站訪問
IE: 6 7 8 9 不支持CORS, 因此出現了JSONP
46.6 視頻:解決方法二:JSONP
callback是jsonp的函數名
46.7 視頻:referer和functionName
46.8 視頻:封裝JSONP
46.9 視頻:面試回答JSONP
46.10 視頻:跨域其他方案
47.【前後分離】靜態服務器
47.1 視頻:靜態服務器
多種類型轉換可以用hash表
47.2 視頻:處理錯誤
錯誤用try
47.3 視頻:問答
48【前後分離】Ajax 實戰:Cookie、Session
48.1 視頻:動態服務器是什麼
靜態服務器: 沒有請求數據庫, 就是靜態服務器.
動態服務器: 請求了數據庫, 就是動態服務器.
48.2 視頻:怎麼做用戶註冊
48.3 視頻:獲取post數據
48.4 視頻:使用cookie標記用戶
48.5 視頻:使用cookie記錄user id
cookie也可以前端設置, 但是不建議, 一般都是後端設置.
48.6 視頻:使用session會話保存用戶信息
防篡改user_id:
1 加密(JWT)
2 把信息隱藏在服務器(session) 一般用文件保存