1.排序法react
const arr = [1, 2, 3, 4, 5, 6]; arr.sort((a, b) => { return b - a; }); const max = arr[0]; console.log(max); // 輸出最大值 6
2.假設法面試
const arr = [2, 1, 3, 5, 4, 6]; for (let i = 1; i < arr.length; i++) { max = arr[0]; const cur = arr[i]; cur > max ? (max = cur) : max; } console.log(max); // 輸出最大值 6
3.內置 Max()方法算法
/** * 內置函數Math.max()支持傳遞多個參數,但不支持直接傳遞一個數組,因此須要藉助apply()來傳遞一個數組。 * * apply()與call()方法相似,區別在於apply()接受的是參數數組,call()接受的是參數列表。 */ const arr = [1, 2, 3, 4, 5, 6]; const max = Math.max.apply(null, arr); console.log(max); // 輸出最大值 6
4.ES6 擴展運算符數據庫
const arr = [1, 2, 3, 4, 5, 6]; console.log(Math.max(...arr)); // 輸出最大值 6
DOM 樹是對 HTML 的抽象,VDOM 就是對真實 DOM 樹的抽象。VDOM 不會觸及瀏覽器的部分,只是存在於 Javascript 空間的樹形結構。編程
虛擬 DOM(VDOM)是真實 DOM 的內存表示,一種編程概念,一種模式。它會和真實的 DOM 同步,在更新 DOM 樹時,虛擬 DOM 使用 diff 算法對比新舊 DOM 的變化,實現局部更新,節省了瀏覽器性能。跨域
DNS(Domain Name System): "域名系統"的英文縮寫,是互聯網上做爲域名和 IP 地址相互映射的一個分佈式數據庫,它用於 TCP/IP 網絡,它所提供的服務是用來將主機名和域名轉換爲 IP 地址的工做。數組
域名解析: 經過域名,最終獲得該域名對應的 IP 地址的過程就是域名解析。瀏覽器
DNS 實例解析:緩存
1.打開瀏覽器,輸入一個域名(例如輸入www.4399.com
),發出一個 DNS 請求到本地 DNS 服務器(中國電信等網絡鏈接服務商提供)。安全
2.本地 DNS 服務器查詢 DNS 請求是否存在緩存記錄,存在,返回結果;不存在,則本地 DNS 服務器向 DNS 根服務器(隨機根服務器d.root.servers.net
)發送查詢請求。
3.DNS 根服務器(DNS 根服務器不記錄存儲具體的域名和 IP 的映射關係
)返回域服務器地址。
4.根據返回結果,本地 DNS 服務器向域服務器(返回對應域服務器地址c.gtld.servers.net
)發送查詢請求。
5.域服務器(域服務器不會直接返回域名與 IP 的映射關係
)返回本域名的解析服務器地址。
6.根據返回結果,本地 DNS 服務器向域名的解析服務器(例如: .4399.com域服務器
)發送查詢請求。
7.域名的解析服務器返回請求域名對應的 IP 地址(例如: 116.207.132.239
)。
8.根據返回結果,本地 DNS 服務器向客戶端返回具體 IP 地址,並將查詢結果緩存在本地 DNS 服務器中,加速下次客戶端的訪問。
/** * naturalWidth && naturalHeight 不兼容IE6/7/8 */ getImageOriginal = () => { let img = document.getElementById("bg-img"); const width = img.naturalWidth; const height = img.naturalHeight; };
類組件: 擁有更多的特性,擁有 state 狀態和生命週期鉤子。
函數組件: 單純接受 props 參數,是一個無狀態組件。
隨着 Hooks 的產生,函數組件也能夠擁有自身的 state 狀態。雖然 Hooks 解決了函數組件 state 的問題,使得代碼更加簡潔輕便,可是類組件仍是擁有着函數組件沒有的其餘特性。
下面例子的標籤語法是 JSX 語法。
/** * JSX 是一個 Javascript 的語法擴展,既不是字符串也不是 HTML,具備 Javascript 的所有功能。 * * JSX 語法中,能夠在大括號中放置任何有效的 Javascript 表達式。 * * JSX 也是一個表達式,能夠賦值給變量、也能夠做爲參數傳入函數。 */ const element = <h1>Hello, World!</h1>;
相同點:
React 組件的數據分爲兩種,props 和 state,兩個數據的改變,均可能會引起組件從新渲染。
(props 和 state 能夠保存信息,信息能夠控制組件的渲染輸出
)
區別:
1.props 是組件的對外接口;state 是組件的內部狀態。
2.props 是傳遞給組件的(相似於函數的形參
);state 是在組件內被組件本身管理的(相似於在一個函數內聲明的變量
)。
3.props 是不可修改的,全部 React 組件都必須像純函數同樣保護它們的 props 不被修改;state 是多變的、能夠修改的,每次 setState 都會異步更新。
Class 類組件: 擁有自身 state 狀態管理,擁有生命週期方法,繼承 ReactComponent 實例化。
無狀態的函數組件: 函數組件沒有連接到 ReactComponent 實例的 this 屬性和生命週期方法。
原則一: 若是你的組件須要訪問 this 就用 Class 實現組件。
原則二: 若是你的組件須要生命週期方法,使用 Class 實現組件。
黃金原則: 若是你可使用無狀態組件,那就使用函數實現一個組件。
總結:
若是可使用無狀態函數,就是儘管用函數。
不然,就使用 Class 類。
setState 函數的弊端: setState 不會馬上改變(更新)React 組件中的 state 值(產生的效果不直觀)。
做用: 函數式的 setState 能夠解決 setState 存在的弊端,讓 setState 函數產生的結果更直觀有效。函數接收兩個參數,第一個是當前的 state 值,第二個是當前的 props 值,函數應該返回一個對象(表明要對 this.setState 的更改)。
// 函數式 setState class Counter extends React.Component { state = { count: 0 }; handleIncrement = () => { this.setState((state, props) => { return { count: state.count + 1, }; }); }; render() { const { count } = this.state; return ( <div> <button onClick={this.handleIncrement}>+++</button> <span>{count}</span> </div> ); } }
React 組件的生命週期分爲三個部分: 裝載期(Mounting)
、更新期(Updating)
、卸載期(Unmounting)
。
1.裝載期(組件第一次在 DOM 樹中渲染的過程)
裝載期調用函數順序:
/** * constructor(創造一個組件的實例,調用對應的構造函數) * * getInitialState(初始化組件的內部狀態this.state) && getDefaultProps(初始化外部接口props) * * componentWillMount(在render函數以前調用,能夠在服務端調用、也能夠在瀏覽器端調用) * * render(返回一個JSX描述結構的純函數) * * componentDidMount(在render函數以後調用,函數調用時,render函數返回的結構已經渲染、組件已經"裝載"到DOM樹中;只能在瀏覽器端調用) */
2.更新期(組件被從新渲染的過程)
更新期調用函數順序:
/** * componentWillReceiveProps(nextProps): 只要是父組件的render函數被調用,render函數裏子組件就會更新, * 無論props變與不變,都會觸發該函數。經過this.setState方法觸發的更新過程不會調用這個函數。 * * shouldComponentUpdate(nextProps, nextState): 決定一個組件何時不須要渲染。返回一個布爾值,true,render從新渲染;false,render不須要渲染。 * * componentWillUpdate(在render函數以前調用,只有在瀏覽器端調用) * * render(渲染純函數,決定了渲染什麼) * * componentDidUpdate(prevProps, prevState): 在render函數以後調用,能夠在服務端調用,也能夠在瀏覽器端調用。 */
3.卸載期(組件從 DOM 中刪除的過程)
卸載期:
/** * componentWillUnmount(React組件要從DOM樹中刪除前,調用卸載函數): componentWillUnmount 中的工做與 componentDidMount相關聯。 * * componenWillUnmount能夠清理React組件生產的內存垃圾,避免形成內存泄漏。 */
shouldComponentUpdate 函數是 React 組件生命週期中更新期的一個具備高性能、決定性的函數。在更新過程當中,React 組件首先調用 shouldComponentUpdate 函數,若是函數返回 true,就繼續更新過程(render 函數);返回 false,就馬上終止更新過程,不會觸發後續更新渲染。
做用:
1.shouldComponentUpdate 函數返回一個布爾值,告知 React 組件在更新過程當中是否要繼續更新。
2.shouldComponentUpdate 函數使用恰當,能夠大大提升 React 組件的性能。
setState 函數調用後觸發組件更新,頁面從新繪製。根據生命週期中的更新期,setState 函數不會調用 componentWillReceiveProps 函數,可是其他的更新函數調用不變。
/** * shouldComponentUpdate(當shouldComponentUpdate函數被調用的時候,this.state沒有獲得更新) * * componentWillUpdate(當componentWillUpdate函數被調用的時候,this.state依然沒有獲得更新) * * render(直到render函數被調用的時候,this.state才獲得更新) * * componentDidUpdate() */
Fiber 是更新過程碎片化的數據結構(每執行完一段更新過程,就把控制權交還React負責任務協調的模塊,比對是否有新的緊急的任務須要更新,有,則優先更新緊急任務;無,則回到節點繼續更新剩餘任務
)。
解決問題:
在 16.0 版本以前的 React 中,更新過程是同步的一層組件套一層組件,逐漸深刻的過程,在更新完全部組件以前不會中止,調用時長長。而 Javascript 具備單線程的特色,每一個同步任務時長不能太長,時長過長會對其餘的輸入的響應削弱甚至無響應,React Fiber 就是爲了解決同步操做時長過長致使的性能問題。
HOC 高階組件: 接受一個組件做爲輸入,返回一個新組件做爲結果的函數。
import React from 'react'; function wrapperComponent(wrappedComponent) { return class WrappingComponent extends React.Component { render() { const {id, ...props} = this.props; return <WrappedComponent {...props}> } } } export default wrapperComponent;
使用場景:
1.重用代碼: 有時一個功能邏輯會在多處 React 組件中使用,利用高階組件的方式把這部分公用邏輯提取出來,就能夠減小組件代碼的重複使用率。
2.修改現有 React 組件的行爲: 對於一些高度封裝的 React 組件(第三方組件或團隊內本身封裝好的組件),對這一類 React 組件進行二次開發時,不想改動封裝組件內部邏輯,利用高階組件的方式就能夠基於原有的組件函數產生新的組件,這樣就不會對原有的組件產生任何改動,保證項目代碼運行正常。
在 React 組件中,循環渲染的組件須要加上 key 屬性,沒有 key 時,React 會發出警告(a key should be provided for list items
),告知咱們組件必需要有 key 屬性。
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((item, index) => { return <li key={item.toString()}>{item}</li>; }); return ( <div> <ul>{listItems}</ul> </div> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById("root") );
key 的做用: key 屬性幫助 React 識別元素,肯定元素的增刪查改;在循環渲染的組件中,能夠根據特定的 key 值,對相應的組件作特別的操做處理等。
類似:
區別:
Hooks 是 React 16.8 中添加的一個全新的 API,它可讓你在不編寫 class 的狀況下使用 state 以及其餘的 React 特性。React Hooks 的意思是,組件儘可能寫成純函數,若是須要外部功能和反作用,就用鉤子把外部的代碼"鉤"進來。React Hooks 就是那些鉤子,你須要什麼功能,就是用什麼鉤子。React 默認提供了一些經常使用的鉤子,或者也可使用封裝屬於本身的鉤子。全部的鉤子都是爲函數引入外部功能,因此 React 約定,鉤子一概使用use
前綴命名。
Hooks 就是 Javascript 函數,可是使用它們會有兩個額外的規則:
只能在函數最外層調用 Hooks。不要再循環、條件判斷或者子函數中調用。
只能在React 的函數組件中調用 Hooks。不要在其餘 Javascript 函數中調用。
一個 Flux 包含四個部分:
Dispatcher: 處理動做分發,維持 Store 之間的依賴關係。
Store: 負責存儲數據和處理數據相關邏輯。
Action: 驅動 Dispatcher 的 Javascript 對象。
View: 視圖部分,負責顯示用戶界面。
Flux 的好處,最重要的就是"單向數據流"的管理方式。在 Flux 的理念中,若是要改變界面,必須改變 store 中的狀態;若是要改變 store 中的狀態,必須派發一個 action 對象。
Flux 流程:
1.用戶訪問 View
2.View 發出用戶指定的 Action。
3.Dispatcher 收到 Action,要求 Store 進行相應的更新。
4.Store 更新後,發出一個"change"事件。
5.View 收到"change"事件後,更新頁面。
options 請求方法的主要用途有兩個:
1.獲取服務器支持的 HTTP 請求方法。
2.用來檢查服務器的性能(形如: AJAX進行跨域請求時的預檢,須要向另一個域名的資源發送一個HTTP OPTIONS請求頭,用以判斷實際發送的請求是否安全
)。
HTTPS 原理:
1.客戶端(Client)發起一個 HTTPS 的請求。
2.服務端(Server)把事先配置好的公鑰證書返回給客戶端。
3.客戶端驗證公鑰證書有效性,驗證經過則繼續;不經過則顯示警告信息。
4.客戶端使用僞隨機數生成器生成加密所使用的對稱密鑰,而後使用證書的公鑰加密這個對稱密鑰,發送給服務端。
5.服務端使用本身的私鑰解密這個消息,得到密鑰。
6.服務端使用得到的對稱密鑰加密"明文內容 A",發送給客戶端。
7.客戶端使用對稱密鑰解密響應的密文,獲得"明文內容 A"。
8.客戶端再次發起 HTTPS 請求,使用對稱密鑰加密請求的"明文內容 B"。
9.服務端使用以前得到的對稱密鑰解密密文,獲得"明文內容 B"。
區別:
一、https 協議須要到 ca 申請證書,通常免費證書較少,於是須要必定費用。
二、http 是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的 ssl 加密傳輸協議。
三、http 和 https 使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是 80,後者是 443。
四、http 的鏈接很簡單,是無狀態的;HTTPS 協議是由 SSL+HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議,比 http 協議安全。
1.flat() 方法
const arr = [[1, 2], [3, 4], 5, 6]; console.log(arr.flat()); // 輸出: [1,2,3,4,5,6]
2.reduce() 與 concat() 方法
const arr = [[1, 2], [3, 4], 5, 6]; console.log(arr.reduce((acc, val) => acc.concat(val), [])); // 輸出: [1,2,3,4,5,6]
3.擴展運算符
const arr = [[1, 2], [3, 4], 5, 6]; console.log([].concat(...arr)); // 輸出: [1,2,3,4,5,6]
4.正則式
const arr = [[1, 2], [3, 4], 5, 6]; const results = JSON.parse( "[" + JSON.stringify(arr).replace(/\[|\]/g, "") + "]" ); console.log(results); // 輸出: [1,2,3,4,5,6]
1.ES6 Set() 方法
const arr = [1, 3, 2, 4, 3, 1, 5, 2]; console.log([...new Set(arr)]); // 輸出: [1,3,2,4,5]
2.兩層 for 循環 + splice()
const arr = [1, 3, 2, 4, 3, 1, 5, 2]; function unique(arr) { let length = arr.length; for (let i = 0; i < length; i++) { for (let j = i + 1; j < length; j++) { if (arr[i] === arr[j]) { arr.splice(j, 1); length--; j--; } } } return arr; } const results = unique(arr); console.log(results); // 輸出: [1,3,2,4,5]
3.indexOf() 方法
const arr = [1, 3, 2, 4, 3, 1, 5, 2]; const unique = (arr) => { let results = []; for (let i = 0; i < arr.length; i++) { if (results.indexOf(arr[i]) === -1) { results.push(arr[i]); } } return results; }; console.log(unique(arr)); // 輸出: [1,3,2,4,5]
4.includes() 方法
const arr = [1, 3, 2, 4, 3, 1, 5, 2]; const unique = (arr) => { let results = []; for (let i = 0; i < arr.length; i++) { if (!results.includes(arr[i])) { results.push(arr[i]); } } return results; }; console.log(unique(arr)); // 輸出: [1,3,2,4,5]
HTTP 頭域包括通用頭、請求頭、響應頭和實體頭。每一個頭域由域名、冒號、域值組成。
1.通用頭部是客戶端和服務端均可以使用的頭部,能夠在客戶端、服務端和其餘應用程序之間提供一些很是有用的通用功能,如 Date 頭部。
2.請求頭部是請求報文特有的,它們爲服務器提供了一些額外信息,好比客戶端但願接收什麼類型的數據,如 Accept 頭部。
3.響應頭部便於客戶端提供信息,好比,客服端在與哪一種類型的服務器進行交互,如 Server 頭部。
4.實體頭部指的是用於應對實體主體部分的頭部,好比,能夠用實體頭部來講明實體主體部分的數據類型,如 Content-Type 頭部。
1.淺拷貝: 若是數組元素是基本類型,拷貝一份,互不影響;而若是數組元素是對象或者數組,就會拷貝對象和數組的引用。這樣原數組(對象)和新數組(對象)都會改變的複製引用拷貝方法稱爲淺拷貝。數組的concat()
,slice()
方法就是一種淺拷貝。
const arr = [1, 2, { name: "tom" }]; const newArr = arr.concat(); arr[2].name = "jerry"; console.log(arr); // 輸出 [1,2,{name:'jerry'}] console.log(newArr); // 輸出 [1,2,{name:'jerry'}]
實現淺拷貝:
function shallowCopy(obj) { if (typeof obj != "object") return; // 判斷傳入的參數,確保拷貝的只有對象 let newObj = obj instanceof Array ? [] : {}; // 判斷參數obj類型,新建數組或者對象 // 遍歷obj,判斷是obj的屬性才拷貝 for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }
2.深拷貝: 徹底的拷貝一個對象和數組,原數組(對象)和新數組(對象)二者相互分離,二者之間的修改徹底獨立且不會相互影響,這樣的複製引用拷貝方法稱爲深拷貝。JSON.stringify()
方法就是一種深拷貝。
const arr = [1, 2, { name: "tom" }]; const newArr = JSON.parse(JSON.stringify(arr)); arr[2].name = "jerry"; console.log(arr); // 輸出 [1,2,{name:'jerry'}] console.log(newArr); // 輸出 [1,2,{name:'tom'}]
實現深拷貝:
function deepCopy(obj) { if (typeof obj != "object") return; let newObj = obj instanceof Array ? [] : {}; // 判斷屬性值的類型,若是是對象,遞歸調用深拷貝函數 for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
柯里化: 一種將使用多個參數的一個函數轉換成一系列使用一個參數的函數的技術(將一個接受多個參數的函數變爲接受一個參數返回一個函數的固定形式)。
實現柯里化:
function curry() { const _args = [...arguments]; function fn() { _args.push(...arguments); return fn; } fn.toString = function () { return _args.reduce((sum, cur) => sum + cur); }; return fn; }
typeof 是一元操做符,能夠對數據類型進行判斷,返回值是表示操做數類型的一個字符串。可是 Javascript 的數據類型中,Null 和 Object 的 typeof 都返回 object
字符串,難以區分二者數據類型;爲了更好的去區分二者之間的關係,可使用 Object.prototype.toString 來檢驗二者的區分。
var class2type = {}; // 生成class2type映射 "Boolean Number String Function Array Date RegExp Object Error Null Undefined" .split(" ") .map(function (item, index) { class2type["[object " + item + "]"] = item.toLowerCase(); }); function type(obj) { // 兼容IE6 if (obj === null) { return obj + ""; } // 基本類型使用typeof,引用類型使用Object.prototype.toString return typeof obj === "object" || obj === "function" ? class2type[Object.prototype.toString.call(obj)] || "object" : typeof obj; }
防抖: 觸發高頻時間後 N 秒內函數只會執行一次,若是 N 秒內高頻時間再次觸發,則從新計算時間。防抖經常使用於用戶進行搜索輸入節約請求資源......
const debounce = (fn, time) => { let timeout = null; return function () { clearTimeout(timeout); timeout = setTimeout(() => { fn.apply(this, arguments); }, time); }; };
節流: 高頻時間觸發,但 N 秒內只會執行一次,因此節流會稀釋函數的執行頻率。節流經常使用於鼠標不斷點擊觸發、監聽滾動事件......
const throttle = (fn, time) => { let flag = true; return function () { if (!flag) { return; } flag = false; setTimeout(() => { fn.apply(this, time); flag = true; }, time); }; };
1.方法一: 正則式判斷
/** * 1.利用()進行分組。 * * 2.利用/加數字表示引用,例如: /1就是引用第一個分組。 * * 思路: 將[a-zA-Z]作分組,引用分組進行判斷是否有連續重複。 */ const str = "hello"; const str1 = "tom"; function isRepeatStr(str) { return /([a-zA-Z])\1/.test(str); } const res = isRepeatStr(str); const res1 = isRepeatStr(str1); console.log(res); // 輸出 true console.log(res1); // 輸出 false
2.方法二: 字符串
/** * charAt(): 從一個字符串中返回指定的字符。 */ const str = "hello"; const str1 = "tom"; function isRepeatStr(str) { let reg = /[a-zA-Z]/; for (let i = 0; i < str.length; i++) { if (str.charAt(i) == str.charAt(i + 1) && reg.test(str[i])) { return true; } } return false; } const res = isRepeatStr(str); const res1 = isRepeatStr(str1); console.log(res); // 輸出 true console.log(res1); // 輸出 false
1.call() 和 apply() 改變了函數的 this 上下文後便執行該函數,bind() 則是返回改變了上下文後的一個函數。
2.call() 和 apply() 的第一個參數都是要改變上下文的對象,call() 第二個參數以參數列表的形式展示;apply() 第二個參數則是以參數數組的形式展示。
/** * call()語法: * fun.call(thisArg, arg1, arg2,......) * thisArg: 函數運行時指向的this值。 * arg1,arg2......: 綁定函數調用時傳入的參數列表。 */ /** * apply()語法: * apply(thisArg, [argsArray]) * thisArg: 函數運行時指向的this值。 * [argsArray]: 綁定函數調用時傳入的參數數組。 */ /** * bind()語法: * bind(thisArg[, arg1[, arg2[, ......]]]) * thisArg: 函數運行時原函數指向的this值。 * [, arg1[, arg2[, ......]]]: 綁定函數調用時傳入的參數。 */
區別總結: 函數須要改變 this 指向時使用 call()、apply()、bind()。
call(thisArg, ...args)
。apply(thisArg, [...args])
。bind(thisArg, ...args)
。function add(...args) { return args.reduce((a, b) => a + b); } function currying(fn) { let args = []; return function temp(...newArgs) { if (newArgs.length) { args = [...args, ...newArgs]; return temp; } else { let value = fn.apply(this, args); args = []; return value; } }; } let addCurry = currying(add); console.log(addCurry(1)(2)(3)()); // 輸出 6
HTTP 狀態碼:
1xx:指示信息類,表示請求已接受,繼續處理。 2xx:指示成功類,表示請求已成功接受。 3xx:指示重定向,表示要完成請求必須進行更近一步的操做。 4xx:指示客戶端錯誤,請求有語法錯誤或請求沒法實現。 5xx:指示服務器錯誤,服務器未能實現合法的請求。
常見的狀態碼:
200 OK:客戶端請求成功 206 Partial Content:客戶發送了一個帶有Range頭的GET請求,服務器完成了它(當時音頻或視頻文件很大時返回206) 301 Moved Permanently:所請求的頁面已經轉移至新的URL 302 Found:所請求的頁面已經臨時轉移至新的URL 304 Not Modified:客戶端有緩衝的文檔併發出看一個條件性的請求,服務器告訴客戶,原來緩衝的文檔還能夠繼續使用 403 Forbidden:對請求頁面的訪問被禁止 404 Not Found:請求資源不存在 500 Internal Server Error:服務器發生不可預期的錯誤原來緩衝的文檔還能夠繼續使用 503 Server Unavailable:請求未完成,服務器臨時過載或宕機,一段時間後可恢復正常
/** * 大體流程: * * 1.url解析: 瀏覽器輸入url,判斷輸入的url是不是一個合法的url;同時檢查瀏覽器是否存在相對應的緩存,存在,返回緩存並渲染頁面;不存在,則發送DNS請求。 * * 2.DNS域名解析: 瀏覽器向DNS服務器請求解析輸入url對應的IP地址,返回解析的IP地址給客戶端。 * * 3.創建TCP鏈接: 接收解析好的IP地址,根據IP地址和默認端口80,和服務器創建TCP鏈接。 * * 4.發送HTTP請求: 瀏覽器發出讀取文件的HTTP請求。 * * 5.服務器處理請求: 服務器對瀏覽器HTTP請求作出響應,返回相對應的HTML文本給瀏覽器。 * * 6.關閉TCP鏈接: 釋放關閉TCP鏈接。 * * 7.瀏覽器解析HTML,渲染頁面: 瀏覽器接收服務器返回的HTML文本,解析HTML文本內容渲染頁面。 */
數組判斷方法:
1.Array.isArray()
const arr = [1, 2, 3]; const arr1 = "tom"; console.log(Array.isArray(arr)); // 輸出 true console.log(Array.isArray(arr1)); // 輸出 false
2.obj instanceof Array
const arr = [1, 2, 3]; const arr1 = "tom"; console.log(arr instanceof Array); // 輸出 true console.log(arr1 instanceof Array); // 輸出 false
3.obj.constructor === Array
const arr = [1, 2, 3]; const arr1 = "tom"; console.log(arr.constructor === Array); // 輸出 true console.log(arr1.constructor === Array); // 輸出 false
4.Object.prototype.toString
const arr = [1, 2, 3]; const arr1 = "tom"; console.log(Object.prototype.toString.call(arr) === "[object Array]"); // 輸出 true console.log(Object.prototype.toString.call(arr1) === "[object Array]"); // 輸出 false