你不知道的16個js原生函數(shù)和屬性的區(qū)別
點擊上方 程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
前言
原生內(nèi)置了很多API, 作用類似,卻也有差千差萬別,了解其區(qū)別,掌握前端基礎(chǔ),是修煉上層,成為前端高級工程師的必備知識,讓我們一起來分類歸納,一起成長吧。
上一篇前端基礎(chǔ)好文:那些你熟悉而又陌生的函數(shù)[2]
屬性獲取 keys, getOwnPropertyNames, getOwnPropertySymbols
Object.keys[3]
返回一個由一個給定對象的自身可枚舉屬性組成的數(shù)組,數(shù)組中屬性名的排列順序和正常循環(huán)遍歷該對象時返回的順序一致 。
Object.getOwnPropertyNames[4]
返回一個由指定對象的所有自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值作為名稱的屬性)組成的數(shù)組。
Object.getOwnPropertySymbols[5]
一個給定對象自身的所有 Symbol 屬性的數(shù)組。
Reflect.ownKeys[6]
返回一個由目標對象自身的屬性鍵組成的數(shù)組。
等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
例子
const symbolSalary = Symbol.for("salary");
const symbolIsAnimal = Symbol.for("isAnimal");
const symbolSay = Symbol.for("say");
function Person(age, name){
this.age = age;
this.name = name;
this.walk = function () {
console.log("person:walk");
}
}
// 原型方法
Person.prototype.say = function(words){
console.log("say:", words);
}
Person.prototype[symbolSay] = function(words){
console.log("symbolSay", words);
}
// 原型屬性
Person.prototype[symbolIsAnimal] = true;
Person.prototype.isAnimal = true;
const person = new Person(100, "程序員");
person[symbolSalary] = 6000;
person["sex"] = "男";
// sex 不可枚舉
Object.defineProperty(person, "sex", {
enumerable: false
});
Object.defineProperty(person, symbolSalary, {
enumerable: false, // 無效的設(shè)置
value: 999
});
const keys = Object.keys(person);
const names = Object.getOwnPropertyNames(person);
const symbols = Object.getOwnPropertySymbols(person);
const ownKeys = Reflect.ownKeys(person);
console.log("keys", keys); // [ 'age', 'name', 'walk' ]
console.log("getOwnPropertyNames", names); // [ 'age', 'name', 'walk', 'sex' ]
console.log("getOwnPropertySymbols", symbolSalary); // [ Symbol(salary) ]
console.log("ownKeys", ownKeys); // [ 'age', 'name', 'walk', 'sex', Symbol(salary) ]
console.log("--------")
console.log(person.isAnimal); // true
console.log(person[symbolIsAnimal]); // true
console.log(person[symbolSalary]); // 999
person[symbolSay]("hello world"); // symbolSay hello world
person.say("hello world"); // say: hello world
person.walk(); // person:walk
復(fù)制代碼
總結(jié)
-
Object.keys:則返回的是所有可枚舉屬性鍵,也就是屬性下的enumerable: true。但不包括Symbol值作為名稱的屬性鍵。
-
Object.getOwnPropertyNames:返回的是對象所有自己的屬性鍵 ,包括不可枚舉屬性但不包括Symbol值作為名稱的屬性鍵。
-
Object.getOwnPropertySymbols: 方法返回一個給定對象自身的所有 Symbol 屬性鍵的數(shù)組。
-
Reflect.ownKeys: 返回一個由目標對象自身的屬性鍵組成的數(shù)組。等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
節(jié)點位置關(guān)系 Node.contains, Node.compareDocumentPosition
Node.compareDocumentPosition[7]
比較當前節(jié)點與任意文檔中的另一個節(jié)點的位置關(guān)系
語法 compareMask = node.compareDocumentPosition( otherNode )
返回值是一個具有以下值的位掩碼:
| 常量名 | 十進制值 | 含義 |
|---|---|---|
| DOCUMENT_POSITION_DISCONNECTED | 1 | 不在同一文檔中 |
| DOCUMENT_POSITION_PRECEDING | 2 | otherNode在node之前 |
| DOCUMENT_POSITION_FOLLOWING | 4 | otherNode在node之后 |
| DOCUMENT_POSITION_CONTAINS | 8 | otherNode包含node |
| DOCUMENT_POSITION_CONTAINED_BY | 16 | otherNode被node包含 |
| DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | 32 | 待定 |
在一些場景下,可能設(shè)置了不止一位比特值。比如 otherNode 在文檔中是靠前的且包含了 Node, 那么DOCUMENT_POSITION_CONTAINS 和 DOCUMENT_POSITION_PRECEDING 位都會設(shè)置,所以結(jié)果會是 0x0A 即十進制下的 10。
看代碼:
結(jié)果是:20
-
child 在 parent之后,賦值得4 -
child 被 parent包含,賦值的16
4 + 16 = 20
<div id="parent">
<div id="child"></div>
</div>
<script>
const pEl = document.getElementById("parent");
const cEl = document.getElementById("child");
console.log(pEl.compareDocumentPosition(cEl)); // 20
</script>
復(fù)制代碼
Node.contains[8]
返回的是一個布爾值,來表示傳入的節(jié)點是否為該節(jié)點的后代節(jié)點
基本等于compareDocumentPosition的 | DOCUMENT_POSITION_CONTAINED_BY | 16 |otherNode被node包含 |
總結(jié)
-
compareDocumentPosition 返回的是數(shù)字,帶組合意義的數(shù)據(jù),不僅僅可以返回包含,還可以返回在之前之后等信息 -
contains 返回的是布爾值,僅僅告訴你是否有包含關(guān)系
取文本 innerText, textContent
HTMLElement.innerText[9]
解析過程:
-
對HTML標簽進行解析; -
對CSS樣式進行帶限制的解析和渲染; -
將ASCII實體轉(zhuǎn)換為對應(yīng)的字符; -
剔除格式信息(如\t、\r、\n等),將多個連續(xù)的空格合并為一個
Node.textContent[10]
解析過程:
-
對HTML標簽進行剔除; -
將ASCII實體轉(zhuǎn)換為相應(yīng)的字符。
需要注意的是:
-
對HTML標簽是剔除不是解析,也不會出現(xiàn)CSS解析和渲染的處理,因此 <br/>等元素是不生效的。 -
不會剔除格式信息和合并連續(xù)的空格,因此\t、\r、\n和連續(xù)的空格將生效
例子
<p id="source">
<style>
#source {
color: red;
}
</style>
Take a look at<br>how this text<br>is interpreted
below.
<span style="display:none">HIDDEN TEXT</span>
</p>
<h3>Result of textContent:</h3>
<textarea id="textContentOutput" rows="12" cols="50" readonly>...</textarea>
<h3>Result of innerText:</h3>
<textarea id="innerTextOutput" rows="12" cols="50" readonly>...</textarea>
<script>
const source = document.getElementById('source');
const textContentOutput = document.getElementById('textContentOutput');
const innerTextOutput = document.getElementById('innerTextOutput');
textContentOutput.innerHTML = source.textContent;
innerTextOutput.innerHTML = source.innerText;
</script>
復(fù)制代碼
看看結(jié)果:
總結(jié)
-
innerText是會解析css的, <br/>有效,剔除格式信息(如\t、\r、\n等),將多個連續(xù)的空格合并為一個。 -
textContent是剔除html標簽, <br/>無效,\t、\r、\n和連續(xù)的空格將生效。
節(jié)點取值 value , nodeValue
Node.nodeValue[11]
-
對于 text,comment, 和CDATA節(jié)點來說, nodeValue返回該節(jié)點的文本內(nèi)容. -
對于 attribute 節(jié)點來說, 返回該屬性的屬性值.
對應(yīng)著下面表格的 nodeType的值 text 3,4,8
| 常量 | nodeType 值 | 描述 |
|---|---|---|
| Node.ELEMENT_NODE | 1 | 一個 元素 節(jié)點,例如 |
和
|| Node.TEXT_NODE | 3 | Element 或者 Attr 中實際的 文字 || Node.CDATA_SECTION_NODE | 4 | 一個 CDATASection,例如 <!CDATA[[ … ]]>。|| Node.PROCESSING_INSTRUCTION_NODE | 7 | 一個用于XML文檔的 ProcessingInstruction (en-US) ,例如 聲明。|| Node.COMMENT_NODE | 8 | 一個 Comment 節(jié)點。|| Node.DOCUMENT_NODE | 9 | 一個 Document 節(jié)點。|| Node.DOCUMENT_TYPE_NODE | 10 | 描述文檔類型的 DocumentType 節(jié)點。例如 就是用于 HTML5 的。|| Node.DOCUMENT_FRAGMENT_NODE | 11 | 一個 DocumentFragment 節(jié)點 |
value
特定的一些HTMLElement元素,用value屬性獲取其值。常見的有value屬性的元素如下:
-
HTMLInputElement[12] <input value="1" /> -
HTMLTextAreaElement[13] <textarea value= "你哈" /> -
HTMLButtonElement[14] <button value= "提交" /> -
HTMLDataElement[15] <data value="21053">圣女果</data> -
HTMLSelectElement[16] <select><option value ="volvo">Volvo</option> -
HTMLOptionElement[17] <select><option value ="volvo">Volvo</option> -
HTMLParamElement[18]
<object classid="clsid:F08DF954-8592-11D1-B16A-00C0F0283628" id="Slider1" width="100" height="50">
<param name="BorderStyle" value="1" />
</object>
復(fù)制代碼
-
HTMLProgressElement[19] <progress value="22" max="100"></progress>
總結(jié)
-
nodeValue 是文本節(jié)點,屬性節(jié)點,注釋節(jié)點等類型的節(jié)點用來取值的方法 -
vlaue是特定的元素節(jié)點用來取值的方法
節(jié)點復(fù)制 adoptNode, importNode, cloneNode
Document.adoptNode[20]
將外部文檔的一個節(jié)點拷貝一份,然后可以把這個拷貝的節(jié)點插入到當前文檔中.
Document.importNode[21]
從其他的document文檔中獲取一個節(jié)點。該節(jié)點以及它的子樹上的所有節(jié)點都會從原文檔刪除 , 并且它的ownerDocument 屬性會變成當前的document文檔。之后你可以把這個節(jié)點插入到當前文檔中。
Node.cloneNode[22]
生成節(jié)點的一個副本。
實際上 Document 是繼承自 Node, 也具備cloneNode方法。
這里提一個問題:Document.adoptNode與Document.importNode是操作外部文檔的,那么操作所在的文檔會有什么效果呢?
Node.cloneNode 有一個boolean類型的可選參數(shù)deep:
-
true: 則該節(jié)點的所有后代節(jié)點也都會被克隆 -
false: 則只克隆該節(jié)點本身.
注意
-
cloneNode deep參數(shù)在不同版本的瀏覽器實現(xiàn)中,默認值可能不一樣, 所以強烈建議寫上值。 -
cloneNode 會克隆一個元素節(jié)點會拷貝它所有的屬性以及屬性值,當然也就包括了屬性上綁定的事件(比如onclick="alert(1)"),但不會拷貝那些使用addEventListener()方法或者node.onclick = fn這種用JavaScript動態(tài)綁定的事件
總結(jié)
-
adoptNode 從外部文檔進行拷貝 -
importNode 從外部文檔進行拷貝,并從外部文檔刪除 -
cloneNode 從本文檔進行復(fù)制,有淺復(fù)制和深復(fù)制
父節(jié)點 childNodes , children
Node.childNodes[23]
節(jié)點的子節(jié)點集合,包括元素節(jié)點、文本節(jié)點還有屬性節(jié)點
ParentNode.children[24]
返回的只是節(jié)點的元素節(jié)點集合, 即 nodeType為1的節(jié)點。
例子
來實際看一段代碼:
<div id="root">
1
<span>2</span>
3
<!-- <div></div> -->
<!CDATA[[ 4 ]]>
</div>
<script>
const rootEl = document.getElementById("root");
console.log(rootEl.children);
console.log(rootEl.childNodes);
</script>
復(fù)制代碼
返回結(jié)果截圖:
Node.parentNode與Node.parentElement也是同樣的道理。
總結(jié)
-
children只返回元素節(jié)點,也就是 nodeType為1的節(jié)點 -
childNodes 返回所有類型的節(jié)點
添加節(jié)點 append, appendChild
node.appendChild[25]
將一個節(jié)點附加到指定父節(jié)點的子節(jié)點列表的末尾處
ParentNode.append[26]
方法在 ParentNode的最后一個子節(jié)點之后插入一組 Node 對象或 DOMString 對象。被插入的 DOMString 對象等價為 Text 節(jié)點.
例子
我們一次append三個節(jié)點,其中兩個文本節(jié)點,一個div節(jié)點。
<div id="root"></div>
<script>
function createEl(type, innerHTML){
const el = document.createElement(type);
el.innerHTML = innerHTML;
return el;
}
const rootEl = document.getElementById("root");
rootEl.append("我們", createEl("div", "都是"), "好孩子");
</script>
復(fù)制代碼
總結(jié)
-
ParentNode.append()允許追加 DOMString 對象,而 Node.appendChild() 只接受 Node 對象。 -
ParentNode.append() 沒有返回值,而 Node.appendChild() 返回追加的 Node 對象。 -
ParentNode.append() 可以追加多個節(jié)點和字符串,而 Node.appendChild() 只能追加一個節(jié)點。
簡直說, append強大太多了。
文檔可見狀態(tài) Document.hidden, Document.visibilityState
document.hidden[27]
返回布爾值,表示頁面是(true)否(false)隱藏。
Document.visibilityState[28]
返回document的可見性, 由此可以知道當前文檔(即為頁面)是在背后, 或是不可見的隱藏的標簽頁,或者(正在)預(yù)渲染.可用的值如下:
-
'visible' : 此時頁面內(nèi)容至少是部分可見. 即此頁面在前景標簽頁中,并且窗口沒有最小化. -
'hidden' : 此時頁面對用戶不可見. 即文檔處于背景標簽頁或者窗口處于最小化狀態(tài),或者操作系統(tǒng)正處于 '鎖屏狀態(tài)' . -
'prerender' : 頁面此時正在渲染中, 因此是不可見的 . 文檔只能從此狀態(tài)開始,永遠不能從其他值變?yōu)榇藸顟B(tài) .注意: 瀏覽器支持是可選的.
當此屬性的值改變時, 會遞交 visibilitychange 事件給Document.
例子
我們先輸出當前狀態(tài),然后點擊別的tab,等下再點擊回來。
console.log(
"visibilityState:",
document.visibilityState,
" hidden:",
document.hidden,
);
console.log("");
document.addEventListener("visibilitychange", function () {
console.log(
"visibilityState:",
document.visibilityState,
" hidden:",
document.hidden
);
});
復(fù)制代碼
我們?nèi)粘?梢杂?code style="margin: 3px;padding: 3px;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);">visibilitychange來監(jiān)聽當前頁面處于隱藏時,去清除定時器或頁面中的動畫, 停止音樂視頻等的播放。
我還想到一個有意思的
-
廣告倒計時
你離開后,不算倒計時,會不會被罵死
-
閱讀某些協(xié)議
你離開后,停止倒計時
總結(jié)
-
hidden 與 visibilityState 返回值不同,一個是布爾值,一個是字符串 -
visibilityState 的狀態(tài)多一種 prerender, 其對應(yīng)的hidden的值是true -
visibilityState e有相關(guān)的事件
函數(shù)調(diào)用 call, apply, bind
Function.prototype.call[29]
使用一個指定的 this 值和單獨給出的一個或多個參數(shù)來調(diào)用一個函數(shù)
Function.prototype.apply[30]
調(diào)用一個具有給定this值的函數(shù),以及以一個數(shù)組(或類數(shù)組對象)的形式提供的參數(shù)
Function.prototype.bind[31]
方法創(chuàng)建一個新的函數(shù),在 bind() 被調(diào)用時,這個新函數(shù)的 this 被指定為 bind() 的第一個參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時使用
例子
function sum(...args) {
const total = args.reduce((s, cur) => {
return s + cur;
}, 0);
return (this.base || 0) + total;
}
const context = {
base: 1000
};
const bindFun = sum.bind(context, 1, 2);
const callResult = sum.call(context, 1, 2, 3, 4);
const applyResult = sum.apply(context, [1, 2, 3, 4]);
const bindResult = bindFun(3, 4);
console.log("call:", callResult); // 1010
console.log("apply:", applyResult); // 1010
console.log("bind:", bindResult); // 1010
復(fù)制代碼
總結(jié)
相同點,都能改變被調(diào)用函數(shù)的this指向。
-
call: 第二個參數(shù)開始,可以接收任意個參數(shù) -
apply: 第二個參數(shù),必須是數(shù)組或者類數(shù)組 -
bind: 第二個參數(shù)開始,可以接收任意個參數(shù) , 返回的是一個新的函數(shù)
注意點:
-
bind調(diào)用多次,this指向第一次第一個參數(shù)
log 調(diào)用了兩次bind, 第一次bind{ val: 1 }, 第二次bind{ val: 2 }, 輸出的this是一次bind的上下文
function log() {
console.log("this", this);
}
console.log(log.bind({ val: 1 }).bind({ val: 2 })()) // { val: 1 }
復(fù)制代碼
再看一段類似的代碼:
雖然this的指向不會再變改變,但是參數(shù)還是繼續(xù)接受, arguments 長度為2, 第一次bind的1,第二次bind的 2 , 都照單全收。
function log() {
console.log("this", this); // { val: 1 }
console.log("arguments", arguments); // { '0': 1, '1': 2 }
}
console.log(log.bind({ val: 1 }, 1).bind({ val: 2 }, 2)()) // 1
復(fù)制代碼
字符串截取 substr, substring
String.prototype.substr[32]
返回一個字符串中從指定位置開始到指定字符數(shù)的字符
語法:第二參數(shù),是需要截取的長度
str.substr(start[, length])
String.prototype.substring[33]
返回一個字符串在開始索引到結(jié)束索引之間的一個子集, 或從開始索引直到字符串的末尾的一個子集。
語法:第二參數(shù),結(jié)束索引
str.substring(indexStart[, indexEnd])
例子
提示:
-
兩個參數(shù)都沒設(shè)置的時候,效果相同 -
第一個參數(shù)是**大于等于0的整數(shù)**,沒設(shè)置第二參數(shù)的時候,效果相同
const str = "我們都是好孩子";
console.log(str.substr()) // 我們都是好孩子
console.log(str.substring()) // 我們都是好孩子
console.log(str.substr(1)) // 們都是好孩子
console.log(str.substring(1)) // 們都是好孩子
console.log(str.substr(-1)) // 子
console.log(str.substring(-1)) // 我們都是好孩子
console.log(str.substr(1, 2)) // 們都
console.log(str.substring(1, 2)) // 們
復(fù)制代碼
總結(jié)
-
substr 第二個參數(shù)是需要截取的長度 -
substring 第二個參數(shù)是結(jié)束索引值的 -
沒指定參數(shù)或者第一個參數(shù)是大于等于0的整數(shù)時,效果相同 -
第一個參數(shù)是負數(shù)或者第二個參數(shù)是負數(shù),處理規(guī)則不通
具體參見 substr[34]和 substring[35]
遍歷 for of, for in
for in
獲取enumerable:true的屬性鍵
for of
遍歷屬性值。不受到enumerable限制。
例子
-
在數(shù)組原型上增加了方法`gogo`, `for in`結(jié)果中出現(xiàn)了,而 `for of`結(jié)果沖未出現(xiàn)。 -
定義了 屬性2不能被遍歷, `for in`結(jié)果中未出現(xiàn),而 `for of`結(jié)果中出現(xiàn)了。
// 原型上增加方法
Array.prototype.gogo = function(){
console.log("gogo");
}
var a = [1,2,3];
// key值2不可以枚舉
Object.defineProperty(a, 2, {
enumerable: false
});
Object.defineProperty(a, "2", {
enumerable: false
});
for(let p in a){
// 索引被遍歷出來是字符串類型
console.log(p, typeof p); // 0 string; 1 string; gogo string
}
console.log("---")
for(let v of a){
console.log(v); // 1 2 3
}
復(fù)制代碼
總結(jié)
for in
-
獲取enumerable:true的屬性鍵。 -
可以遍歷對象。 -
可以獲取原型上的屬性鍵。 -
數(shù)字屬性鍵被遍歷出來是字符串。比如索引值
for of:
-
遍歷屬性值。不受到enumerable限制。 -
可遍歷數(shù)組。一般不可以遍歷對象,如果實現(xiàn)了Symbol.iterator,可以遍歷。如Array,Map,Set,String,TypedArray,arguments 對象等等 -
不能獲取原型上的值
當前時間 Date.now(), Performance.now()
Date.now\(\)[36]
方法返回自 1970 年 1 月 1 日 00:00:00 (UTC) 到當前時間的毫秒數(shù)。
Performance.now[37]
獲取當前的時間戳的值(自創(chuàng)建上下文以來經(jīng)過的時間),其值是一個精確到毫秒的 DOMHighResTimeStamp[38].
<!DOCTYPE html>
<html lang="en">
<head>
<script>
console.log("p1", performance.now())
</script>
</head>
<body>
<script>
console.log("p2", performance.now());
setTimeout(() => {
console.log("p3", performance.now());
}, 1000)
</script>
</body>
</html>
復(fù)制代碼
總結(jié)
-
Date.now()的基準是1970 年 1 月 1 日 00:00:00 (UTC), 而Performance.now是上下文創(chuàng)建。 -
Date.now()返回的是整數(shù),Performance.now返回的是double類型 -
理論上 Performance.now精度更高
域名信息 host, hostname
location.host[39]
其包含:主機名,如果 URL 的端口號是非空的,還會跟上一個 ':' ,最后是 URL 的端口號
location.hostname
返回域名
例子
https與http的默認端口號,是不會被 host包含的,看下面的代碼
https://developer.mozilla.org:443 的host是 developer.mozilla.org, 因為443是https的默認端口。
var anchor = document.createElement("a");
anchor.href = "https://developer.mozilla.org:443/en-US/Location.host";
console.log(anchor.host == "developer.mozilla.org:443") // false
console.log(anchor.host == "developer.mozilla.org") // true
console.log(anchor.hostname == "developer.mozilla.org:443"); // false
console.log(anchor.hostname == "developer.mozilla.org"); // true
anchor.href = "https://developer.mozilla.org:4097/en-US/Location.host";
console.log(anchor.host == "developer.mozilla.org:4097") // true
console.log(anchor.hostname == "developer.mozilla.org") // true
復(fù)制代碼
總結(jié)
-
默認端口下, host等于hostname -
host額外包含端口號
事件注冊 on, addEventListener
內(nèi)聯(lián)事件
注冊事件。
EventTarget.addEventListener[40]
方法將指定的監(jiān)聽器注冊到 EventTarget 上,當該對象觸發(fā)指定的事件時,指定的回調(diào)函數(shù)就會被執(zhí)行。
例子
分別注冊兩次onclick和click事件,onclick只輸出一次,click輸出兩次.
<button id="btn" >點我</button>
<script>
const btnEl = document.getElementById("btn");
btnEl.onclick = () => console.log("onclick", 1);
btnEl.onclick = () => console.log("onclick", 1);
btnEl.addEventListener("click", ()=> console.log("click", 1));
btnEl.addEventListener("click", ()=> console.log("click", 2));
</script>
復(fù)制代碼
總結(jié)
-
內(nèi)聯(lián)事件是覆蓋型,只能使用事件冒泡,
addEventListener支持多個事件處理程序,并支持事件捕獲。 -
內(nèi)聯(lián)事件特定情況下可以被Node.cloneNode復(fù)制,addEventListener的不行
更多細節(jié)參見 Node.cloneNode[41] -
addEventListener為DOM2級事件綁定,onclick為DOM0級事件綁定
按鍵時間 keypress, keydown
keypress[42]
當按下產(chǎn)生字符值的鍵時觸發(fā)按鍵事件。產(chǎn)生字符值的鍵的示例有字母鍵、數(shù)字鍵和標點鍵。不產(chǎn)生字符值的鍵的例子是修改鍵,如 Alt、 Shift、 Ctrl 或 Meta。
不再推薦使用此功能。盡管一些瀏覽器可能仍然支持它,但它可能已經(jīng)從相關(guān)的 web 標準中刪除
keydown[43]
與keypress事件不同,無論是否生成字符值,所有鍵都會觸發(fā) keydown 事件。
例子
輸入123,keydown和keypress的值keyCode一樣
總結(jié)
-
觸發(fā)順序keydown -> keypress -
keydown:當用戶按下鍵盤上的任意鍵時觸發(fā); -
keypress:當用戶按下鍵盤上的字符鍵時觸發(fā);對中文輸入法支持不好,無法響應(yīng)中文輸入 -
keypress的keyCode與keydown不是很一致;
異步加載腳本 defer,async
defer
異步加載,按照加載順序執(zhí)行腳本的
async
異步加載,亂序執(zhí)行腳本。
這個一圖勝千文
例子
四個script標簽,兩個async,兩個defer。
代碼內(nèi)容如下:
-
async1: console.log("async1"); -
async2: console.log("async2"); -
defer1: console.log("defer1"); -
defer2: console.log("defer2");
<script src="./async1.js" async ></script>
<div>
sdfsdfsdfsdfsdfsdfd
</div>
<script src="./async2.js" async ></script>
<script src="./defer1.js" defer ></script>
<script src="./defer2.js" defer ></script>
復(fù)制代碼
從上面可以看出,有時候 async2會比async1輸出早,defer的輸出也可能比async的輸出早。但是defer的輸出一定 defer1然后defer2
總結(jié)
-
都是異步加載,defer會按照加載順序執(zhí)行,async亂序執(zhí)行
JS魔法堂:被玩壞的innerHTML、innerText、textContent和value屬性[44]
keydown,keypress,keyup三者之間的區(qū)別[45]
關(guān)于本文
作者:云的世界
https://juejin.cn/post/6982742095375597575

“分享、點贊、在看” 支持一波 
