15衍慎、正則
正則就是一個(gè)規(guī)則,用來(lái)處理字符串的規(guī)則
1命迈、正則匹配
編寫(xiě)一個(gè)規(guī)則仇让,驗(yàn)證某個(gè)字符串是否符合這個(gè)規(guī)則,正則匹配使用的是test方法2躺翻、正則捕獲
編寫(xiě)一個(gè)規(guī)則丧叽,在一個(gè)字符串中把符合規(guī)則的內(nèi)容都獲取到;正則的exec公你、字符串的split踊淳、replace、match等方法都支持正則
正則的創(chuàng)建方式以及區(qū)別
1.字面量方式:var reg=/\d/;
2.實(shí)例創(chuàng)建方式 var reg=new RegExp('a','b');支持兩個(gè)參數(shù)陕靠,第一個(gè)為元字符迂尝,第二個(gè)是修飾符
<font color=red>兩種創(chuàng)建方式的區(qū)別:<font>
1,字面量方式中出現(xiàn)一切字符都會(huì)按找元字符來(lái)解析剪芥,所以不能進(jìn)行變量值的拼接垄开,而實(shí)例創(chuàng)建的方式是可以的。
2税肪,字面量方式中直接寫(xiě)\d就可以溉躲,而在實(shí)例創(chuàng)建方式中需要把它轉(zhuǎn)義;只需要在\d之前再加一個(gè)\即可。即\\d
正則的元字符和修飾符
任何一個(gè)正則都是由
元字符
和修飾符
組成的
修飾符
ignoreCase(i):忽略大小寫(xiě);
global(g):全局匹配;找到所有的匹配而不是只找到第一個(gè)匹配
multiline(m):多行匹配;
元字符
代表出現(xiàn)次數(shù)的量詞元字符
* : 出現(xiàn)零到多次
? : 出現(xiàn)0次或1次
+ : 出現(xiàn)1到多次
{n} : 出現(xiàn)n次
{n,} : 出現(xiàn)n到多次
{n,m} : 出現(xiàn)n到m次
具有特殊意義的元字符
\ : 轉(zhuǎn)義字符(兩個(gè)\\就表示兩個(gè)\\)
^ : 以某一個(gè)元字符開(kāi)始益兄,不占位置锻梳。(只對(duì)字符串的開(kāi)頭起作用)
$ : 以某一個(gè)元字符結(jié)尾,不占位置净捅。(只對(duì)字符串的末尾起作用)
. : 除了\n(換行符)以外的任意字符
() : 分組
x|y : x或y中的一個(gè)
[xyz] : x或者y或者z中的一個(gè)
[^xyz] : 除了x y z的任何一個(gè)字符
[a-z] : a-z之間的任何一個(gè)字符
[^a-z] : 除了a-z的任何一個(gè)字符
\d : 一個(gè)0-9之間的數(shù)字
\D : 匹配一個(gè)非數(shù)字字符
\b : 一個(gè)邊界符:“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”,單詞左右兩邊是邊界疑枯,-的左右兩邊也是邊界,所以會(huì)把zhu-feng-pei-xun當(dāng)作4個(gè)單詞蛔六,而我們想把它當(dāng)成一個(gè)單詞
\n : 匹配一個(gè)換行符荆永。
\s : 匹配一個(gè)空白字符 (空格废亭,制表符,換頁(yè)符)
\w : 數(shù)字具钥,字母滔以,下劃線(xiàn)中的任意一個(gè)字符
?: : 只匹配不捕獲
?= : 正向預(yù)查
?! : 負(fù)向預(yù)查
正則中[]的特殊含義
1、里面出現(xiàn)的元字符一般都是代表本身意義的但是有一些依然表示符號(hào)本身的意思如[\d\w]
2氓拼、中括號(hào)中出現(xiàn)'-'代表兩種意思
- [a-z0-9]:- 代表范圍連接符
- [a-z_0-9-]:如果-的左右兩邊任何一邊沒(méi)有內(nèi)容那么’-‘代表本身的意思。
3抵碟、[]中出現(xiàn)的兩位數(shù)不代表本身意思桃漾,而是以一位數(shù)來(lái)解析,如[18]代表1或8兩個(gè)數(shù)字中的一個(gè)拟逮;
正則中()的作用
提高優(yōu)先級(jí)
正則中的分組撬统,也可以理解為一個(gè)大正則中的一個(gè)正則(包起來(lái)的部分是個(gè)一個(gè)整體);我們可以使用小括號(hào)改變一些默認(rèn)的優(yōu)先級(jí)敦迄。如(x|y)
分組引用
(\d)\1:\1代表引用和前面相同的數(shù)字恋追;
分組捕獲
正則捕獲的時(shí)候不僅可以把大正則匹配的內(nèi)容捕獲到,而且也會(huì)把小括號(hào)中的內(nèi)容捕獲到
常用的正則表達(dá)式編寫(xiě)
注意:正則中如果同時(shí)加入了^和 $表示只能是xxx罚屋,不加的話(huà)表示包含xxx苦囱,而且^只對(duì)字符串的開(kāi)頭起作用,$只對(duì)字符串的結(jié)尾起作用脾猛;
reg= /^-?((\d)|([1-9]\d+))(\.\d+)?$/ 有效數(shù)字正則
reg=/^1\d{10}$/ 手機(jī)號(hào)驗(yàn)證
//=>/^[\u4E00-\u9FA5]$/ 中文漢字的正則
姓名的正則:
reg = /^[\u4E00-\u9FA5]{2,10}$/;
reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10})?$/;
郵箱正則
/*
* 以數(shù)字字母下劃線(xiàn)開(kāi)頭
* @前面可以是 數(shù)字撕彤、字母、下劃線(xiàn)猛拴、-羹铅、. 這些符號(hào)
* 不能把 -和. 連續(xù)出現(xiàn),出現(xiàn)一次后面必須跟數(shù)字字母下劃線(xiàn)
*
* @后面的部分支持
* 企業(yè)郵箱
* .com.cn 多域名情況
*/
reg=/^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
身份證:
前六位:省市縣
接下來(lái)八位 出生年+月+日
接下來(lái)的兩位:沒(méi)什么用
倒數(shù)第二位數(shù)字 奇數(shù)為男愉昆,偶數(shù)為女
reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/;
正則的捕獲
exec
正則的捕獲:reg.exec(str)
捕獲的內(nèi)容是一個(gè)數(shù)組职员,數(shù)組中的第一項(xiàng)是當(dāng)前正則捕獲的內(nèi)容,如果有小括號(hào)(),則第二項(xiàng)捕獲的是小括號(hào)里的內(nèi)容跛溉。
- index:捕獲內(nèi)容在字符串中開(kāi)始的索引位置焊切。
- input:捕獲的原始字符串。如果沒(méi)有匹配的返回null芳室;
1蛛蒙、(懶惰性
)捕獲的特點(diǎn):執(zhí)行一次捕獲一次,每次執(zhí)行exec只捕獲第一個(gè)匹配的內(nèi)容渤愁。
為什么會(huì)存在懶惰性牵祟?
- 每個(gè)正則都自帶lastIndex屬性:正則每一次捕獲在字符串中開(kāi)始查找的位置,默認(rèn)值為0抖格;
我們手動(dòng)修改lastIndex的值也不會(huì)影響exec每次開(kāi)始查找的索引诺苹。
如何解決只捕獲第一個(gè)匹配(懶惰性
)咕晋?
在正則末尾加一個(gè)修飾符"g"
原理:
修改lastIndex的值為上一次捕獲內(nèi)容之后的第一個(gè)字符的索引;加了g之后能保證下次捕獲第二個(gè)匹配的內(nèi)容;
通過(guò)加g 每次捕獲結(jié)束后收奔,lastIndex的值都會(huì)改變成最新的值掌呜,下次捕獲從最新的位置開(kāi)始找。如果沒(méi)有找到符合的坪哄,則返回null质蕉;
如何解決exec執(zhí)行一次捕獲一次?
1翩肌、
//我的方法
RegExp.prototype.myExec=function(){
var str=arguments[0]||'',ary=this.exec(str),ary1=[];
if(this.global!==true)return ary;
while(ary){
ary1=ary1.concat(ary);
ary=this.exec(str);
}
return ary1;
}
//老師的方法
RegExp.prototype.myExec=function () {
var str=arguments[0]||'', ary=this.exec(str),result=[];
if(!this.global)return ary;
while (ary){
result.push(ary);
ary=this.exec(str);
}
return result;
}
###match
>用字符串方法方法實(shí)現(xiàn)多次捕獲
str.match(reg)
>1模暗、如果正則中加了修飾符g,那么執(zhí)行一次就可以把所有匹配的結(jié)果捕獲到
>2念祭、如果不加g兑宇,那么只捕獲第一次匹配的結(jié)果。返回一個(gè)數(shù)組粱坤,數(shù)組中是捕獲的每一項(xiàng)隶糕;
`[局限性]`
>在分組捕獲中,
>如果正則不加修飾符g站玄,
> - 那么match和exec一樣枚驻,可以捕獲到小分組的內(nèi)容。
>如果正則加了修飾符g
> - match只能捕獲到大正則匹配的內(nèi)容株旷,而對(duì)于小分組匹配的內(nèi)容是無(wú)法捕獲到的测秸;
`注意`:由于test和exec的原理相同,如果加了g灾常,都是修改lastIndex值來(lái)匹配或者捕獲霎冯,所以使用test和exec都會(huì)修改lastIndex的值,所以使用exec捕獲之前最好不要使用test钞瀑;
用test也可以捕獲符合的字符串
reg.test(str);
RegExp.$1//只能捕獲第1個(gè)小分組里面的內(nèi)容
RegExp.$2//只能捕獲第2個(gè)小分組里面的內(nèi)容
RegExp.$3//只能捕獲第2個(gè)小分組里面的內(nèi)容
同reg.exec(str);也能使用RegExp.$1來(lái)捕獲第1個(gè)小分組
RegExp.$1//只能捕獲第1個(gè)小分組里面的內(nèi)容
RegExp.$2//只能捕獲第2個(gè)小分組里面的內(nèi)容
###所有的支持正則的方法都可以實(shí)現(xiàn)正則的捕獲(一般都是字符串的方法)
>字符串中常用的支持正則的方法:
>- match
>- replace
>- split:如果給的正則中包含小分組沈撞,那么會(huì)把小分組中的內(nèi)容也捕獲到;
>?:只匹配不捕獲雕什, 只能放在小分組的開(kāi)頭缠俺。如果加在分組中邻辉,那么只會(huì)匹配該分組中的內(nèi)容陈瘦,而不會(huì)捕獲
>/(?:&|=)/
>計(jì)算是第幾個(gè)分組的時(shí)候欠肾,我們從左向右找'('即可
var reg = /^-?(\d|([1-9]\d+))(\.\d+)?$/;//=>計(jì)算是第幾個(gè)分組的時(shí)候逝她,我們從左向右找 ( 即可
##replace(第二個(gè)參數(shù)支持直接在字符串中使用$1-9)
>替換字符串
>在不使用正則的情況下,每次執(zhí)行只能替換第一個(gè)匹配的字符串尊浪,而且每次執(zhí)行都是從字符串索引為0的位置開(kāi)始查找
>`第一個(gè)參數(shù)為正則時(shí)`偶妖,正則捕獲幾次肌访,就替換幾次,換成函數(shù)也同理盒使,正則捕獲幾次崩掘,函數(shù)就執(zhí)行幾次,函數(shù)中返回的是什么少办,就相當(dāng)于把正則捕獲的內(nèi)容替換成什么苞慢。
>`第二個(gè)參數(shù)為函數(shù)時(shí)`,正則捕獲幾次英妓,函數(shù)就執(zhí)行幾次挽放,函數(shù)執(zhí)行的時(shí)候還會(huì)默認(rèn)的傳入三個(gè)參數(shù):
>context(捕獲的內(nèi)容)
>index(捕獲內(nèi)容在字符串中的開(kāi)始索引)
>input(原始的字符串)
str.replace(/珠峰/g,function(context,index,input){
arguments[0]大正則匹配的內(nèi)容
//如果正則中有分組的話(huà)
arguments[1]第1個(gè)小分組匹配的內(nèi)容
arguments[2]第2個(gè)小分組匹配的內(nèi)容
…………直到小分組的內(nèi)容顯示完
argument[n]每一次捕獲的開(kāi)始索引
argument[n+1]原始字符串
return 的是什么就會(huì)把正則每次捕獲的內(nèi)容替換成什么
})
需求:把每個(gè)單詞的首字母替換為大寫(xiě),zhu-feng-pei-xun當(dāng)成一個(gè)單詞
var str='my name is zhu-feng-pei-xun,i am 8 years old,i am qian duan pei xun no1!';
var reg=/[a-zA-Z-]+/g;
str=str.replace(reg,function () {
return arguments[0].slice(0,1).toUpperCase()+arguments[0].slice(1);
})
console.log(str);
###時(shí)間格式化字符串
方法1
var str = '2017-11-07 16:37:00';
//=>'2017年11月07日 16時(shí)37分00秒'
//=>使用正則實(shí)現(xiàn)
//1蔓纠、執(zhí)行一次捕獲操作辑畦,得到需要的六個(gè)結(jié)果
var reg = /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})$/g;
// str = str.replace(reg, function () {
// var arg = arguments;
// return arg[1] + '年' + arg[2] + '月' + arg[3] + '日 ' + arg[4] + '時(shí)' + arg[5] + '分' + arg[6] + '秒';
// });
str = str.replace(reg, '$1年$2月$3日 $4時(shí)$5分$6秒');//=>$1等價(jià)于第一個(gè)分組中獲取的內(nèi)容,類(lèi)似于上面代碼的arg[1]
console.log(str);//=>'2017年11月07日 16時(shí)37分00秒'
方法2
String.prototype.myformate=function () {
var ary=this.match(/\d+/g);
var temp=arguments[0]||'{0}年{1}月{2}日 {3}時(shí){4}分{5}秒';
var reg=/\{(\d)\}/g;
temp=temp.replace(reg,function () {
var value=ary[arguments[1]]||'0';
return value.length<2?'0'+value:value;
})
return temp;
}
##16、OOP(面向?qū)ο缶幊趟枷?
###單例模式
>我們把對(duì)象數(shù)據(jù)類(lèi)型實(shí)現(xiàn)`把描述同一件事務(wù)的屬性或者特征歸納匯總在一起贺纲,以此避免全局變量沖突問(wèn)題`的方式和思想叫做:?jiǎn)卫O(shè)計(jì)模式;
>把描述同一件事務(wù)的屬性或者方法存放在某一個(gè)命名空間下褪测,多個(gè)命名空間中的屬性和方法是互不干擾的
```javascript
//=>單例模式
//1猴誊、singleton不僅僅是對(duì)象名了,在單例模式中侮措,singleton稱(chēng)之為 “命名空間(nameSpace)”
var singleton={
xxx:xxx,
...
};
var singleton={
nameSpace1:{
xxx:xxx,
...
},
nameSpace2:{
xxx:xxx,
...
}
...
};
使用單例模式實(shí)現(xiàn)模塊化開(kāi)發(fā)
模塊化開(kāi)發(fā):把一個(gè)復(fù)雜頁(yè)面按照具體功能劃分成幾大塊懈叹,然后由不同的人分別去開(kāi)發(fā),這種模塊劃分的思想就是模塊化開(kāi)發(fā)功能分扎。
//=>項(xiàng)目主管(開(kāi)發(fā)人員):公共模塊
var utils={
trim:function(){}
};
//=>陸永勇:搜索模塊
var searchModel={
submit:function(){
utils.trim();
},
...
};
//=>唐元帥:天氣模塊
var weatherModel={
setWeather:function(){},
...
};
//=>陳金廣:頻道模塊
var channelModel={
show:function(){
//=>在當(dāng)前的命名空間下調(diào)取其它命名空間的方法:指定好對(duì)應(yīng)的命名空間名字即可澄成,使用 [NameSpace].[property] 就可以操作了
searchModel.submit();
//=>調(diào)取本模塊中的一些方法,可以直接使用THIS處理即可:此方法中的THIS一般都是當(dāng)前模塊的命名空間
this.setChannel();
},
setChannel:function(){},
...
};
channelModel.show();
高級(jí)單例模式
基于JS高階編程技巧
惰性思想
畏吓,來(lái)實(shí)現(xiàn)的單例模式墨状,并且可以把一些常用的設(shè)計(jì)模式(如:命令模式、發(fā)布訂閱模式菲饼、promise設(shè)計(jì)模式等)融合進(jìn)來(lái)肾砂,最后清晰的規(guī)劃我們的業(yè)務(wù)邏輯代碼,方便后期二次開(kāi)發(fā)和維護(hù)宏悦,這種設(shè)計(jì)思想綜合體就是高級(jí)單例模式镐确,也是最常用的。
var serchModel=(function(){
function submit(){
}
return {
init:function(){
this.submit();
}
}
})();
searchModel.init();
對(duì)象饼煞、類(lèi)源葫、實(shí)例
對(duì)象:萬(wàn)物皆對(duì)象
類(lèi):對(duì)象的具體細(xì)分(按照屬性或特性細(xì)分的一些類(lèi)別)
實(shí)例:某一個(gè)類(lèi)中的具體事物
JS常用的內(nèi)置類(lèi)
數(shù)據(jù)類(lèi)型的類(lèi)
Number:每個(gè)數(shù)字或者NaN是它的一個(gè)實(shí)例
String:字符串類(lèi)
Boolean:布爾類(lèi)
Null
Undefined:瀏覽器屏蔽了我們操作null和udnefined這個(gè)類(lèi)
Object:對(duì)象類(lèi),每個(gè)對(duì)象數(shù)據(jù)類(lèi)型都是它的實(shí)例
- Array:數(shù)組類(lèi)
- RegExp:正則類(lèi)
- Date:日期類(lèi)
Function:函數(shù)類(lèi)砖瞧,每個(gè)函數(shù)都是它的一個(gè)實(shí)例
元素對(duì)象或者元素集合的類(lèi)
HTMLCollection:元素集合類(lèi)
- getElementsByTagName()
- getElementsByClassName()
- querySelectorAll
NodeList:節(jié)點(diǎn)集合類(lèi)
- childNodes
- getElementsByName()
HTMLDivElement
HTMLElement
Element(標(biāo)簽類(lèi))
Node(節(jié)點(diǎn)類(lèi)息堂,Element只是其中的一個(gè)元素節(jié)點(diǎn))
[圖片上傳失敗...(image-45ab-1541561653878)]
為什么getElementById的上下文只能是document?(即getElementById為什么只能通過(guò)document來(lái)調(diào)用)块促?
因?yàn)橹挥性贒ocument這個(gè)類(lèi)上才有g(shù)etElementById這個(gè)方法储矩,其他類(lèi)上(如:HTMLDivElement類(lèi))沒(méi)有g(shù)etElementById這個(gè)方法感耙,而document是HTMLDocument這個(gè)類(lèi)的一個(gè)實(shí)例,能通過(guò)document._proto_._proto_找到Document這個(gè)類(lèi)的原型上公有的getElementById方法。
[圖片上傳失敗...(image-585c72-1541561653878)]
基于面向?qū)ο髣?chuàng)建數(shù)據(jù)
創(chuàng)建方式:兩種
1.字面量創(chuàng)建方式
- var obj={}持隧;
2.實(shí)例創(chuàng)建方式(構(gòu)造函數(shù)方式)
- var obj=new Array();
1即硼、對(duì)于引用數(shù)據(jù)類(lèi)型來(lái)說(shuō),兩種創(chuàng)建方式是大致相同的屡拨,只不過(guò)只酥,兩種方法創(chuàng)建的語(yǔ)法不同。
兩種創(chuàng)建方式在核心意義上沒(méi)有差別呀狼,都是創(chuàng)建Array這個(gè)類(lèi)的一個(gè)實(shí)例裂允,但是在語(yǔ)法上是有區(qū)別的
1、字面量創(chuàng)建方式傳遞進(jìn)來(lái)什么哥艇,都是給數(shù)組每一項(xiàng)加入的內(nèi)容
2绝编、構(gòu)造函數(shù)創(chuàng)建方式
new Array(10):創(chuàng)建一個(gè)長(zhǎng)度為10的數(shù)組,數(shù)組中的每一項(xiàng)都是空
new Array('10'):如果只傳遞一個(gè)實(shí)參,并且實(shí)參不是數(shù)字貌踏,相當(dāng)于把當(dāng)前值作為數(shù)組的第一項(xiàng)存儲(chǔ)進(jìn)來(lái)
new Array(10,20,30):如果傳遞多個(gè)實(shí)參十饥,不是設(shè)置長(zhǎng)度,而是把傳遞的內(nèi)容當(dāng)做數(shù)組中的每一項(xiàng)存儲(chǔ)起來(lái)
2祖乳、對(duì)于基本數(shù)據(jù)類(lèi)型來(lái)說(shuō)逗堵,字面量方式創(chuàng)建出來(lái)的結(jié)果和實(shí)例方式創(chuàng)建出來(lái)的結(jié)果是有一定區(qū)別的,從嚴(yán)格意義上來(lái)講眷昆,只有實(shí)例創(chuàng)建出來(lái)的結(jié)果才是標(biāo)準(zhǔn)的對(duì)象蜒秤,數(shù)據(jù)類(lèi)型值也是標(biāo)準(zhǔn)的基本數(shù)據(jù)類(lèi)型,也是標(biāo)準(zhǔn)的內(nèi)置類(lèi)的實(shí)例亚斋;對(duì)于字面量方式創(chuàng)建出來(lái)的結(jié)果是基本數(shù)據(jù)類(lèi)型的值作媚,不是嚴(yán)格的實(shí)例,但是由于JS的松散特點(diǎn)帅刊,導(dǎo)致了可以使用 內(nèi)置類(lèi).prototype上提供的方法掂骏;
構(gòu)造函數(shù)設(shè)計(jì)模式
使用構(gòu)造函數(shù)方式,主要是為了創(chuàng)建類(lèi)和實(shí)例的厚掷,也就是基于面向?qū)ο笏枷雭?lái)實(shí)現(xiàn)一些需求
在JS中弟灼,當(dāng)我們使用new xxx()執(zhí)行函數(shù)的時(shí)候,此時(shí)的函數(shù)就不是普通的函數(shù)了冒黑,而是變?yōu)橐粋€(gè)類(lèi)田绑,返回的結(jié)果叫做當(dāng)前類(lèi)的實(shí)例,我們這種new xxx執(zhí)行的方式稱(chēng)之為
構(gòu)造函數(shù)設(shè)計(jì)模式
function fn(){
}
new fn();
構(gòu)造函數(shù)執(zhí)行時(shí)new都干了些什么抡爹?
在new Fn()掩驱,執(zhí)行的時(shí)候,是先把函數(shù)執(zhí)行了,也就是后面的Fn()先執(zhí)行欧穴,形成一個(gè)私有作用域民逼,形參賦值變量提升,在變量提升完了之后涮帘,new操作符才起了作用拼苍,這個(gè)時(shí)候,瀏覽器開(kāi)始創(chuàng)建一個(gè)新的對(duì)象调缨,讓Fn中的this指向這個(gè)新創(chuàng)建的對(duì)象疮鲫,然后讓這個(gè)對(duì)象的_proto_指向Fn.prototype,然后JS代碼才開(kāi)始繼續(xù)往下執(zhí)行弦叶,開(kāi)始往新創(chuàng)建的對(duì)象當(dāng)中添加每個(gè)實(shí)例私有的屬性和方法俊犯。JS代碼執(zhí)行完成后,會(huì)默認(rèn)返回當(dāng)前創(chuàng)建的這個(gè)對(duì)象伤哺。
[圖片上傳失敗...(image-348e4d-1541561653878)]
普通函數(shù)執(zhí)行與構(gòu)造函數(shù)執(zhí)行的區(qū)別
構(gòu)造函數(shù)執(zhí)行的時(shí)候燕侠,也是先形成一個(gè)私有作用域,形參賦值立莉,變量提升绢彤,在代碼從上而下執(zhí)行之前,構(gòu)造函數(shù)有特殊的操作:
瀏覽器會(huì)在當(dāng)前的作用域中默認(rèn)創(chuàng)建一個(gè)對(duì)象數(shù)據(jù)類(lèi)型的值桃序,并且會(huì)讓當(dāng)前函數(shù)中的this指向創(chuàng)建的這個(gè)對(duì)象杖虾。
然后JS代碼再執(zhí)行烂瘫,代碼執(zhí)行完成后媒熊,即使函數(shù)中沒(méi)有寫(xiě)return,在構(gòu)造函數(shù)模式中:瀏覽器會(huì)默認(rèn)的把創(chuàng)建的對(duì)象返回到函數(shù)外面
<font color=red>總結(jié):</font>
- 構(gòu)造函數(shù)執(zhí)行期間坟比,既具備函數(shù)執(zhí)行的一面芦鳍,也同時(shí)具備自己獨(dú)有的操作:在構(gòu)造函數(shù)執(zhí)行期間,瀏覽器會(huì)默認(rèn)創(chuàng)建一個(gè)對(duì)象葛账,這個(gè)對(duì)象就是當(dāng)前這個(gè)構(gòu)造函數(shù)(類(lèi))實(shí)例柠衅,函數(shù)執(zhí)行完成后,瀏覽器會(huì)默認(rèn)的把這個(gè)實(shí)例返回籍琳。所以new Fn()執(zhí)行菲宴,F(xiàn)n是一個(gè)類(lèi),
返回的結(jié)果
就是Fn這個(gè)類(lèi)的一個(gè)實(shí)例
構(gòu)造函數(shù)執(zhí)行后面的‘()’問(wèn)題
構(gòu)造函數(shù)執(zhí)行如果不需要傳遞參數(shù)趋急,函數(shù)后面的()可省略喝峦,如
new Fn()
可寫(xiě)為new Fn
;
注意
:
- 如果要在new Fn之后直接調(diào)用實(shí)例的方法呜达,則必須要加小括號(hào)谣蠢,即必須寫(xiě)成
new Fn().方法名
構(gòu)造函數(shù)模式的返回值問(wèn)題
構(gòu)造函數(shù)模式中默認(rèn)返回值是當(dāng)前的實(shí)例,如果有return,返回分2種情況:
1、return 后面是一個(gè)基本數(shù)據(jù)類(lèi)型的值眉踱,當(dāng)前實(shí)例是不變的挤忙,例如return 100;我們的返回值還是當(dāng)前類(lèi)的實(shí)例谈喳;
2册烈、return 后面是一個(gè)引用數(shù)據(jù)類(lèi)型的值,當(dāng)前實(shí)例會(huì)被返回的值給替換掉例如return {name:"珠峰"}我們的返回值就不再是當(dāng)前類(lèi)的實(shí)例了叁执,而是對(duì)象 {name:"珠峰"}茄厘;
A instanceof B
檢測(cè)某一個(gè)實(shí)例是否屬于這個(gè)類(lèi), 判斷A實(shí)例是否屬于B類(lèi)
attr in object
檢測(cè)attr是否是object的屬性,不管是私有屬性還是公有屬性只要存在谈宛,用in來(lái)檢測(cè)都是true
a.hasOwnProperty(attr)
attr是否是A實(shí)例的私有屬性
對(duì)象數(shù)據(jù)類(lèi)型的
- 普通對(duì)象
- 數(shù)組
- 正則
- Math數(shù)學(xué)函數(shù)
- 一般類(lèi)的實(shí)例
- 函數(shù)的prototype屬性(Function.prototype除外次哈,它是函數(shù)數(shù)據(jù)類(lèi)型的)
- 實(shí)例的_proto_屬性
函數(shù)數(shù)據(jù)類(lèi)型的
- 普通函數(shù)
- 所有的類(lèi)(內(nèi)置類(lèi)和自定義類(lèi)都是)
原型鏈模式
基于構(gòu)造函數(shù)模式的原型鏈模式解決了方法或者屬性公有的問(wèn)題,把實(shí)例之間公有的屬性和方法寫(xiě)在當(dāng)前類(lèi)的prototype屬性上吆录;
1窑滞、每一個(gè)函數(shù)數(shù)據(jù)類(lèi)型都有一個(gè)天生自帶的屬性:prototype(原型),并且這個(gè)屬性的屬性值是一個(gè)對(duì)象數(shù)據(jù)類(lèi)型的值(<font color=red>Function.prototype是函數(shù)數(shù)據(jù)類(lèi)型的,但是它沒(méi)有prototype屬性(Function.prototype.prototype是undefined)恢筝。Array.prototype是一個(gè)數(shù)組</font>)哀卫,瀏覽器默認(rèn)為其開(kāi)辟一個(gè)堆內(nèi)存;
2撬槽、在瀏覽器給prototype開(kāi)辟的這個(gè)堆內(nèi)存中此改,瀏覽器天生給它加了一個(gè)constructor屬性(構(gòu)造函數(shù)),屬性值是當(dāng)前函數(shù)(類(lèi))本身侄柔;
3共啃、每一個(gè)對(duì)象數(shù)據(jù)類(lèi)型(普通對(duì)象、數(shù)組暂题、正則移剪、實(shí)例、protoype..)也天生自帶一個(gè)屬性:_proto_薪者,屬性值指向當(dāng)前實(shí)例所屬類(lèi)的原型(prototype);
(IE中屏蔽了對(duì)象的__proto__屬性纵苛,但是確實(shí)有,只是不讓我們使用而已)
4言津、Object是JS中所有對(duì)象數(shù)據(jù)類(lèi)型的基類(lèi)(最頂層的類(lèi))攻人;
原型鏈模式中的this
原型模式中的this分兩種情況:
1、 在類(lèi)中this.xxx=xxx;this->當(dāng)前類(lèi)的實(shí)例
2悬槽、 原型鏈中提供的私有(公有)方法中的this問(wèn)題:
總結(jié)
:看執(zhí)行的時(shí)候"."前面是誰(shuí)this就是誰(shuí)怀吻。具體操作步驟如下
- 1、需要先確定this的指向(this)
- 2陷谱、把this替換成對(duì)應(yīng)的的代碼
- 3烙博、按照原型鏈查找的機(jī)制瑟蜈,一步步的查找結(jié)果
如何往原型中批量添加屬性和方法
重構(gòu)原型
讓某個(gè)構(gòu)造函數(shù)的原型指向我們自己開(kāi)辟的堆內(nèi)存,但是自己開(kāi)辟的堆內(nèi)存當(dāng)中是沒(méi)有constructor屬性的渣窜,所以要往自己開(kāi)辟的堆內(nèi)存中添加constructor屬性铺根,屬性值為當(dāng)前構(gòu)造函數(shù)本身;
缺點(diǎn):重構(gòu)原型后乔宿,會(huì)導(dǎo)致之前添加的屬性和方法都沒(méi)有了位迂,只能使用重構(gòu)之后添加的屬性和方法;
注意:
- 不要忘了重構(gòu)之后要添加constructor屬性指向當(dāng)前構(gòu)造函數(shù)详瑞;
- 內(nèi)置類(lèi)的原型不能重構(gòu)掂林,瀏覽器不允許我們這么做;
- 重構(gòu)原型之前生成的實(shí)例的
__proto__
屬性值依然指向重構(gòu)之前的原型坝橡,而不是重構(gòu)之后的原型泻帮,只有在重構(gòu)原型之后生成的實(shí)例的__proto__
屬性值才指向新的原型;
17计寇、面向?qū)ο蟮睦斫夂蛯W(xué)習(xí)繼承
面向?qū)ο缶幊?/h2>
它是一種編程思想锣杂,讓我們基于類(lèi)和實(shí)例的概念來(lái)編程開(kāi)發(fā)和學(xué)習(xí)。
類(lèi)的繼承番宁、封裝和多態(tài)
類(lèi)的封裝
把實(shí)現(xiàn)一個(gè)功能的代碼元莫,封裝在一個(gè)函數(shù)當(dāng)中,以后再想實(shí)現(xiàn)這個(gè)功能蝶押,只需要執(zhí)行這個(gè)方法即可踱蠢,不需要重復(fù)的編寫(xiě)代碼,減少了頁(yè)面中的代碼冗余度棋电,提高了代碼的重復(fù)利用率茎截,實(shí)現(xiàn)了低耦合高內(nèi)聚
的思想
類(lèi)的多態(tài)
一個(gè)類(lèi)的多種形態(tài):重載、重寫(xiě)离陶;
[重載]
方法名相同稼虎,參數(shù)不同衅檀,叫做方法的重載
JS中沒(méi)有嚴(yán)格意義上的重載招刨,如果方法名相同,那么就會(huì)保留最后一個(gè)方法哀军,和傳遞的參數(shù)沒(méi)有關(guān)系沉眶;
JS中的重載:根據(jù)傳遞的實(shí)參不同,來(lái)實(shí)現(xiàn)不同的功能杉适』丫螅可以把這種方法叫做重載。
[重寫(xiě)]
JS中的重寫(xiě):子類(lèi)重寫(xiě)父類(lèi)的方法
類(lèi)的繼承
子類(lèi)繼承父類(lèi)的一些屬性和方法
原型繼承
<font color=red>原理</font>:讓子類(lèi)的原型指向父類(lèi)的一個(gè)實(shí)例(很少單獨(dú)使用)
Son.prototype=new Parent();
/繼承父類(lèi)之后猿推,需要手動(dòng)添加constructor屬性
Son.prototype.constructor=Son;
<font color=red>特點(diǎn)</font>:它是把父類(lèi)中私有+公有的屬性和方法的都繼承到了子類(lèi)的原型上(子類(lèi)公有的)
<font color=red>核心</font>:原型繼承是讓子類(lèi)和父類(lèi)之間增加了原型鏈的連接關(guān)系片习,以后子類(lèi)的實(shí)例想要父類(lèi)中的方法捌肴,需要利用原型鏈查找機(jī)制一級(jí)一級(jí)向上查找來(lái)使用
<font color=red>原型繼承存在的問(wèn)題:</font>
- 1、子類(lèi)的原型指向了父類(lèi)的一個(gè)實(shí)例藕咏,如果實(shí)例的某個(gè)屬性的值是引用數(shù)據(jù)類(lèi)型状知,那么我生成子類(lèi)的一個(gè)實(shí)例f,我通過(guò)f來(lái)修改子類(lèi)公有的這個(gè)引用數(shù)據(jù)類(lèi)型的值孽查,那么子類(lèi)的其他實(shí)例也會(huì)受影響饥悴;
- 2、不能向父類(lèi)的構(gòu)造函數(shù)傳遞參數(shù)盲再。如果父類(lèi)給其實(shí)例定義的私有屬性的值跟傳入的參數(shù)有關(guān)系西设,那么子類(lèi)繼承過(guò)來(lái)之后,所有子類(lèi)實(shí)例的公有屬性的值都是一樣的答朋,
call繼承
<font color=red>原理</font>:把父類(lèi)當(dāng)作普通函數(shù)在子類(lèi)中執(zhí)行贷揽,修改函數(shù)中的this為子類(lèi)的實(shí)例。
function A(){
this.x=100;
}
function B(){
//一般都把call繼承放在子類(lèi)函數(shù)體中的第一行,這樣做的好處就是子類(lèi)私有的可以替換掉繼承過(guò)來(lái)的結(jié)果梦碗;
A.call(this);
this.y=200
}
<font color=red>特點(diǎn)</font>:把父類(lèi)私有的屬性和方法克隆一份一模一樣的作為子類(lèi)私有的屬性(父類(lèi)公有的無(wú)法繼承)
寄生組合式繼承(call繼承+Object.create繼承)
<font color=red>總結(jié)</font>:寄生組合式繼承完成了一個(gè)需求
- 子類(lèi)公有繼承了父類(lèi)公有的
- 子類(lèi)私有繼承了父類(lèi)私有的
- 而且子類(lèi)還可以擴(kuò)展自己的實(shí)例公有的屬性和方法(擴(kuò)展到創(chuàng)建的空對(duì)象上)擒滑,而不影響到父類(lèi)
Object.create():創(chuàng)建一個(gè)空對(duì)象,并把傳入的參數(shù)當(dāng)作空對(duì)象的原型叉弦;
<font color=red>原理</font>:把父類(lèi)當(dāng)作函數(shù)在子類(lèi)中執(zhí)行丐一,修改函數(shù)中的this為子類(lèi)的實(shí)例。用Object.create()創(chuàng)建空對(duì)象淹冰,并把傳入的參數(shù)當(dāng)作空對(duì)象的原型库车,把子類(lèi)的原型指向空對(duì)象的原型。
function A(){
this.x=100;
}
function B(){
this.y=200
}
//創(chuàng)建一個(gè)空對(duì)象樱拴,讓傳入的參數(shù)當(dāng)作空對(duì)象的原型柠衍,然后讓B的原型指向這個(gè)空對(duì)象;
B.prototype=Object.create(A.prototype);
//為了保證構(gòu)造函數(shù)的完整性,我們要給子類(lèi)的原型手動(dòng)設(shè)置constructor屬性值
B.prototype.constructor=B;
//Object.create在IE低版本不兼容晶乔,所以我們要自己模擬一個(gè)create方法珍坊。
Object.myCreate=function(){
var Fn=new Function();
Fn.prototype=argument[0];
return new Fn();
}
//以下寫(xiě)法兼容所有瀏覽器;
B.prototype=Object.myCreate(A.prototype);
<font color=red>特點(diǎn)</font>:把父類(lèi)私有的給子類(lèi)私有,把父類(lèi)公有的給子類(lèi)公有正罢。
ES6中的類(lèi)和繼承
ES6中的繼承相當(dāng)于寄生組合式繼承
class Father{//定義一個(gè)類(lèi)阵漏;
constructor(name,age){//構(gòu)造函數(shù)定義實(shí)例的私有屬性
this.name=name;
this.age=age;
}
getName(){//公有的函數(shù)和方法
console.log(this.name,this.age);
}
static like(){//static后寫(xiě)Father當(dāng)做對(duì)象時(shí)的私有屬性
console.log("我是Father函數(shù)的私有屬性")
}
}
class Son extends Father{//子類(lèi)Son繼承父類(lèi)Father
constructor(name,age,color){
注意:super()只能用在子類(lèi)的構(gòu)造函數(shù)之中,用在其他地方會(huì)報(bào)錯(cuò)
super(name,age);//super中的參數(shù)相當(dāng)于把父類(lèi)當(dāng)作普通函數(shù)執(zhí)行時(shí)傳遞給普通函數(shù)的參數(shù)
//下面為子類(lèi)的私有屬性
this.color=color;
}
//下面為子類(lèi)公有的方法
getColor(){
console.log(this.color)
}
static my(){//static后寫(xiě)的是把Son當(dāng)做對(duì)象時(shí)的私有屬性
console.log("我是Son函數(shù)的私有屬性")
}
}
關(guān)于super的兩種情況:
注意翻具,使用super的時(shí)候履怯,必須顯式指定是作為函數(shù)、還是作為對(duì)象使用裆泳,否則會(huì)報(bào)錯(cuò)叹洲。
1、作為函數(shù)執(zhí)行時(shí):
只能在子類(lèi)的構(gòu)造函數(shù)中第一行寫(xiě)super()工禾,此時(shí)就相當(dāng)于Father.call(this);否則會(huì)報(bào)錯(cuò)(比如在子類(lèi)的公有方法中執(zhí)行super);
2运提、作為普通對(duì)象調(diào)用時(shí)
在子類(lèi)的普通方法中(公有方法或私有方法)蝗柔,super指向父類(lèi)的原型,相當(dāng)于Father.prototype民泵,而通過(guò)super.getName(),getName方法中的this依然是子類(lèi)的實(shí)例诫咱,而不是super。
在子類(lèi)的靜態(tài)方法中(把子類(lèi)當(dāng)作對(duì)象添加的方法)洪灯,指向父類(lèi)坎缭。
為什么要手動(dòng)修改constructor?
var a,b;
(function(){
function A (arg1,arg2) {
this.a = 1;
this.b=2;
}
A.prototype.log = function () {
console.log(this.a);
}
a = new A();
b = new A();
})()
a.log();
// 1
b.log();
// 1
它是一種編程思想锣杂,讓我們基于類(lèi)和實(shí)例的概念來(lái)編程開(kāi)發(fā)和學(xué)習(xí)。
類(lèi)的繼承番宁、封裝和多態(tài)
把實(shí)現(xiàn)一個(gè)功能的代碼元莫,封裝在一個(gè)函數(shù)當(dāng)中,以后再想實(shí)現(xiàn)這個(gè)功能蝶押,只需要執(zhí)行這個(gè)方法即可踱蠢,不需要重復(fù)的編寫(xiě)代碼,減少了頁(yè)面中的代碼冗余度棋电,提高了代碼的重復(fù)利用率茎截,實(shí)現(xiàn)了低耦合高內(nèi)聚
的思想
一個(gè)類(lèi)的多種形態(tài):重載、重寫(xiě)离陶;
[重載]
方法名相同稼虎,參數(shù)不同衅檀,叫做方法的重載
JS中沒(méi)有嚴(yán)格意義上的重載招刨,如果方法名相同,那么就會(huì)保留最后一個(gè)方法哀军,和傳遞的參數(shù)沒(méi)有關(guān)系沉眶;
JS中的重載:根據(jù)傳遞的實(shí)參不同,來(lái)實(shí)現(xiàn)不同的功能杉适』丫螅可以把這種方法叫做重載。
[重寫(xiě)]
JS中的重寫(xiě):子類(lèi)重寫(xiě)父類(lèi)的方法
子類(lèi)繼承父類(lèi)的一些屬性和方法
<font color=red>原理</font>:讓子類(lèi)的原型指向父類(lèi)的一個(gè)實(shí)例(很少單獨(dú)使用)
Son.prototype=new Parent();
/繼承父類(lèi)之后猿推,需要手動(dòng)添加constructor屬性
Son.prototype.constructor=Son;
<font color=red>特點(diǎn)</font>:它是把父類(lèi)中私有+公有的屬性和方法的都繼承到了子類(lèi)的原型上(子類(lèi)公有的)
<font color=red>核心</font>:原型繼承是讓子類(lèi)和父類(lèi)之間增加了原型鏈的連接關(guān)系片习,以后子類(lèi)的實(shí)例想要父類(lèi)中的方法捌肴,需要利用原型鏈查找機(jī)制一級(jí)一級(jí)向上查找來(lái)使用
<font color=red>原型繼承存在的問(wèn)題:</font>
- 1、子類(lèi)的原型指向了父類(lèi)的一個(gè)實(shí)例藕咏,如果實(shí)例的某個(gè)屬性的值是引用數(shù)據(jù)類(lèi)型状知,那么我生成子類(lèi)的一個(gè)實(shí)例f,我通過(guò)f來(lái)修改子類(lèi)公有的這個(gè)引用數(shù)據(jù)類(lèi)型的值孽查,那么子類(lèi)的其他實(shí)例也會(huì)受影響饥悴;
- 2、不能向父類(lèi)的構(gòu)造函數(shù)傳遞參數(shù)盲再。如果父類(lèi)給其實(shí)例定義的私有屬性的值跟傳入的參數(shù)有關(guān)系西设,那么子類(lèi)繼承過(guò)來(lái)之后,所有子類(lèi)實(shí)例的公有屬性的值都是一樣的答朋,
<font color=red>原理</font>:把父類(lèi)當(dāng)作普通函數(shù)在子類(lèi)中執(zhí)行贷揽,修改函數(shù)中的this為子類(lèi)的實(shí)例。
function A(){
this.x=100;
}
function B(){
//一般都把call繼承放在子類(lèi)函數(shù)體中的第一行,這樣做的好處就是子類(lèi)私有的可以替換掉繼承過(guò)來(lái)的結(jié)果梦碗;
A.call(this);
this.y=200
}
<font color=red>特點(diǎn)</font>:把父類(lèi)私有的屬性和方法克隆一份一模一樣的作為子類(lèi)私有的屬性(父類(lèi)公有的無(wú)法繼承)
<font color=red>總結(jié)</font>:寄生組合式繼承完成了一個(gè)需求
Object.create():創(chuàng)建一個(gè)空對(duì)象,并把傳入的參數(shù)當(dāng)作空對(duì)象的原型叉弦;
<font color=red>原理</font>:把父類(lèi)當(dāng)作函數(shù)在子類(lèi)中執(zhí)行丐一,修改函數(shù)中的this為子類(lèi)的實(shí)例。用Object.create()創(chuàng)建空對(duì)象淹冰,并把傳入的參數(shù)當(dāng)作空對(duì)象的原型库车,把子類(lèi)的原型指向空對(duì)象的原型。
function A(){
this.x=100;
}
function B(){
this.y=200
}
//創(chuàng)建一個(gè)空對(duì)象樱拴,讓傳入的參數(shù)當(dāng)作空對(duì)象的原型柠衍,然后讓B的原型指向這個(gè)空對(duì)象;
B.prototype=Object.create(A.prototype);
//為了保證構(gòu)造函數(shù)的完整性,我們要給子類(lèi)的原型手動(dòng)設(shè)置constructor屬性值
B.prototype.constructor=B;
//Object.create在IE低版本不兼容晶乔,所以我們要自己模擬一個(gè)create方法珍坊。
Object.myCreate=function(){
var Fn=new Function();
Fn.prototype=argument[0];
return new Fn();
}
//以下寫(xiě)法兼容所有瀏覽器;
B.prototype=Object.myCreate(A.prototype);
<font color=red>特點(diǎn)</font>:把父類(lèi)私有的給子類(lèi)私有,把父類(lèi)公有的給子類(lèi)公有正罢。
ES6中的繼承相當(dāng)于寄生組合式繼承
class Father{//定義一個(gè)類(lèi)阵漏;
constructor(name,age){//構(gòu)造函數(shù)定義實(shí)例的私有屬性
this.name=name;
this.age=age;
}
getName(){//公有的函數(shù)和方法
console.log(this.name,this.age);
}
static like(){//static后寫(xiě)Father當(dāng)做對(duì)象時(shí)的私有屬性
console.log("我是Father函數(shù)的私有屬性")
}
}
class Son extends Father{//子類(lèi)Son繼承父類(lèi)Father
constructor(name,age,color){
注意:super()只能用在子類(lèi)的構(gòu)造函數(shù)之中,用在其他地方會(huì)報(bào)錯(cuò)
super(name,age);//super中的參數(shù)相當(dāng)于把父類(lèi)當(dāng)作普通函數(shù)執(zhí)行時(shí)傳遞給普通函數(shù)的參數(shù)
//下面為子類(lèi)的私有屬性
this.color=color;
}
//下面為子類(lèi)公有的方法
getColor(){
console.log(this.color)
}
static my(){//static后寫(xiě)的是把Son當(dāng)做對(duì)象時(shí)的私有屬性
console.log("我是Son函數(shù)的私有屬性")
}
}
關(guān)于super的兩種情況:
注意翻具,使用super的時(shí)候履怯,必須顯式指定是作為函數(shù)、還是作為對(duì)象使用裆泳,否則會(huì)報(bào)錯(cuò)叹洲。
1、作為函數(shù)執(zhí)行時(shí):
只能在子類(lèi)的構(gòu)造函數(shù)中第一行寫(xiě)super()工禾,此時(shí)就相當(dāng)于Father.call(this);否則會(huì)報(bào)錯(cuò)(比如在子類(lèi)的公有方法中執(zhí)行super);
2运提、作為普通對(duì)象調(diào)用時(shí)
在子類(lèi)的普通方法中(公有方法或私有方法)蝗柔,super指向父類(lèi)的原型,相當(dāng)于Father.prototype民泵,而通過(guò)super.getName(),getName方法中的this依然是子類(lèi)的實(shí)例诫咱,而不是super。
在子類(lèi)的靜態(tài)方法中(把子類(lèi)當(dāng)作對(duì)象添加的方法)洪灯,指向父類(lèi)坎缭。
var a,b;
(function(){
function A (arg1,arg2) {
this.a = 1;
this.b=2;
}
A.prototype.log = function () {
console.log(this.a);
}
a = new A();
b = new A();
})()
a.log();
// 1
b.log();
// 1
a,b签钩,他們同為類(lèi)A的實(shí)例掏呼。因?yàn)锳在閉包里,所以現(xiàn)在我們是不能直接訪(fǎng)問(wèn)A的铅檩,那如果我想給類(lèi)A增加新方法怎么辦憎夷?
這個(gè)時(shí)候就可以通過(guò)a.constructor.prototype 來(lái)給其所屬類(lèi)添加公有的屬性和方法了
18、JS中的DOM盒子模型與一個(gè)盒子垂直水平居中
CSS中的盒子模型
css中的盒子模型有兩種昧旨,分別是 ie 盒子模型和標(biāo)準(zhǔn) w3c 盒子模型
w3c中的CSS盒子模型
[圖片上傳失敗...(image-e9c57d-1541561653878)]
width拾给、height:不是盒子的寬高,而是盒子中內(nèi)容的寬度和高度
盒子的寬=width+padding(left+right)+border(left/right);
CSS3盒子模型與IE中的盒子模型
[圖片上傳失敗...(image-4b0dea-1541561653878)]
width和height不僅僅是內(nèi)容的寬度兔沃,而是代表整個(gè)盒子的寬度(已經(jīng)包含了padding和border)蒋得,以后修改的padding或者border,只會(huì)影響盒子中內(nèi)容的高度乒疏,盒子的大小不會(huì)改變
css3中的盒子模型屬性box-sizing
box{
box-sizing:border-box;
}
box-sizing的可能值:content-box(default)额衙,border-box,inherit(從父類(lèi)繼承)。
content-box:border和padding不計(jì)算入width之內(nèi)怕吴,盒子的寬度=width+padding+border
border-box:border和padding計(jì)算入width之內(nèi)窍侧,盒子的寬度=width
如何選擇<font color="red">w3c盒子模型</font>?
在網(wǎng)頁(yè)的頂部加上 <font color="red">!DOCTYPE</font> 聲明。假如不加 doctype 聲明转绷,那么各個(gè)瀏覽器會(huì)根據(jù)自己的行為去理解網(wǎng)頁(yè)伟件,即 ie 瀏覽器會(huì)采用 ie 盒子模型去解釋你的盒子,而火狐會(huì)采用標(biāo)準(zhǔn) w3c 盒子模型解釋你的盒子议经,所以網(wǎng)頁(yè)在不同的瀏覽器中就顯示的不一樣了斧账。反之,假如加上了 doctype 聲明爸业,那么所有瀏覽器都會(huì)采用標(biāo)準(zhǔn) w3c 盒子模型去解釋你的盒子其骄,網(wǎng)頁(yè)就能在各個(gè)瀏覽器中顯示一致了亏镰。
JS盒模型屬性
通過(guò)JS盒子模型屬性獲取到的結(jié)果都是不帶單位的扯旷,而且只能是正 數(shù)(會(huì)默認(rèn)的進(jìn)行四舍五入),而且只有scrollTop和scrollLeft可讀寫(xiě)索抓,其他都是只讀屬性钧忽;
clientWidth毯炮、clientHeigit(內(nèi)容寬度+padding)
(只讀屬性,每次訪(fǎng)問(wèn)都會(huì)重新計(jì)算耸黑,最好用變量保存)
clientWidth:內(nèi)容寬度Width+左右填充padding
clientHeight:內(nèi)容高度height+上下填充padding
當(dāng)前盒子可視區(qū)域的寬度和高度
可視區(qū)域:內(nèi)容寬高+左右填充padding
和內(nèi)容是否溢出桃煎,以及是否設(shè)置了overflow:hidden沒(méi)有關(guān)系
document.documentElement.clientWidth || document.body.clientWidth:
- 獲取當(dāng)前瀏覽器可視窗口(一屏幕)的寬度
clientTop、clientLeft(盒子邊框的高度和寬度)
clientTop:盒子上邊框的寬度相當(dāng)于border-top
clientLeft:盒子左邊框的寬度相當(dāng)于border-left
獲取的就是邊框的寬度
offsetWidth大刊、offsetHeight(內(nèi)容寬度+padding+border)
只讀屬性
offsetWidth:盒子寬度+pading+border
offsetHeight:盒子高度+pading+border
在clientWidth和clientHeight的基礎(chǔ)上加上了左右或者上下邊框的寬度为迈,和內(nèi)容是否溢出也沒(méi)關(guān)系;
offsetParent缺菌、offsetLeft葫辐、offsetTop
offsetParent:當(dāng)前元素的父級(jí)參照物(在同一個(gè)平面中,最外層的元素是里面所有元素的父級(jí)參照伴郁,和HTML層級(jí)結(jié)構(gòu)沒(méi)有必然的聯(lián)系耿战。一個(gè)頁(yè)面中所有的父級(jí)參照物都是body。標(biāo)準(zhǔn)流中為body)
<font color=red>父級(jí)參照物可通過(guò)position: absolute relative fixed來(lái)改變焊傅;三個(gè)中任何一個(gè)都可以改變父級(jí)參照物剂陡,但是只能改變定位元素子元素的父級(jí)參照物,定位的元素的父級(jí)參照物不改變狐胎。<font>
**offsetLeft:當(dāng)前元素距離其父級(jí)參照物的內(nèi)邊框的左偏移量 **
offsetTop:當(dāng)前元素距離其父級(jí)參照物的內(nèi)邊框的上偏移量
在IE8當(dāng)中鸭栖,是從當(dāng)前元素的外邊框距離其父級(jí)參照物的外邊框的偏移量
當(dāng)前元素的外邊框距離父級(jí)元素參照物內(nèi)邊框的偏移量,父級(jí)參照物默認(rèn)為body
scrollWidth握巢、scrollHeight纤泵、scrollTop、scrollLeft
[沒(méi)有內(nèi)容溢出時(shí)]
獲取的結(jié)果和clientWidth镜粤、clientHeight是一樣的
[有內(nèi)容溢出的時(shí)候]
- scrollHeight:真實(shí)內(nèi)容高度+上填充padding(因?yàn)閮?nèi)容溢出下padding已經(jīng)計(jì)算了所以不用加)
- scrollWidth:真實(shí)內(nèi)容寬度+左填充padding(因?yàn)閮?nèi)容溢出右padding已經(jīng)計(jì)算了所以不用加)
scrollLeft/scrollTop:橫向或縱向滾動(dòng)條卷去的寬度/高度(只有這兩個(gè)可讀寫(xiě))
存在最大最小值:最小為0捏题,最大為卷去的高度/寬度 - 一屏幕的高度clientHeight
[圖片上傳失敗...(image-6e371a-1541561653878)]
獲取元素具體的樣式值
1、ele.style.xxx
- 獲取當(dāng)前元素所有寫(xiě)在行內(nèi)樣式上的值(只有寫(xiě)在行內(nèi)樣式上的才能獲取到)
2肉渴、getComputedStyle/currentStyle(IE8及以下使用currentStyle)都帶單位公荧;
- getComputedStyle(ele,當(dāng)前元素的偽類(lèi)一般為null)同规,獲取的是一個(gè)對(duì)象數(shù)據(jù)類(lèi)型的值循狰,如果需要獲取某一項(xiàng)需要用點(diǎn)或者[]來(lái)訪(fǎng)問(wèn)獲取結(jié)果的某個(gè)屬性
- ele.currentStyle (currentStyle是元素的一個(gè)屬性,而不是一個(gè)方法)獲取結(jié)果也是對(duì)象數(shù)據(jù)類(lèi)型的券勺,獲取某一項(xiàng)也要通過(guò)點(diǎn)或者[]來(lái)訪(fǎng)問(wèn)绪钥;
這兩個(gè)屬性獲取的結(jié)果都是字符串;
如何讓一個(gè)盒子水平垂直居中
1关炼、用CSS
使用定位程腹,需要知道盒子的具體寬高(兼容IE低版本)
position:absolute
top:50%
left:50%
margin:-高度的一半px 0 0 -寬度的一半px;
使用定位:不需要知道盒子的寬和高(不兼容IE低版本)
position:absolute儒拂;
top:0寸潦;
left:0色鸳;
right:0;
bottom:0见转;
margin:auto命雀;
如何讓一個(gè)寬度不固定的塊級(jí)元素居中?
修改display為inline-block
父級(jí)的text-align:center
使用css3方法實(shí)現(xiàn)
position: absolute;
top:50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
2、用JS方法實(shí)現(xiàn)
首先讓盒子先絕對(duì)定位斩箫,然后設(shè)置盒子的left和top值即可
left=(當(dāng)前瀏覽器窗口的寬度-內(nèi)容的寬度)/2+'px'
clientWidth- offsetWidth
left=((document.documentElement.clientWidth || document.body.clientWidth)-ele.offsetWidth)/2+'px'
top=(當(dāng)前瀏覽器窗口的高度-內(nèi)容的高度)/2+'px'
left=((document.documentElement.clientHeight || document.body.clientHeight)-ele.offsetHeight)/2+'px'
19吏砂、JS中的定時(shí)器與異步編程
setTimeout(fn,interval)
設(shè)定一個(gè)定時(shí)器,到達(dá)指定時(shí)間之后執(zhí)行對(duì)應(yīng)的方法(執(zhí)行一次就結(jié)束了)乘客;
)
setInterval(fn,interval)
設(shè)置一個(gè)定時(shí)器赊抖,每間隔多少時(shí)間執(zhí)行一次fn,直到定時(shí)器清除為止(執(zhí)行很多次)
兩個(gè)定時(shí)器的區(qū)別
共同點(diǎn):
設(shè)置定時(shí)器時(shí)都會(huì)有一個(gè)返回值寨典,代表當(dāng)前是在瀏覽器中設(shè)置的第幾個(gè)定時(shí)器(返回的是定時(shí)器的序號(hào)氛雪,不管是setTimeout還是setInterval,)只要遇到這兩個(gè)其中一個(gè)耸成,就算一個(gè)新的定時(shí)器报亩,定時(shí)器的序號(hào)就會(huì)加1,即使清除了設(shè)置的定時(shí)器井氢,也不會(huì)重新計(jì)算序號(hào)弦追。
不同點(diǎn):
setTimeout是隔一段時(shí)間之后執(zhí)行一次函數(shù)
setInterval是每隔一段時(shí)間之后都執(zhí)行一次函數(shù);
用clearTimeout和clearInterval都可以清除兩個(gè)中任何一個(gè)定時(shí)器花竞,傳入的參數(shù)為定時(shí)器的序號(hào)劲件;
為什么我們要手動(dòng)清除定時(shí)器?
定時(shí)器也是一個(gè)函數(shù)约急,函數(shù)執(zhí)行完成后零远,返回了一個(gè)基本數(shù)據(jù)類(lèi)型值(定時(shí)器的序列號(hào))。沒(méi)有產(chǎn)生堆內(nèi)存的話(huà)就會(huì)在空閑時(shí)間被銷(xiāo)毀掉厌蔽,但是為什么setTimeout不會(huì)自動(dòng)銷(xiāo)毀牵辣?
因?yàn)楫?dāng)創(chuàng)建一個(gè)定時(shí)器的時(shí)候,瀏覽器會(huì)同時(shí)開(kāi)啟一個(gè)監(jiān)聽(tīng)者奴饮,當(dāng)setTimeout執(zhí)行完成后纬向,監(jiān)聽(tīng)者始終知道這個(gè)定時(shí)器的地址,所以不能銷(xiāo)毀戴卜,我們要手動(dòng)去清除定時(shí)器逾条。我們手動(dòng)清除的時(shí)候其實(shí)就是在切斷定時(shí)器和監(jiān)聽(tīng)者之間的聯(lián)系;這樣定時(shí)器就會(huì)被銷(xiāo)毀掉投剥;
定時(shí)器中的this問(wèn)題
不管在哪執(zhí)行师脂,定時(shí)器函數(shù)中的this是window;
var obj={
fn:function(){
//this:obj
setTimeout(function(){
//=>this:window 不管在哪執(zhí)行,定時(shí)器中的this是window
},1000);
//=>想讓定時(shí)器函數(shù)中的this是obj,使用bind方法改變?yōu)閛bj
setTimeout(function(){
//=>this:obj
}.bind(this),1000);
//也可以用變量保存的方式來(lái)改變this
var _this=this;
setTimeout(function(){
//=>_this:obj
_this.name
='xxx';
},1000);
setTimeout(()=>{
//=>this:obj 箭頭函數(shù)中的this繼承宿主環(huán)境(上級(jí)作用域中)的this
},1000);
}
};
obj.fn();
同步編程和異步編程
JS是單線(xiàn)程的危彩,當(dāng)前的任務(wù)沒(méi)有完成攒磨,下面的任務(wù)是不進(jìn)行處理的(同步的)
同步編程
當(dāng)前的事情沒(méi)有完成泳桦,繼續(xù)處理當(dāng)前的事情,只有當(dāng)前的事件完成了,才會(huì)去做下一件事情熙含。(JS中大部分都是同步編程的)如for循環(huán)
異步編程
規(guī)劃一件事情粗梭,但不是當(dāng)前馬上去執(zhí)行這件事,需要一定時(shí)間之后再執(zhí)行浮毯,不會(huì)等到時(shí)間到了完疫,任務(wù)執(zhí)行完了,才繼續(xù)完成下面的任務(wù)债蓝。而是把它放到等待任務(wù)隊(duì)列中壳鹤,同時(shí)開(kāi)始計(jì)算等待時(shí)間,繼續(xù)執(zhí)行主任務(wù)隊(duì)列中的任務(wù)饰迹,只有主任務(wù)隊(duì)列中的任務(wù)都完成了芳誓,再到等待任務(wù)隊(duì)列當(dāng)中,看哪個(gè)先到時(shí)間了啊鸭,就先執(zhí)行哪個(gè)锹淌。如果主任務(wù)隊(duì)列中的任務(wù)沒(méi)完成,不會(huì)去執(zhí)行等待任務(wù)隊(duì)列當(dāng)中的任務(wù)赠制;
JS中的異步編程
在JS中的異步編程只有四種:
1赂摆、定時(shí)器都是異步編程的
2、所有的事件綁定都是異步編程钟些、
3烟号、Ajax讀取數(shù)據(jù)的時(shí)候,我們一般都設(shè)置為異步編程
4政恍、回調(diào)函數(shù)也是異步編程
定時(shí)器是有最小等待時(shí)間的褥符,即使設(shè)置為0也不會(huì)馬上執(zhí)行,等待時(shí)間短的先執(zhí)行抚垃;
同步異步編程的核心原理
JS中有兩個(gè)任務(wù)隊(duì)列(存放任務(wù)列表的空間就是任務(wù)隊(duì)列)
1喷楣、主任務(wù)隊(duì)列:同步執(zhí)行任務(wù);(從上到下執(zhí)行)
2鹤树、等待任務(wù)隊(duì)列:存放異步的任務(wù)铣焊;
<font color=red>原理</font>:規(guī)劃一件事情,但不是當(dāng)前馬上去執(zhí)行這件事罕伯,需要一定時(shí)間之后再執(zhí)行曲伊,不會(huì)等到時(shí)間到了,任務(wù)執(zhí)行完了,才繼續(xù)完成下面的任務(wù)坟募。而是把它放到等待任務(wù)隊(duì)列中岛蚤,開(kāi)始計(jì)時(shí),繼續(xù)執(zhí)行下面的操作懈糯,只有主任務(wù)隊(duì)列中的任務(wù)都完成了涤妒,再到等待任務(wù)隊(duì)列當(dāng)中,看哪個(gè)先到時(shí)間了赚哗,就先執(zhí)行哪個(gè)她紫,如果都到時(shí)間了,那么就看哪個(gè)等待的時(shí)間短屿储,就先執(zhí)行哪一個(gè)贿讹。如果主任務(wù)隊(duì)列中的任務(wù)沒(méi)完成,不會(huì)去執(zhí)行等待任務(wù)隊(duì)列當(dāng)中的任務(wù)够掠;
JS中動(dòng)畫(huà)實(shí)現(xiàn)的原理
CSS3動(dòng)畫(huà)
在CSS3中提供了transition(過(guò)渡動(dòng)畫(huà))/animation(幀動(dòng)畫(huà))
優(yōu)勢(shì):
性能好民褂,實(shí)現(xiàn)起來(lái)簡(jiǎn)單,CSS能解決的動(dòng)畫(huà)絕對(duì)不用其他方式疯潭。
弊端:
不兼容大部分IE或者其他低版本瀏覽器(移動(dòng)端的動(dòng)畫(huà)一般都是基于CSS3來(lái)完成的)
JavaScript動(dòng)畫(huà)
在JS中實(shí)現(xiàn)動(dòng)畫(huà)常用的有:
1赊堪、使用定時(shí)器驅(qū)動(dòng)動(dòng)畫(huà),
2袁勺、使用requestAnimationFrame來(lái)完成的動(dòng)畫(huà)
而所謂的canvas動(dòng)畫(huà)基本上也是基于這兩種方案完成的(canvas本身是繪圖)
Flash動(dòng)畫(huà)
非常早的動(dòng)畫(huà)處理方案雹食,想要實(shí)現(xiàn)動(dòng)畫(huà),需要把這部分制作成Flash影片期丰,然后用Adobe Flash Player插件來(lái)播放群叶;現(xiàn)在一些簡(jiǎn)單的DOM動(dòng)畫(huà)都告別了flash的時(shí)代,影片的播放也可以基于H5中的audio或者video完成钝荡;
JS中基于定時(shí)器的動(dòng)畫(huà)運(yùn)動(dòng)的兩種形式
1街立、限定步長(zhǎng),不限制運(yùn)動(dòng)時(shí)間埠通;
2赎离、限定運(yùn)動(dòng)的總時(shí)間,不限制每一步走的長(zhǎng)度端辱;公式:
- time為定時(shí)器走一次的時(shí)間梁剔,zTime為運(yùn)動(dòng)總的時(shí)間
- 元素當(dāng)前所在位置=(time/zTime*總路程+起始位置)
時(shí)間消耗測(cè)試
1、此方法只能測(cè)試運(yùn)算時(shí)間在1毫秒以上的舞蔽,
var startTime=new Date();
//需要測(cè)試消耗時(shí)間的代碼
console.log(new Date()-startTime);
2荣病、此方法可以測(cè)試運(yùn)算時(shí)間在1毫秒以下的
console.time()
//需要測(cè)試消耗時(shí)間的代碼
console.timeEnd()
20、JS中的回調(diào)函數(shù)
什么是回調(diào)函數(shù)
把一個(gè)函數(shù)當(dāng)作實(shí)參值傳遞給另外一個(gè)函數(shù)渗柿,在另外一個(gè)函數(shù)中執(zhí)行這個(gè)函數(shù)个盆,這種處理機(jī)制就是回調(diào)函數(shù)機(jī)制;
什么時(shí)候用到回調(diào)函數(shù)?
凡是在某一個(gè)函數(shù)的某一個(gè)階段需要完成某一件事情(而這件事情是不確定的)颊亮,都可以利用回調(diào)函數(shù)機(jī)制柴梆,把需要處理的事情當(dāng)作值傳遞進(jìn)來(lái)
function fn(num,callBack){
typeof callBack==='function'?callBack():null;
//也可以使用以下默認(rèn)方式(不過(guò)不嚴(yán)謹(jǐn):可能傳遞的不是函數(shù))
callBack&&callBack()
}
1、回調(diào)函數(shù)可以被執(zhí)行多次终惑;
2绍在、還可以給callBack()傳遞參數(shù)值;
3狠鸳、還可以把回調(diào)函數(shù)中的this進(jìn)行修改揣苏;
4悯嗓、我們還可以接收回調(diào)函數(shù)執(zhí)行返回的值件舵;
var ary=[12,23,34];
ary.sort(funciton(a,b){
/這里的function就是sort方法中的回調(diào)函數(shù)
})
回調(diào)函數(shù)中的this問(wèn)題
回調(diào)函數(shù)中的 this一般都是window(嚴(yán)格模式下是undefined),原因:
我們一般執(zhí)行回調(diào)函數(shù)的時(shí)候都是直接執(zhí)行回調(diào)函數(shù)脯厨,沒(méi)有指定執(zhí)行主體铅祸,所以默認(rèn)情況下都是window;
定時(shí)器中的this問(wèn)題
只要不指明執(zhí)行主體合武,定時(shí)器中的this就是window.(嚴(yán)格模式下也是window)临梗;
關(guān)于Each循環(huán)方法的封裝
需求
兼容所有瀏覽器
類(lèi)似于JQ中的EACH方法,我們需要支持對(duì)數(shù)組稼跳,類(lèi)書(shū)組盟庞,純對(duì)象的遍歷任務(wù)
需要支持對(duì)原有數(shù)組的修改(回調(diào)函數(shù)中的返回值,可以修改原來(lái)數(shù)組中的某一項(xiàng)值)
在遍歷中汤善,通過(guò)回調(diào)函數(shù)返回值什猖,來(lái)結(jié)束當(dāng)前正在遍歷的操作(回調(diào)函數(shù)中返回false,我們應(yīng)該結(jié)束對(duì)數(shù)組的遍歷)
21红淡、ES6(JS新語(yǔ)法規(guī)范ES2016)基礎(chǔ)知識(shí)及核心原理
(詳細(xì)內(nèi)容請(qǐng)參考阮一峰大神的的ES6入門(mén):http://es6.ruanyifeng.com/#docs/intro)
使用Babel編譯ES6
1不狮、下載安裝babel
npm install babel-cli -g
我們之所以可以使用babel命令,是因?yàn)樵谌汁h(huán)境下會(huì)生成一些xxx.cmd的文件在旱,而這里的xxx就是可以在doc窗口中執(zhí)行的命令
執(zhí)行babel命令后摇零,可以完成一些編譯或者其他任務(wù),原因是執(zhí)行babel命令后桶蝎,會(huì)自動(dòng)加載處理任務(wù)的文件驻仅;
配置.babelrc文件,安裝在一些語(yǔ)言解析包
我們需要把.babelrc文件配置在當(dāng)前項(xiàng)目的根目錄下
注意:在電腦上不能直接創(chuàng)建沒(méi)有文件名的文件登渣,但是可以在webS中new->file來(lái)創(chuàng)建噪服,或者使用命令創(chuàng)建
1、babelrc這個(gè)后綴名在某些ws中是不識(shí)別的绍豁,我們需要設(shè)置關(guān)聯(lián)
2芯咧、在這個(gè)文件中編寫(xiě)內(nèi)容:
{
"presets":[],//存的是我們編譯代碼時(shí)候需要依賴(lài)的語(yǔ)言解析包
"plugins":[]//存的是我們編譯代碼時(shí)候需要依賴(lài)的插件信息
}
3、安裝依賴(lài)的語(yǔ)言解析包
在當(dāng)前項(xiàng)目的根目錄下安裝
npm install babel-preset-latest
安裝最新已經(jīng)發(fā)布的語(yǔ)言標(biāo)準(zhǔn)解析模塊
npm install babel-preset-stage-2
安裝當(dāng)前還沒(méi)有發(fā)布但是已經(jīng)進(jìn)入草案的語(yǔ)言解析模塊
4、完成最后.babelrc
{
"presets":[
"latest",
"stage-2"
],//存的是我們編譯代碼時(shí)候需要依賴(lài)的語(yǔ)言解析包
"plugins":[]//存的是我們編譯代碼時(shí)候需要依賴(lài)的插件信息
}
三敬飒、使用命令編譯JS代碼
基本上所有支持命令操作的模塊都有一個(gè)命令
babel --help/babel -h 查看幫助
babel -V 查看版本號(hào)
babel -o 把某一個(gè)JS文件中的ES6代碼進(jìn)行編譯
babel -d 把某一個(gè)文件夾中所有的JS文件中的ES6代碼進(jìn)行編譯
babel -w 監(jiān)聽(tīng)文件中代碼的改變邪铲,當(dāng)代碼改變后,會(huì)自動(dòng)進(jìn)行編譯
ES6增加的語(yǔ)法
let&&const
let
與var
的區(qū)別
let 變量名=變量值
使用let創(chuàng)建變量和使用var創(chuàng)建變量的區(qū)別
- 1无拗、用var聲明的變量會(huì)變量提升带到,用let聲明的變量不會(huì)進(jìn)行變量提升
用let創(chuàng)建變量
let xxx=xxx;
用let創(chuàng)建函數(shù)
let xxx=function(){}
創(chuàng)建自執(zhí)行函數(shù)
;(function(){
})();
- 2、用let定義變量不允許在
同一個(gè)作用域中
重復(fù)聲明一個(gè)變量(只要當(dāng)前作用域中有這個(gè)變量英染,不管是用var還是用let聲明的揽惹,再用let聲明的話(huà)會(huì)報(bào)錯(cuò):不能重復(fù)聲明一個(gè)變量),但是可以重復(fù)定義(賦值)
let i=10;
let i=20;/會(huì)報(bào)錯(cuò)四康,
i=20;重復(fù)賦值不會(huì)報(bào)錯(cuò)
- 3搪搏、暫時(shí)性死區(qū):在代碼塊內(nèi),使用let命令聲明變量之前闪金,該變量都是不可用的疯溺。這在語(yǔ)法上,稱(chēng)為“暫時(shí)性死區(qū)”(temporal dead zone哎垦,簡(jiǎn)稱(chēng) TDZ)囱嫩。
if (true) {
// TDZ開(kāi)始
tmp = 'abc'; // ReferenceError,報(bào)錯(cuò)之后下面都不會(huì)輸出
console.log(tmp); // ReferenceError,報(bào)錯(cuò)之后下面都不會(huì)輸出
let tmp; // TDZ結(jié)束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
//下面也會(huì)報(bào)錯(cuò)出現(xiàn)TDZ
console.log(typeof x); // ReferenceError
let x;
//作為比較如果一個(gè)變量根本沒(méi)有被聲明漏设,使用typeof反而不會(huì)報(bào)錯(cuò)墨闲。
console.log(typeof x);// "undefined"
- 4、ES6語(yǔ)法創(chuàng)建的變量(let)存在塊級(jí)作用域
- [ES5]
window全局作用域
函數(shù)執(zhí)行形成的私有作用域- [ES6]
除了有ES5中的兩個(gè)作用域郑口,ES6中新增加塊級(jí)作用域(我們可以把塊級(jí)作用域理解為之前學(xué)習(xí)的私有作用域鸳碧,存在私有作用域和作用域鏈的一些機(jī)制)ES6中把大部分用{}包起來(lái)的都稱(chēng)之為塊級(jí)作用域
;
const
const細(xì)節(jié)知識(shí)點(diǎn)和let類(lèi)似
const聲明的常量只要聲明就必須賦值,而且變量的值是一定的潘酗,不能被修改杆兵;
注意
:并不是變量的值不得改動(dòng),而是變量指向的那個(gè)內(nèi)存地址不得改動(dòng)仔夺。對(duì)于簡(jiǎn)單類(lèi)型的數(shù)據(jù)(數(shù)值琐脏、字符串、布爾值)缸兔,值就保存在變量指向的那個(gè)內(nèi)存地址日裙,因此等同于常量。但對(duì)于復(fù)合類(lèi)型的數(shù)據(jù)(主要是對(duì)象和數(shù)組)惰蜜,變量指向的內(nèi)存地址昂拂,保存的只是一個(gè)指針,const只能保證這個(gè)指針是固定的抛猖,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的格侯,就完全不能控制了鼻听。因此,將一個(gè)對(duì)象聲明為常量必須非常小心联四。
const聲明的變量也存在暫時(shí)性死區(qū)撑碴,即只能在聲明的位置之后使用;
JS中創(chuàng)建變量的方式匯總
[ES5]
- var :創(chuàng)建變量
function:創(chuàng)建函數(shù)
ES5中創(chuàng)建變量或者函數(shù):存在變量提升朝墩,重復(fù)聲明等特征醉拓;[ES6]
- let創(chuàng)建變量
const:ES6中創(chuàng)建常量
ES6中創(chuàng)建的變量或者常量:都不存在變量提升,也不可以重復(fù)聲明收苏,而且還存在塊級(jí)作用域亿卤;
class:創(chuàng)建一個(gè)類(lèi)
import:導(dǎo)入
ES6中的解構(gòu)賦值
按照原有值的結(jié)構(gòu),把原有值中的某一部分內(nèi)容快速獲取到(快速賦值給一個(gè)變量)
數(shù)組的解構(gòu)賦值
解構(gòu)賦值本身是ES6的語(yǔ)法規(guī)范鹿霸,使用什么關(guān)鍵字來(lái)聲明這些變量是無(wú)所謂的排吴,如果不用關(guān)鍵字來(lái)聲明,那么就相當(dāng)于給window添加的自定義屬性杜跷;(嚴(yán)格模式下必須使用關(guān)鍵字來(lái)聲明傍念,因?yàn)閲?yán)格模式下不允許出現(xiàn)不用關(guān)鍵字聲明的變量;)矫夷,如果解構(gòu)不到值葛闷,那么變量的值就是undefined;
let [a,b,c]=[12,23,34];
var [d,e,f]=[35,41,63];
console.log(a,b,c)//12,23,34;
console.log(d,e,f)//35,41,63;
[q,w,e]=[1,2,3];//相當(dāng)于給window添加了三個(gè)屬性:q,w,e值分別為1双藕,2淑趾,3;(嚴(yán)格模式下會(huì)報(bào)錯(cuò))
多維數(shù)組的解構(gòu)賦值忧陪,可以讓我們快速的獲取到需要的結(jié)果
let [a,b,c]=[[45,36],12,[23,43,[1,2[4,[8]]]]23,34];
console.log(a)//[45,36]
console.log(b)//12
console.log(c)//[23,43,[1,2,[4,[8]]]]
//數(shù)組中不需要解構(gòu)的值可用逗號(hào)(扣泊,)空開(kāi),一個(gè)逗號(hào)代表空開(kāi)一項(xiàng)
let [,,,A]=[12,23,45];
console.log(A)//undefined
let [,,B]=[12,23,45]
console.log(B)//45
在解構(gòu)賦值中嘶摊,支持?jǐn)U展運(yùn)算符即<font color=red>...</font>,只要用了擴(kuò)展運(yùn)算符延蟹,就相當(dāng)于新生成了一個(gè)數(shù)組或者對(duì)象,如果解構(gòu)不到值的話(huà)叶堆,新生成的數(shù)組或者對(duì)象為空阱飘,而不是undefined,但是擴(kuò)展運(yùn)算符必須放在末尾
let [a,...c]=[12,1,4,83,34];
console.log(a)//12
console.log(c)//[1,4,83,34];
let [a,...b,c]=[12,1,4,83,34];//會(huì)報(bào)錯(cuò)虱颗,擴(kuò)展運(yùn)算符只能放在末尾沥匈;
對(duì)象的解構(gòu)賦值
對(duì)象的簡(jiǎn)潔表示法:
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
對(duì)象的解構(gòu)與數(shù)組有一個(gè)重要的不同。數(shù)組的元素是按次序排列的忘渔,變量的取值由它的位置決定高帖;而對(duì)象的屬性沒(méi)有次序,變量必須與屬性同名畦粮,才能取到正確的值散址。
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
如果變量名與屬性名不一致乖阵,必須寫(xiě)成下面這樣。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
真正被賦值的是后者预麸,而不是前者义起。
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
first//error: first is not defined
如果要將一個(gè)已經(jīng)聲明的變量用于解構(gòu)賦值,必須非常小心师崎。
// 錯(cuò)誤的寫(xiě)法
let x;
{x} = {x: 1};//會(huì)報(bào)錯(cuò)
因?yàn)?JavaScript 引擎會(huì)將{x}理解成一個(gè)代碼塊默终,從而發(fā)生語(yǔ)法錯(cuò)誤。只有不將大括號(hào)寫(xiě)在行首犁罩,避免 JavaScript 將其解釋為代碼塊齐蔽,才能解決這個(gè)問(wèn)題。
// 正確的寫(xiě)法
let x;
({x} = {x: 1});
放在圓括號(hào)當(dāng)中就可以避免 JavaScript 將其解釋為代碼塊床估。
解構(gòu)賦值中支持指定默認(rèn)值
let [foo = true] = [];
console.log(foo);// true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
var {x: y = 3} = {};
y // 3
var {x: y = 3} = {x: 5};
y // 5
解構(gòu)賦值的作用
1含滴、快速交換兩個(gè)變量的值
let a=12;
let b=13;
[a,b]=[b,a];
console.log(a);//13
console.log(b);//12
2、可以接收函數(shù)返回的多個(gè)值
let fn = function () {
let a = 12,
b = 13,
c = 14;
return [a, b, c];
};
let [a,b,c] = fn();
console.log(a, b, c);//=>12 13 14
<font color=red>...</font> 的三種身份:擴(kuò)展運(yùn)算符丐巫、展開(kāi)運(yùn)算符谈况、剩余運(yùn)算符
1、擴(kuò)展運(yùn)算符(注意递胧,在解構(gòu)賦值中碑韵,叫做擴(kuò)展運(yùn)算符,只能放在末尾)
只要用了擴(kuò)展運(yùn)算符缎脾,就相當(dāng)于新生成了一個(gè)數(shù)組或者對(duì)象祝闻,如果解構(gòu)不到值的話(huà),新生成的數(shù)組或者對(duì)象為空遗菠,而不是undefined联喘,但是擴(kuò)展運(yùn)算符必須放在末尾
數(shù)組中的擴(kuò)展運(yùn)算符
let [a,b,...c]=[12,1,4,83,34]
console.log(a);//12
console.log(b);//1
console.log(c);//[4,83,34]
對(duì)象中的擴(kuò)展運(yùn)算符
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x);//1
console.log(y );//2
console.log(z );//{ a: 3, b: 4 }
2、剩余運(yùn)算符
function(...arg){
...arg就相當(dāng)于剩余運(yùn)算符辙纬,可以把傳遞的所有參數(shù)都獲取到豁遭,而且獲取到的是一個(gè)數(shù)組
}
3、展開(kāi)運(yùn)算符
function fn1(){
}
function fn2(){
fn1(...arguments)
...arguments:這里的...就相當(dāng)于展開(kāi)運(yùn)算符贺拣,把a(bǔ)rguments展開(kāi)蓖谢,把里面的每一項(xiàng)分別傳遞給fn1當(dāng)作參數(shù),然后讓fn1執(zhí)行纵柿;
}
箭頭函數(shù)
兩種寫(xiě)法:1蜈抓、表達(dá)式 2、函數(shù)體
表達(dá)式:
1.let fn=p=>p; 等價(jià)于 var fn=function(p){return p};
2.let fn=()=>n; 等價(jià)于 var fn=funciton(){return n};
3.let fn=(n,m)=>n+m;等價(jià)于 var fn=function(n,m){return n+m};
函數(shù)體:
let fn=(n,m)=>{
var total=n+m;
return total;
}
1昂儒、箭頭函數(shù)中不支持arguments,但是用 剩余運(yùn)算...arg 代替了arguments沟使,arg是一個(gè)數(shù)組,可以直接使用數(shù)組方法
let obj={
name:'obj',
fn(){
//此方法的屬性名為fn渊跋,屬性值為一個(gè)函數(shù)腊嗡,和下面的sum寫(xiě)法是一樣的着倾;
},
sum:function () {
}
};
let fn = (...arg)=> {
/console.log(arguments);//=>Uncaught ReferenceError: arguments is not defined
/=>不支持arguments,我們使用ES6中的剩余運(yùn)算符...來(lái)獲取傳遞的進(jìn)來(lái)的所有參數(shù)值(優(yōu)勢(shì):使用剩余運(yùn)算符接收到的結(jié)果本身就是一個(gè)數(shù)組,不需要再轉(zhuǎn)換了)
/console.log(arg instanceof Array);//=>true
return eval(arg.join('+'));
};
//=>也可以把FN簡(jiǎn)寫(xiě)成以下方式
//let fn = (...arg)=> eval(arg.join('+'));
console.log(fn(10, 20, 30, 40));
2燕少、箭頭函數(shù)中的this問(wèn)題卡者,可以默認(rèn)為箭頭函數(shù)中沒(méi)有this,在箭頭函數(shù)中出現(xiàn)的this都是宿主環(huán)境中(即上級(jí)作用域中)的this客们,與箭頭函數(shù)點(diǎn)之前的執(zhí)行主體沒(méi)有任何關(guān)系崇决;
ES6中的類(lèi)和繼承
ES6中創(chuàng)建類(lèi)和實(shí)例用class,創(chuàng)建出來(lái)的類(lèi)不存在變量提升底挫;
ES5中創(chuàng)建類(lèi)和實(shí)例恒傻,以及如何禁止用戶(hù)把類(lèi)當(dāng)做普通函數(shù)執(zhí)行:new.target
if (typeof new.target === 'undefined') {
throw new SyntaxError(`當(dāng)前Person不能作為一個(gè)普通函數(shù)執(zhí)行,請(qǐng)使用new Person來(lái)執(zhí)行~~`);
}
class Father {//定義一個(gè)類(lèi)建邓;
constructor(name, age) {//構(gòu)造函數(shù)定義實(shí)例的私有屬性
this.name = name;
this.age = age;
}
getName() {//公有的函數(shù)和方法
console.log(this.name + "的年齡是" + this.age + "歲了");
}
static like() {//static后面寫(xiě)的是把Father當(dāng)做對(duì)象時(shí)的私有屬性
console.log("我是Father函數(shù)的私有屬性")
}
}
class Son extends Father {//子類(lèi)Son繼承父類(lèi)Father
constructor(name, age, color) {
super(name, age);//繼承父類(lèi)的私有屬性盈厘,必須寫(xiě)
//下面為子類(lèi)的私有屬性
this.color = color;
super當(dāng)作對(duì)象調(diào)用時(shí),super就相當(dāng)于父類(lèi)的原型
}
//下面為子類(lèi)公有的方法
getColor() {
console.log(this.color)
}
}
字符串中新增加的方法
字符串.includes(val)
:返回布爾值官边,字符串中是否包含val所代表的字符串沸手;
字符串.startsWith(val)
:val是否在字符串的起始位置。
字符串.endsWith(val)
:val是否在字符串的尾部注簿。
三個(gè)方法都返回一個(gè)布爾值
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
這三個(gè)方法都支持第二個(gè)參數(shù)契吉,表示開(kāi)始搜索的位置。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
上面代碼表示滩援,使用第二個(gè)參數(shù)n時(shí)栅隐,endsWith的行為與其他兩個(gè)方法有所不同。它 針對(duì)前n個(gè)字符玩徊,而其他兩個(gè)方法針對(duì)從第n個(gè)位置直到字符串結(jié)束。
repeat()
:返回一個(gè)新字符串谨究,表示將原字符串重復(fù)n次恩袱。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
模版字符串
模版字符串,也是字符串胶哲,可以直接使用字符串中的方法畔塔;
模版字符串的空格和換行,都是被保留的鸯屿,如果想要消除空格可以使用trim方法澈吨;
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
模版字符串中可以嵌入變量,需要將變量寫(xiě)在${}中寄摆,大括號(hào)內(nèi)部可以放入任意的 JavaScript 表達(dá)式谅辣,可以進(jìn)行運(yùn)算,以及引用對(duì)象屬性婶恼。
let x = 1;
let y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
模板字符串之中還能調(diào)用函數(shù)桑阶。
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
ES6中新增加的迭代for of
forEach柏副,for,for in蚣录,for of的區(qū)別
forEach
:不支持返回值割择,只是普通的循環(huán)遍歷
for in
:key輸出的值為字符串類(lèi)型,包括把數(shù)組當(dāng)成對(duì)象添加的屬性也可以遍歷出來(lái)
for of
:只返回具有數(shù)字索引的屬性萎河。這一點(diǎn)跟for...in循環(huán)也不一樣荔泳。(不能遍歷對(duì)象)
let arr = [3, 5, 7];
arr.foo = 'hello';
for (let i in arr) {
//for in是把a(bǔ)rr當(dāng)成對(duì)象遍歷,i是屬性名虐杯,包括arr的私有屬性
console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr) {
//for of是把a(bǔ)rr當(dāng)成數(shù)組遍歷换可,i是數(shù)組中的每一項(xiàng)
console.log(i); // "3", "5", "7"
}
for of循環(huán)不會(huì)返回?cái)?shù)組arr的foo屬性
如果只想拿到索引,可用keys()方法
for (let index of arr.keys()) {
console.log(index);
}
// 0
// 1
// 2
如果兩個(gè)都想拿到厦幅,可用entries()方法
for (let (index, elem) of arr.entries['?ntr?s]()) {
console.log(index, elem);
}
// 0 "3"
// 1 "5"
// 2 "7"
ES6中的模塊導(dǎo)入和導(dǎo)出
//=>A模塊(在A模塊中導(dǎo)入B模塊)
import Temp,{lib} from "./B";//=>把導(dǎo)入的Temp中的部分屬性方法進(jìn)行解構(gòu)賦值
new Temp().init();
lib();//=>Temp.lib()
//=>B模塊(導(dǎo)出)
export default class Temp {
init() {
console.log(`hello world`);
}
static lib(){//=>Temp.lib
}
}