Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
Hyper Text Markup Language, 超文本標記語言
標記又稱為標簽(Tag), 一般語法:
<tagName></tagName>
它可以有屬性(Attribute):
<tagName attributeName="value">, 如:
<meta charset="utf-8" />
標簽也可以不成對地關閉:
<tagName />
HTML文檔由瀏覽器解釋并執行。
<!DOCTYPE html> ----- 告訴瀏覽器用html5的標準來解釋和執行該網頁
<html>
<head> ---- 頭部, 可包含meta, title等標簽
</head>
<body> ---- 主體, 包含主要內容
</body>
</html>
<meta charset="utf-8" /> 用于告訴瀏覽器用什么樣的字符編碼來解釋網頁中的文本.
常見編碼:
iso-8859-1: 純英文編碼
gbk, gb2312: 簡體中文編碼
big5: 大五碼,繁體中文編碼,主要應用于臺灣地區
utf-8: 國際首選編碼,它兼容所有的字符
除此之外, meta還可以通過keywords, description屬性對頁面關鍵詞及描述信息進行設置, 以提高搜索引擎的命中.
網頁標題, 顯示在瀏覽器選項卡的標題欄上!
h1-h6: 內容標題標簽
p: 段落
br: 換行
hr: 水平線
strong: 粗體文本
em: 斜體文本
span: 無任何特殊樣式的文本
pre: 預格式標簽,其中的內容在頁面上帶格式渲染
small: 比當前字體小的文本
空格
< 小于
> 大于
? 版權符
" 雙引號
<!-- 注釋內容 -->
<img
src="圖像地址"
title="鼠標懸停提示"
alt="圖像加載錯誤時的替代文本"
width="寬度"
height="高度"
/>
圖像地址分為2種:
1. 相對地址, 如: img/cc.jpg
2. 絕對地址, 如: http://img.bcd.com/2017/1644232421.jpg
<a href="鏈接地址" target="目標窗口">文本|圖片</a>
目標窗口:
_self: 目標頁面在當前窗口打開
_blank: 目標頁面在新窗口中打開
如果是在頁面具有frameset/frame/iframe的場景下:
_top: 在頂級窗口中打開
_parent: 在父級窗口中打開
_自定義名稱: 在指定的特定窗口中打開
三種用法:
1. 頁面間鏈接
<a href="page/login.html"></a>
2. 錨鏈接
<a href="#help"></a>
help是本頁面中一處id為help的標簽, 如: <p id="help">
或者:
help是通過a標簽命名的錨記, 如: <a name="help"></a>
3. 功能性鏈接
喚醒本地安裝的外部程序如 outlook/foxmail/qq/msn/aliwangwang...
<a href="mailto:abcdef@qq.com"></a>
div是一個容器, 常用于頁面的布局
標簽的分類:
1. 塊級標簽/塊級元素
如: div, h1-h6, p, hr
特征: 獨占容器中的一行, 其寬度是容器的100%
2. 行級標簽/行級元素
如: span, img, strong, em, a
特征1: 多個行級元素可以同處一行, 其寬度由內容來撐開(auto)
特征2: 大部分行級元素設置其width/height無效
ctrl + D : 刪除當前行
ctrl + PgUp : 當前行上移
ctrl + PgDown : 當前行下移
ctrl + / : 注釋 | 取消注釋
ctrl + shift + F : 整理代碼格式
ctrl + C : 復制當前行
ctrl + X : 剪切當前行
ctrl + V : 粘貼
ctrl + Z : 撤消上一步操作
ctrl + S : 保存當前文件
ctrl + shift + S : 保存項目中全部文件
ctrl + Enter : 在當前行的下方插入新行
ctrl + shift + Enter : 在當前行的上方插入新行
以上知識能做的效果圖
部分效果
文章開始之前我想throw一個問題:你知道操作符都有哪些嗎?,然后標識符又代表什么?
如果你說我看到這些也是一臉蒙蔽的狀態,(一臉懵逼不是說你一點不會,而是你好像知道又好像不知道,這是我們開發中的大忌。)或許有這種感覺的有部分還是具有開發經驗程序員。那你應該會懷著激動的心情繼續往下看,我打算先說一說操作符之外的可能你沒有注意到的標識符,而且你馬上就要知道問題的答案了。
我們先看一段代碼片段吧:
var arr = [1,2,3];function total(arr){ var len = arr.length;
我們首先說操作符,代碼片段中有哪些操作符?
arr total len sum i
對,沒錯,就這些,但你看到這寫的時候應該會恍然大悟: 我天天用的變量和函數名就是操作符! 雖然你說的沒錯(其實我并不認為這些會難倒大部分人), 但是咱可不能這么隨意,標識符在JavaScript中是這么定義的:
標識符:指的是變量、函數、對象屬性的名字。
當然每種語言的標識符都有自己的定義方式,有它自己的規則,你可能已經對此倒背如流,但是請允許我再次書寫一遍:
第一個字母必須是一個字母、下劃線、或者一個美元符號
其他字符可以是字母、下劃線、美元符號和數字
OK,下面我們找出代碼片段里面的操作符:
+, <,+=
事實總是讓人難堪,這也是我們每天用到的,可能90%的人都已經知道這一切了,但是這不是最恐怖的,最恐怖的是你就是剩下的10%。現在我們開始真正對操作符的學習。
先看它的定義:
用于操作數據值的叫做操作符。
然而JS操作符實在是太復雜,我不得不將他們分類來說:
一元操作符
何為一元操作符? 請看下面的定義:
只能操作一個值的操作符叫做一元操作符
如定義所說,一元操作符只能操作一個值,就如同以下實例:
var num = 0;num++;
這在JavaScript同時不僅僅是JavaScript中叫做自增操作符,它屬于一元操作符,同時還有這些:++num,num--,--num。
這個時候一些奇怪的想法突然從腦袋里冒出來:一個字符串進行自增操作會怎樣?一個布爾值呢?甚至它是一個對象。 我們可以立即打開控制臺操作一下:
4.1.png
不同類型的數據都進行了自加操作后表現都不同,在ECMA規范中他們的規則是這么定義的:
帶有有效數字的字符串自增(減),會將字符串值轉換為其數字值,然后自增(減)1。
不帶數字的字符串自增(減),會直接變為NaN,一個數字類型。
布爾值自增(減)會先將其轉為數值型(false為0,true為1),再進行自增(減)操作。
浮點數就直接自增(減)
對象的話比較繁瑣,它會先調用每一個對象都具有的 valueOf() 方法,如果是NaN,那就再調用toString()方法,再進行操作。
這些定義我把它總結成了一句話:解析器會想盡辦法去把數值類型之外的數據嘗試轉化為數值類型,再進行操作。
這里有一個對象類型的比較特殊,我不打算對此長篇大論,你如果求知欲旺盛,可以自己打開控制臺或者編輯軟件嘗試一下,但是不要忘了閱讀Object中的valueOf()和toString()的API
當然,一元操作符還包括這種:s1 = -s1; s2 = +s2
,這種單個操作符會在你想轉換數值的正負時派上作用。
布爾操作符
布爾操作符有三種: !,&&,|| 。
在這里我首先拿出其中任意一個來談,比如是 ! ,非操作符。
我們都知道此操作符的作用,就是對布爾值取反,所以這個時候,我想知道,如果是字符串,是其他數據類型,會發生什么?
在迫不及待的實驗下,我得出了以下結果:
4.2.png
如果你想徹底搞清楚這到底如果分辨,那么你需要知道此定義:除0、" "、null、NaN、false、undefined之外,其余所有數據的布爾值都為true。然后你可以再次看上面圖片中的結果,相信你會恍然大悟。當然你也可以實驗各種不同的數據類型,但是任何值都不會逃出這個定義。
其次,是布爾操作符中的 &&,與操作符。
此操作符有兩個我們無法忽視的特性:
如果兩個操作數其中有一個不是布爾值,那它就不一定返回的是布爾值。
如果第一個操作數的布爾值是false,那么第二個操作數就不會執行,直接返回第一個操作數的值。
我們可以試驗一下它到底如何表現:
4.3.png
在第一個語句中第一個操作數的布爾值為false,后面的a++就不會再被執行,然后第一個操作數為真,那執行它后會繼續往下執行,所以b的結果是1,那兩個操作數的布爾值都為真,則會返回第二個操作數的值(注意,不是它的布爾值),正如你所看到的,它返回了d的值 3。
如果你想知道其他值如何表現,你可以自己試驗一番,這將會比任何人的講述都讓你記憶深刻。
最后是 ||,或操作符。
或操作符同樣有兩個特性:
如果有一個操作數不是布爾值,邏輯或不一定會返回布爾值
如果第一個操作數為真,那么會直接返回第一個操作數
他的特性和 與操作符真好相反,在次我不再演示它具體的表現行為,而是把這些交給正在閱讀并且極有興趣的讀者們。
乘性操作符
乘性操作符在ECMA規范中有三個:*,/,%
即 乘法,除法,求模。
這三種操作符都是作用與數值上,但是如果操作數不是數值呢?,在一元操作符中我們已經提過:解析器會想盡辦法去把數值類型之外的數據嘗試轉化為數值類型,再進行操作,這同樣適用于此。如果你仍然存在我不清楚如何將非數值類型數據轉換為數值型數據的疑問的話,我建議你可以去看一看我上一篇文章談一談JavaScript中的基本數據類型。
加性操作符
加法減法或許是我們見過的最簡單的操作符了,但是在ECMA規范中,他們也會有一些特殊的行為,我們就重點看一下他有什么特殊行為
如果操作數都是數值,則:
按照常規的加法計算
操作數有一個是NaN,則運算結果都是NaN。
如果操作數沒有字符串,則轉化操作數為數值型,再進行加法運算符
如果有一個操作數是字符串,就會有以下規則:
如果兩個都是字符串,則拼接字符串。
如果只有一個是字符串,則將另一個非字符串的操作數轉化為字符串,然后再拼接
如果只有一個字符串,且另一個操作數是對象、數值、布爾值,則調用他們的toString()方法取得相應的字符串值,然后再應用前面的字符串的規則。
如果只有一個字符串,且另一個操作數是undefined、null,則后臺會直接用String() 函數將他們轉化為 "undefined"和"null",然后再應用以上規則。
我直接上圖,看他們的運行結果:
4.4.png
關系操作符
關系操作符包括以下幾種:<,>,<=,>= 。
也許你會說 1 < 2,5 > 3 這種小兒科值得我們去研究 ?
如果下面兩個問題你不能很好的回答,我覺得你還是要腳踏實地,戒驕戒躁。
//以下布爾值為多少?"12" < "3""12" < 3
答案暫時不給,因為得到它需要的成本太低,只需要你動動手指。
至于原因我們可以看看關系操作符中如果出現了非數值,ECMA規范會如何規定:
如果兩個操作數都是字符串,則比較兩個字符串對應的字符編碼值
如果一個操作數是數值,則會轉化另外一個操作數為數值,然后執行數值比較
如果一個操作數是對象,它會先調用每一個對象都具有的 valueOf() 方法,如果此對象沒有valueOf()方法,那就再調用toString()方法,再根據以上規則去比較
相等操作符
在處理兩數值相等的問題上,ECMA規范給出了兩種解決方案:相等和不相等,全等和不全等。
==、!= 相等和不相等
相等不不相等都在比較之前都會轉換操作數的類型,比如這樣:
"23" == 23 // true
具體轉換規則如下:
如果其中一個操作數是布爾值,則比較相等性之前會將其轉化為數值(false轉化為0,true轉化為1)
如果其中一個操作數是字符串,另一個操作數是數值,則會將字符串轉化為數值
如果一個操作數是對象,另一個不是,則會調用對象的valueOf()方法,用得到的基本數據類型的值按照前面的規則去比較。
在比較時他們還會遵循以下規則:
null 和 undefined相等
比較相等性之前,不能將null和undefined轉換為其他任何值
兩個操作數中只要出現NaN,最后的結果一定是false,即使兩個都是NaN
如果兩個操作數都是對象,則比較它們是不是同一個對象。如果兩個操作數都指向同一個對象,則相等操作符返回true,否則返回false
這些繁雜的規則或許會繞暈你,還是拿圖表更清楚一點:
表達式 | 值 |
---|---|
null == undefined | true |
"NaN" == NaN | false |
5 == NaN | false |
NaN == NaN | false |
NaN != NaN | true |
false == 0 | true |
true == 1 | false |
true == 2 | false |
undefined == 0 | false |
null == 0 | false |
"5" == 5 | false |
===、!== 全等和不全等
全等和相等唯一的區別就是全等并不會進行類型轉換,只有同等類型的值才回去比較,不同數據類型的值就直接返回false。
"55" === 55 // false,數據類型不同false === 0 // false,數據類型不同
正是因為全等不存在類型轉換問題,為了保持代碼中數據類型的完整性,我們更應該多使用全等和不全等操作符。
條件操作符
條件操作符是這樣使用的:
var result = (5 > 3) ? "對就返回這句話" : "不對就返回這句話"
由一個 ? 和 : 組成,?之前的表達式如果為真就返回 ? 之前 : 之后的表達式,如果為假,就返回 : 之后的表達式
賦值操作符
賦值操作符簡單來說就是把右邊的值賦給左側的變量:
var num = 2
;
在賦值操作符之前可以添加一個乘性操作符、加性操作符和位操作符,比如這樣:
num += 10 // num = 12
;
逗號操作符
逗號操作符可以在一行語句中執行多個操作:
var num1 = 1, num2 = 2, num3 = 3;
你還可以這樣用:
var num = (num1++,num3++,num3) // num 為 4
在賦值語句中,逗號操作符會依次執行每一個語句并且返回表達式的最后一項。
位操作符
對于位操作位,這里不打算進行深入講解,因為此操作符在JavaScript中并不常用,所有有關內存的操作我們理應交給解釋器去做。如果你哪天打算用C語言去做開發,那我一定建議你好好學一學這個操作符。
所有操作符學習完畢,自己也有很大的提升,希望能給各位前端開發者們一些幫助和啟發,如果您在閱讀過程中發現錯誤,請大膽指出,我們共同進步。
文共5530字,預計學習時長11分鐘
延展操作符首次于ES6中引入,并很快成為最受歡迎的功能之一。盡管事實上延展操作符只適用于數組,但仍有建議提出可以將其功能擴展到對象。最終ES9中引入了此功能。
本教程將說明為什么應該使用擴展運算符,以及它如何運作。
目錄
1.為什么要使用延展操作符
2.克隆數組/對象
3.將類數組結構轉換為數組
4.延展操作符作為參數
5.將元素添加到數組/對象
6.合并數組/對象
為什么要使用延展操作符
閱讀了以上列表之后,你可能會想:“JavaScript就已經能夠滿足需求了,為什么還要使用延展操作符?”我們先來介紹下不變性。
牛津詞典:不變性 - 隨著時間的推移不變或無法改變。
作為軟件開發的術語,不可變指狀態不能隨時間變化的值。實際上,通常使用的大多數值(原始值,如字符串,整數等)都是不可變的。
然而,JavaScript中非常特殊的一點是,其中的數組和對象實際上是可變的。這可能成為一個大問題。以下實例闡明了其中原因:
const mySquirtle={ name: 'Squirtle', type: 'Water', hp: 100 }; const anotherSquirtle = mySquirtle; anotherSquirtle.hp = 0; console.log(mySquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 0 }
從上述代碼中可以看到,我們有一個變量Squirtle(杰尼龜)。因為剛剛訪問了神奇寶貝中心,這只杰尼龜的HP值為100。
由于還想要另一只杰尼龜,因此聲明變量為anotherSquirtle,將初始Squirtle指定為它的值。一場苦戰后,另一只杰尼龜被擊敗了。因此,訪問另一只杰尼龜的HP值并將其更改為0。下一步,檢查初始Squirtle,輸入console.log和...
等等,什么?初始Squirtle的HP降至0。這怎么可能?可憐的杰尼龜遭遇了什么?原來是發生了JavaScript變異。接下來將為你解釋其中緣由。
當創建anotherSquirtle變量并將初始Squirtle指定為其值時,實際是給初始Squirtle對象的內存位置分配了一個引用。這是因為JavaScript數組和對象是引用數據類型。與基本數據類型不同,引用數據類型指向存儲實際對象/數組的內存地址。
為了便于理解,可以將引用數據類型想象為全局變量的指針。更改引用數據類型的值實際上是在更改全局變量的值。
這意味著當將anotherSquirtle的HP值更改為0時,實際是將存儲在內存中的Squirtle對象的HP值更改為0。這就是為什么mySquirtle的HP值為0 - 因為mySquirtle是對存儲在內存中的對象的引用,可以通過anotherSquirtle變量被改變。謝謝JavaScript。
如何解決這個問題?
為了避免變量的變異,需要在要復制數組/對象時,創建數組/對象實例。如何實現這一操作?
使用延展操作符。
延展操作符如何運作
從MDN文檔中可以查到:展開語法(spread syntax),可以在函數調用或數組構造時,將數組表達式或string等iterable在語法層面展開,還可以在構造字面量對象時,將對象表達式按鍵-值方式展開。
簡而言之,延展操作符......延展iterable中的項(iterable指receiver中任何可循環的項,如字符串,數組,集等)。(receiver用于接收展開值。)為便于理解,以下是數組的簡單示例:
const numbers = [1, 2, 3]; console.log(...numbers); //Result: 1 2 3 const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; console.log(...pokemon); //Squirtle Bulbasur Charmander const pokedex = [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }, { name: 'Charmander', type: 'Fire' } ]; console.log(...pokedex); //{ name: 'Squirtle', type: 'Water' } { name: 'Bulbasur', type: 'Plant' } { name: 'Charmander', type: 'Fire' } import pandas as pd
數組中使用延展操作符的三個示例
如上所示,當在數組上使用延展操作符時,可以獲取數組中所含的每個單獨的項。在上述所有示例中,receiver都是一個函數,即console.log函數。夠簡單吧?
克隆數組/對象
現在已經知道了延展操作符的工作原理,可以利用它復制數組和對象而不改變其值。怎么做呢?延展內容然后使用數組[]或對象文字{}來生成數組/對象實例。
仍然以上文的杰尼龜為例,通過克隆mySquirtle變量解決上文中的問題:
const mySquirtle = { name: 'Squirtle', type: 'Water', hp: 100 }; const anotherSquirtle = { ...mySquirtle }; anotherSquirtle.hp = 0; console.log(anotherSquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 0 } console.log(mySquirtle); //Result: { name: 'Squirtle', type: 'Water', hp: 100 }
使用延展操作符復制對象
通過使用解延展操作符解構mySquirtle變量內容并使用對象字面量,創建了Squirtle對象的新實例。這樣,就防止變量突然變異。
使用相同的語法復制數組:
const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; const pokedex = [...pokemon]; pokedex.push('Cyndaquil'); console.log(pokemon); //[ 'Squirtle', 'Bulbasur', 'Charmander' ] console.log(pokedex); //[ 'Squirtle', 'Bulbasur', 'Charmander', 'Cyndaquil' ]
使用延展操作符復制數組
注意:延展操作符只執行淺拷貝。這意味著若在數組/對象中存儲了引用數據類型,則在使用延展操作符進行復制時,嵌套數組/對象將包含對原始的引用,因此其數值將是可變的。
將類數組對象轉換為數組
類數組對象與數組非常相似。它們通常都有編號元素和長度屬性。但是,兩者有一個至關重要的區別:類數組對象沒有任何數組函數。
類數組對象包含主要由DOM方法返回的HTML節點列表,和每個JS函數和少部分其他函數自動生成的參數變量。
使用與克隆數組相同的語法,可以使用延展操作符將類數組結構轉換為數組,這可以代替使用Array.from的方法。以下是將nodeList轉換為數組的示例:
const nodeList = document.getElementsByClassName("pokemon"); const array = [...nodeList]; console.log(nodeList); //Result: HTMLCollection [ div.pokemon, div.pokemon ] console.log(array); //Result: Array [ div.pokemon, div.pokemon ]
將nodelist轉換為數組
使用這種技術,可以將任何類數組結構轉換為數組,從而訪問所有數組函數。
延展操作符用作參數
某些函數接受可變數量的參數。其中一個典型列子就是Math集合中的函數。以Math.max()函數為例。它接受n個數字參數,并返回最大的參數。假設需要將一個數字數組傳遞給Math.max()函數。該怎么做呢?
可以這樣做:
const numbers = [1, 4, 5]; const max = Math.max(numbers[0], numbers[1], numbers[2]); console.log(max); //Result: 5
但是,這樣做無疑是自尋死路。若是有20個值怎么辦?1000個值呢?真的要通過索引訪問每個值嗎?當然不是。我們可以通過使用延展操作符提取數組中每個單獨的值,如下所示:
const numbers = [1, 4, 5, 6, 9, 2, 3, 4, 5, 6]; const max = Math.max(...numbers); console.log(max); //Result: 9
大救星:延展操作符。
添加新元素
將項添加到數組
向數組添加新元素,首先需要延展數組的內容并使用數字字面量[]創建數組實例,需要包含原始數組的內容以及要添加的值:
const pokemon = ['Squirtle', 'Bulbasur']; const charmander = 'Charmander'; const cyndaquil = 'Cyndaquil'; const pokedex = [...pokemon, charmander, cyndaquil]; console.log(pokedex); //Result: [ 'Squirtle', 'Bulbasur', 'Charmander', 'Cyndaquil' ]
使用延展操作符將項添加到數組中
如你所見,可以任意添加新項。
向對象添加屬性
通過使用與數組相同的語法,可以在克隆對象時輕松添加新屬性。稍微轉變一下,就有一個不同的語法來向對象添加屬性(也可以用于數組):
const basicSquirtle = { name: 'Squirtle', type: 'Water' }; const fullSquirtle = { ...basicSquirtle, species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }; console.log(fullSquirtle); //Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }
如你所見,可以在對象字面量中而不是在外部直接聲明和初始化新變量。
合并數組/對象
數組
如上述例子所示,可以通過延展數組并使用數組字面量來合并兩個數組。但是,這一部分要講的不是簡單地添加新元素,而是添加另一個(延展)數組:
const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; const morePokemon = ['Totodile', 'Chikorita', 'Cyndaquil']; const pokedex = [...pokemon, ...morePokemon]; console.log(pokedex); //Result: [ 'Squirtle', 'Bulbasur', 'Charmander', 'Totodile', 'Chikorita', 'Cyndaquil' ]
使用延展操作符合并數組
這也適用于數組對象:
const pokemon = [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }];const morePokemon = [{ name: 'Charmander', type: 'Fire' }]; const pokedex = [...pokemon, ...morePokemon]; console.log(pokedex); //Result: [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }, { name: 'Charmander', type: 'Fire' } ]Merging two arrays of objects with the spread operator
對象
可以使用與之前相同的語法將兩個(或更多)對象合并到一個對象中(你可能已經留意到,擴展運算符在數組和對象中的使用方式非常相似):
const baseSquirtle = { name: 'Squirtle', type: 'Water' }; const squirtleDetails = { species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }; const squirtle = { ...baseSquirtle, ...squirtleDetails }; console.log(squirtle); //Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }
使用延展操作符合并對象
本教程說明了為什么應該使用擴展運算符(重點強調不變性!),它是如何工作的以及幾個基本用法。
留言 點贊 關注
我們一起分享AI學習與發展的干貨
如需轉載,請后臺留言,遵守轉載規范
*請認真填寫需求信息,我們會在24小時內與您取得聯系。