定義
:是一個用來處理字符串的規則javascript
正則只能用來處理字符串css
處理通常包含兩方面java
- 驗證當前字符串是否符合某個規則"正則匹配"
- 把一個字符串中符合規則的字符獲取到"正則捕獲"
let reg1=/^\d+$/g;//=>字面量方式
let reg2=new RegExp("^\\d+$","g");//=>構造函數方式
複製代碼
正則兩個斜槓之間包起來的都是"元字符",斜槓後面出現的都是"修飾符"ajax
`i`:ignoreCase 忽略大小寫匹配
`m`:multiline 多行匹配
`g`:global 全局匹配
複製代碼
讓其左邊的元字符出現多少次正則表達式
`?`:出現零到一次
`*`:出現零到屢次
`+`:出現一到屢次
`{n}`:出現N次
`{n,}`:出現N到屢次
`{n,m}`:出現N到M次
複製代碼
`\d`:0~9之間的一個數字
`\D`:非0~9之間的任意字符
`\w`:"數字、字母、下劃線"中的任意一個
`\s`:匹配任意一個空白字符(包括\t製表符[TAB]鍵四個空格)
`\b`:匹配邊界符 "zhu"(z左邊和u右邊就是邊界) "zhu-feng"(z左邊、u右邊、f左邊、g右邊是邊界)
`\n`:匹配一個換行符
`\`:轉義字符 把一個普通字符轉義爲特殊的字符,例如:\d;把有特殊含義的轉換爲普通意思,例如:`\.` 此處的點就不是任意字符,而是一個小數點
`.`:匹配除了\n之外的任意字符
`^`:以某個元字符開頭
`$`:以某個元字符結尾
`|`:或者 例如`x|y`表明x或者y中的任意一個
`[]`:中括號中的任意一個字符 例如`[xyz]`表明x或者y或者z中的任意一個
`[^]`:除了中括號中字符之外的任意字符 例如`[^xyz]`表明除了x/y/z之外的任意字符
`[a-z]`:獲取a-z中的任意一個字符([0-9] 等價於\d...)
`[^a-z]`:除了a-z的任意字符
`()`:正則分組
`(?:)`:當前分組只匹配不捕獲
`(?=)`:正向預查
`(?!)`:反向預查
複製代碼
中括號中出現的元字符通常都是表明自己含義的,可是\d在中括號中仍然表明的是0~9中的一個數字express
let reg=/^.$/;
//=>一個正則設置了^和$,那麼表明的含義其實就是隻能是xxx
---------------------
let reg=/^[.]+$/;
console.log(reg.test("n"));//=>false
console.log(reg.test("1"));//=>false
console.log(reg.test("nn"));//=>false
console.log(reg.test("..."));//=>true
---------------------
let reg=/^[\d]+$/;
console.log(reg.test("d"));//=>false
console.log(reg.test("0"));//=>true
複製代碼
中括號中出現的兩位數,不是兩位數,而是兩個數字中的任意一個編程
let reg=/^[18]$/;
console.log(reg.test("1"));//=>true
console.log(reg.test("8"));//=>true
console.log(reg.test("18"));//=>false
-------------------
let reg=/[18]/;
console.log(reg.test("18"));//=>true
console.log(reg.test("81321"));//=>true
console.log(reg.test("22"));//=>false
-------------------
let reg=/^[12-65]$/;
//=>這個正則的意思是,只能是1,5,或者2-6之間的一個數
console.log(reg.test("1"));//=>true
console.log(reg.test("7"));//=>false
複製代碼
案例json
匹配年齡在18~65之間設計模式
/* * 18~19 1[89] * 20~59 [2-5]\d * 60~65 6[0-5] */
let reg=/^(1[89])|([2-5]\d)|(6[0-5])$/
複製代碼
案例數組
驗證身份證號,並把生日,地域,性別信息匹配出來
//=>前6位表明地域,倒數第二位偶數表明女,奇數表明男
let reg=/^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|x)$/
let str="130828199012040617"
console.log(reg.exec(str));
["130828199012040617","130828","1990","12","04","1",index:0,input:"130828199012040617"]
複製代碼
只要在正則中出現的元字符(在基於字面方式建立),除了特殊和有量詞意義的之外,其他的都是普通元字符
定義
用於檢索字符串中的正則表達式的匹配,並返回包含該查找結果的一個數組。若是能夠匹配獲取的結果是一個數組,若是不能匹配獲取的結果是null
let str="zzzzzzzz2018sssssss2019";
let reg=/\d+/;
console.log(reg.exec(str));
複製代碼
若是咱們只在匹配的時候,想要獲取大正則中部分信息,能夠把想要捕獲到的內容使用小括號包起來,造成一個分組,這樣在捕獲的時候,不只能夠把大正則匹配的信息獲取到,並且還單獨的把小分組匹配的部分信息也捕獲到了(分組捕獲)
若是使用正則分組不是爲了捕獲信息,只是爲了改變優先級或者進行分組引用,能夠在分組的前面加上"?:",表明只去匹配,可是不把這個分組內容捕獲
正則的捕獲有懶惰性
執行一次exec只能捕獲到第一個匹配的內容,剩餘的默認捕獲不到,哪怕是全局下執行一次exec只能捕獲一個匹配的內容,在全局下想要得到全部匹配的內容須要不停的執行exec方法,直到返回值是null爲止
lastIndex是正則實例上內置的屬性,,lastIndex不變致使了正則捕獲的懶惰性,不設置全局匹配的狀況下,無論怎麼操做當前正則實例的lastIndex屬性值一直爲0
let str="zzzzzzz2018sssssss2019";
let reg=/\d+/;
console.log(reg.exec(str));//=>["2018"]
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>["2018"]
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>["2018"]
console.log(reg.lastIndex);//=>0
------
???改變後lastIndex已經變了,爲何不按照lastIndex查找的匹配的機制去匹配
//=>即便手動改變lastIndex值也沒有做用
console.log(reg.exec(str));//=>['2018']
reg.lastIndex = 11;
console.log(reg.lastIndex);//=>11
console.log(reg.exec(str));//=>['2018']
console.log(reg.exec(str));//=>11
複製代碼
解決正則懶惰性的方案
惟一的解決方法
: 須要加全局修飾符G,此時只要屢次執行exec方法,就能夠匹配到字符串中全部匹配的內容
lastIndex意思是正則表達式開始下一次查找的索引位置,第一次查找完了的時候會把lastIndex的值設爲匹配到的字符串的最後一個字符的索引位置加1,第二次查找的時候會從lastIndex這個位置開始,後面以此類推。若是沒有找到,則會把lastIndex重置爲0。
let str = 'zzzzzzz2018ssssss2019';
let reg = /\d+/g;
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>['2018']
console.log(reg.lastIndex);//=>11
console.log(reg.exec(str));//=>['2019']
console.log(reg.lastIndex);//=>21
console.log(reg.exec(str));//=>null
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>['2018']
複製代碼
let str="zzzzzzz2018";
let reg=/\d+/g;
console.log(reg.exec(str));//=>["2018"],把reg的內置lastIndex值該爲11
console.log(reg.exec("zzzzzzz2018sssssss2019"));//=>["2019"],雖然捕獲的不是同一個字符串,可是正則是同一個,上一次正則處理的時候修改了它的lastIndex,也會對下一次匹配新的字符串產生影響
複製代碼
基於test進行匹配的時候,若是設置了g,test匹配也至關於捕獲,修改了lastIndex的值
let str = 'zzzzzzz2018ssssss2019';
let reg = /\d+/g;
console.log(reg.test(str));//=>TRUE
console.log(reg.lastIndex);//=>11
console.log(reg.exec(str));//=>['2019']
----------------------------
let str = 'zzzzzzz2018';
let reg = /\d+/g;
if(reg.test(str)){//=>此時lastIndex值爲11
console.log(reg.exec(str));//=>NULL
}
複製代碼
封裝方法--直接捕獲全部匹配的內容
//=>相似於String中的match方法
RegExp.prototype.myExecAll=function(str){
if(!this.global){
return this.exec(str);
}
let ary=[],
execAll=this.exec(str);
while(execAll){
ary.push(execAll[0]);
execAll=this.exec(str);
}
return ary;
};
複製代碼
正則捕獲的貪婪性
每一次匹配捕獲的時候,老是捕獲到和正則匹配中最長的內容
let str="zzzzzzz2018sssssss2019";
let reg=/\d+/g;
console.log(reg.exec(str));//=>["2018"]
複製代碼
取消正則捕獲的貪婪性
把問號放到量詞元字符後面,表明取消捕獲的貪婪性
let str="zzzzzzz2018sssssss2019";
let reg=/\d+?/g;
console.log(reg.exec(str));//=>["2"]
複製代碼
RegExp.$1
把上一次匹配(TEXT/EXEC)到的結果獲取到,獲取的是第一個小分組匹配的內容,大正則匹配的內容沒法獲取,它是一個全局的值,瀏覽器中$1只有一個,其它的正則操做也會覆蓋這個值
let str = 'zzzzzzz20182018sssssss2019';
let reg = /(\d{4})(\1)/g;
console.log(reg.exec(str));//=>["20182018"]
console.log(reg.lastIndex);//=>15
console.log(reg.test(str));//=>TRUE
console.log(RegExp.$1,RegExp.$2);//=>"2018","2018"
複製代碼
let str = 'zzzzzzz2018ssssssss2019';
let reg = /(\d+)/g;
console.log(reg.test(str));//=>TRUE
console.log(RegExp.$1);//=>"2018"
複製代碼
String中的match方法
match方法用於找到一個或多個正則表達式的匹配
正則不加g返回第一個匹配的便可(至關於reg.exec(str)),加了g,把全部匹配的內容都捕獲到,最後統一存儲到一個數組中返回
封裝--String原型上match方法
String.prototype.myMatch=function myMatch(reg){
if(!reg.global){
return reg.exec(this);
}
let result=[],
execAll=reg.exec(this);
while(execAll){
result.push(execAll[0]);
execAll=reg.exec(this);
}
return result;
};
複製代碼
let reg=/\{(\d+)\}/g;
let reg1=/\{(\d+)\}/;
let str="zzzzzzz{2018}zzzzzzz{2019}zzzzzzz{2020}";
console.log(str.myMatch(reg));
console.log(str.myMatch(reg1));
複製代碼
match方法的侷限性
在正則設置了g的狀況下,基於match捕獲的內容只有大正則匹配,小分組的內容沒有單獨抽取出來(不設置g的狀況下和執行exec同樣)
let str="zzzzzzz{2018}zzzzzzz{2019}zzzzzzz{2020}zzzzzzz{2021}";
let reg=/\{(\d+)\}/g;
console.log(reg.exec(str));//=>["{2018}","2018"]
console.log(str.match(reg));//=>["{2018}", "{2019}", "{2020}", "{2021}"]
複製代碼
String中的replace方法
語法:[str].replace(reg,[要替換的內容])
用reg正則和str字符串進行匹配,匹配幾回就替換幾回,每一次都是把當前「大正則」匹配的結果用第二個傳遞的字符串替換掉了
let str="zzzzzzz{val:2018}zzzzzzz{val:2019}",
reg=/\{val(\d+)\}/g;
str=str.replace(reg,"@");//=>"zzzzzzz@zzzzzzz@"
str=str.replace(reg,"$1");//=>"zzzzzzz2018zzzzzzz2019"
複製代碼
replace替換的內容爲函數
reg和str匹配多少次,函數就被觸發執行多少次
每一次正則匹配到結果,都把函數執行,而後基於exec把本次匹配的信息捕獲到,而後把捕獲的信息也就是exec獲得的數組中的每一項依次傳參給傳遞給函數
每一次函數中返回值是什麼,就把當前大正則匹配的內容替換成啥
let str="zzzzzzz2018zzzzzzz2019";
let reg=/\d+/g;
str=str.replace(reg,(...arg)=>{
console.log(arg);
return "AA";
})
console.log(str);//=>"zzzzzzzAAzzzzzzzAA"
複製代碼
案例
把"54689"轉換爲"伍肆陸捌玖"
let str="54389",
ary=['零', '壹', '貳', '叄', '肆', '伍', '陸', '柒', '捌', '玖'];
str=str.replace(/\d/g,item=>{//=>item指的是exec中的第一項
return ary[item];
})
console.log(str);
複製代碼
案例
一個url 後面好多key-value 如localhost?key=val&key2=val2&key3=val3 封裝一個函數 getParam(‘key’) 經過key得到相應等號後面的值.
function getParam(url,key){
let obj={};
url.replace(/([^?#&]+)=([^?#&]+)/g,(...arg)=>{
[,attr,value]=arg;
obj[attr]=value;
});
return obj[key];
}
複製代碼
String中的split方法
字符串根據符合正則的字符進行分割,並用一個數組將分割後的內容返回
split方法不會將分隔符返回,可是會將小分組的內容返回,也就是捕獲到的內容
let str="2018/4/30 17:50:23",
ary=str.split(/\/| |:/g);//=>按照/,空格,:進行拆分
console.log(ary);//=>["2018", "4", "30", "17", "50", "23"]
-------------------
let str = "2018/4/30 17:50:23",
ary = str.split(/(\/| |:)/g);
console.log(ary);// ["2018", "/", "4", "/", "30", " ", "17", ":", "50", ":", "23"]
----------------------
let str = "2018/4/30 17:50:23",
ary = str.split(/(?:\/| |:)/g);
console.log(ary);//=>["2018", "4", "30", "17", "50", "23"]
複製代碼
時間字符串格式化
let str="2018-4-3 17:34:56";
let ary=str.match(/\d+/g).map(item=>item<10?item="0"+item:item);
console.log(ary)//=>["2018","04,"03","17","34","56"]
複製代碼
封裝
String.prototype.myFormatTime=function(template="{0}年{1}月{2}日 {3}時{4}分{5}秒"){
let ary=this.match(/\d+/g).map(function(item){
return item<10?"0"+item:item;
})
template=template.replace(/\{(\d)\}/g,function(...arg){
return ary[arg[1]] || "00"
})
return template;
};
let str="2018-4-3 21:23:45";
str.myFormatTime();//=>"2018年04月03日 21時23分45秒";
let str="2018-4-3";
str.myFormatTime({1}-{2} {3}:{4});//"04-03 00:00"
複製代碼
解析URL
function queryParameter(url){
let obj={};
url.indexof("#")>0?url=url.replace(/#/g,"&HASH="):null;
let ary=url.split(/\?/g)[1].split(/=|&/g);
ary.forEach((item,index)=>{
if(index%2===1) return;
obj[item]=ary[index+1];
})
ary=null;
return obj;
};
複製代碼
獲取一個字符串中最多出現字符的次數和對應的字符
let str = 'zzzzzzzzzzzzzz';
str=str.split("").sort().join("");
let ary=str.match(/(\w)\1*/g);
let obj={};
ary.forEach((item,index)=>{
obj[item[0]]=item.length;
})
let max=0;
for(let key in obj){
if(!obj.hasOwnProperty(key)) break;
obj[key]>max?max=obj[key]:null;
}
for(let key in obj){
if(!obj.hasOwnProperty(key)) break;
if(obj[key]===max){
console.log(`${key}:${max}`);
}
}
複製代碼
\1表示反向引用,它表示的是第一個括號內的子正則表達式匹配內容,而不是第一個括號的內容
let reg=/(\w)\1/;
let str="zzzzzzz";
console.log(reg.test(str));//=>false
console.log(reg.exec(str));//=>null
複製代碼
反向引用只能引用已經捕獲到的
let reg=/^(?:b|c)\1/;
let str="bbc.zzzzzzz.cn";
console.log(reg.exec(str));//=>null
複製代碼
案例:有效數字
1.能夠出現+/-號:能夠沒有,也能夠有一個 2.整數,一位或者多位數字,一位0~9,多位數字不能以0開頭 3.小數部分:有可能有,也有可能沒有,有小數點後面至少要跟一位數字
let reg=/^[+-]?(\d|[1-9]\d+)(\.\d+)?$/;
複製代碼
案例:有效郵箱
第一部分:數字、字母、下劃線、
-
、.
,可是-
和.
不能做爲開頭
第二部分:xxx.xx.xx xxx.xx xxx.xx.xx.xx xxx-xxx-xx.xx.xx
let reg=/^\w+((-\w+)|(.\w+))@[A-Za-z0-9)]+([-.][A-Za-z0-9]+)*(\.[A-Za-z0-9]+)$/;
複製代碼
案例:中文姓名
中文漢字 [\u4E00-\u9FA5]
let reg=/^[\u4E00-\u9FA5]{2,}(·[\u4E00-\u9FA5]{2,})?$/
複製代碼
在JS中經過相關的屬性能夠獲取(設置)元素的樣式信息,這些屬性就是盒子模型屬性(基本上都是有關樣式的)
在JS盒子模型13個屬性中,只有scrollTop/scrollLeft是能夠寫的,其餘屬性只能讀
clientWidth/clientHeight
獲取當前元素可視區域的寬高和內容,當咱們設置了固定的寬高,和 是否有溢出無關(和是否設置了overflow:hidden也無關) 內容的寬高+左右/上下padding
- content-box::width+paddingLeft+paddingRight
- border-box:width-borderRight-borderLeft
//=>獲取當前頁面一屏幕(可視區域的寬度和高度)
document.documentElement.clientWidth||document.body.clientWidth(兼容各類模式的瀏覽器)
document.documentElement.clientHeight||document.body.clientHeight(兼容各類模式的瀏覽器)
複製代碼
clientTop/clientLeft
獲取(上/左)邊框的寬度
offsetWidth/offsetHeight
在client的基礎上加上左右/上下boder
content-box:width+paddingLeft+paddingRight+borderRight+borderLeft
border-box:width
offsetParent
當前盒子的父級參照物
參照物
:同一個平面中,元素的父級參照物和結構沒有必然的聯繫,默認他們的父級參照物都是body(當前平面最外層的盒子),body的父級參照物爲null
參照物能夠改變
:構建出不一樣的平面便可(使用z-index,可是這個屬性只對定位有做用),改變元素的定位(position:relative/absolute/fixed)能夠改變其父級參照物。
若此元素爲當前平面的最大元素,那麼將往當前元素脫離出來的那個平面上找父級元素
![]()
offsetLeft/offsetTop
獲取當前盒子距離其父級參照物的偏移量(上偏移量/左偏移)
當前盒子的外邊框開始~父級參照物的內邊框
無論當前元素的父級元素是誰,都要得到當前元素距離body的左,上偏移量
let offset=function (curEle){
let curEleLeft=curEle.offsetLeft,
curEleTop=curEle.offsetTop,
p=curEle.offsetParent;
while(p.tagName!=="BODY"){
curEleLeft+=p.offsetLeft+p.clientLeft;
curEleTop+=p.offsetTop+p.clientTop;
p=p.offsetParent;
}
return {
top:curEleTop;
left:curEleLeft;
}
}
複製代碼
scrollWidth/scrollHeight
真實內容的寬高(包含溢出的內容)+左右/上下padding
真實內容的寬高不必定是本身設定的值,由於可能會存在內容溢出,有內容溢出的狀況下,須要把溢出的內容也算上,
沒有內容溢出和client同樣
在不一樣瀏覽器中,無論是否設置了overflow:hidden都會對最後的結果產生影響,因此這個值僅僅作參考,屬於約等於的值
//=>獲取當前頁面的真實寬高(包含溢出的部分)
document.documentElement.scrollWidth||document.body.scrollWidth(兼容各類模式的瀏覽器)
document.documentElement.scrollHeight||document.body.scrollHeight(兼容各類模式的瀏覽器)
複製代碼
scrollLeft/scrollTop
滾動條捲去的寬度和高度
最小卷去值
:0最大卷去值
:真實頁面的高度減去一屏幕的高度 document.documentElement.scrollHeight-document.documentElement.clientHeight
操做瀏覽器的盒子模型屬性,咱們通常都要寫兩套,用來兼容各類模式下的瀏覽器
let windHandle=function (attr,value){
if(typeof value !=="undefined"){
document.documentElement[attr]=value;
document.body[attr]=value;
return;
}
return document.documentElement[attr]||document.body[attr];
}
複製代碼
這兩個屬性是"可讀寫"屬性,能夠修改它的值,可是其他11個屬性值都是「只讀」屬性,只能獲取不能修改
1.獲取的都是數字不帶單位
2.獲取的都是整數,不會出現小數(通常都會四捨五入,尤爲是獲取的偏移量)
3.獲取的結果都是複合樣式值(好幾個元素樣式組合在一塊兒的值),若是隻想獲取單一的樣式值(例如:只想獲取padding),咱們的盒子模型屬性就操做不了了(這不能說沒有用,真實項目中咱們就是要獲取組合的值)
只能獲取全部寫在元素行內上的樣式(不寫在行內上,無論你寫沒寫都獲取不到,真實項目中咱們不多會把樣式寫在行內上)
通過計算的樣式:只要當前元素能夠在頁面中呈現(或者瀏覽器渲染它了),那麼它的樣式都是被計算過的
- 無論當前樣式寫在哪
- 無論你是否寫了(瀏覽器會給元素設置一些默認樣式)
標準瀏覽器(IE9+)
window.getComputedStyle([元素],[僞類,通常都寫null])
經過getComputedStyle方法獲得的是一個對象,每個屬性名是當前元素全部的css屬性名,屬性值是css的屬性值
getComputedStyle是window這個實例上的一個屬性
IE6~8
[元素].currentStyle 獲取通過計算的樣式
獲取當前元素的某一個樣式屬性值--封裝
/* * getCSS:獲取某個元素的某個屬性值 * * @param * curEle[object]:當前要操做的元素 * attr[string]:當前要操做的樣式屬性名 * * return * value[string]:當前要獲取的元素的某個屬性值 */
let getCSS=function (curEle,attr){
if("getComputedStyle" in window){
let value=window.getComputedStyle(curEle,null)[attr];
let reg=/^-?\d+(\.\d+)?(px|rem|em|pt)?$/i;
reg.test(value)?value=parseFloat(value):null;
}else{
throw new Error('您的瀏覽器版本太低,請升級到最新版本,謝謝配合!!')
}
return value;
};
複製代碼
細節知識點補充
一、
當屬性名用變量的話,只能用對象[屬性名]的方法
function test(attr){
var obj={aa:21};
console.log(obj.attr); //undefined
console.log(obj[attr]); //21
}
test("aa");
複製代碼
二、
throw是關鍵字,用來拋出一個用戶自定義的異常當前函數的執行將被中止,throw以後的語句將不會執行
語法:throw expression(要拋出的表達式)
throw "Error2" //=>拋出一個值爲字符串的異常
throw 42 //=>拋出一個值爲整數42的異常
throw true //=>拋出了一個值爲true的異常
複製代碼
三、
:Error是一個類語法: new Error(message) 構造一個Error的實例
message是人類可閱讀的錯誤描述信息
基於Error類能夠建立用於用戶自定義的異常
設置當前元素的某一個具體樣式的屬性值--封裝
let setCss=function(curEle,attr,value){
if(attr==="opacity"){
curEle.style.opacity=value;
curEle.style.filter=`alpha(opacity=${value*100})`;
}
if(!isNaN(value){
let reg=/^width|height|fontsize|((margin|padding)?(top|left|right|bottom)?)$/i;
reg.test(value)?value=+"px":null;
})
curEle.style[attr]=value;
};
複製代碼
批量給元素設置屬性以後--封裝
let setGroupCss=function (curEle,options){
for(let attr in options){
if(!options.hasOwnProperty(attr)) break;
setCss(curEle,attr,options[attr]);
}
};
複製代碼
for in循環
遍歷一個對象中的鍵值對的,有多少組鍵值對,咱們就遍歷多少次
遍歷的時候,先遍歷數字屬性名(按照從小到大),再遍歷字符串屬性名(按照書寫順序)
let obj={name:"xxx",age:27,0:0,sex:0,score:100,1:1};
for(let key in obj){
console.log(key);
console.log(obj[key]);
}
輸出結果:
0 1 name age sex scroe
0 1 "xxx" 27 0 100
複製代碼
for in循環只遍歷當前對象可枚舉(可遍歷)的屬性
- 對象的私有屬性(本身寫的)是可枚舉的
- 對象中瀏覽器內置的屬性是不可枚舉的
- 本身手動在Object類原型上設置的屬性也是可枚舉的,Object.prototype內置的自己自帶的屬性時不枚舉的
let obj={name:"xxx",age:27,0:0,sex:0,score:100,1:1};
Object.prototype.bbb=10;
for(let attr in obj){
console.log(attr);
}
輸出結果:
0 1 name age sex score bbb
----------------
爲了不把手動在原型上添加的屬性也遍歷出來
for(let attr in obj){
if(!obj.hasOwnProperty(attr)){
break;
}
}
手動在原型上添加的屬性會最後遍歷
複製代碼
給元素設置樣式--封裝
let css=function (...arg){//=>剩餘運算符
let len=arg.length,
fn=getCss;
len>=3?fn=setCss:null;
len===2&&arg[1] instanceof Object?fn=setGroupCss:null;
return fn(...arg);//=>展開運算符
};
複製代碼
案例:跑馬燈
原理
:將要展現的內容,完整的克隆一份放到其末尾,利用定時器,每隔一段時間將要展現的內容往前移動一段距離,當第一組的內容所有滾動完,此時框的最左邊正好展現的是克隆內容的開頭,這時讓移動的距離變爲0,整個內容回從新返回起始位置,實現無縫;
實現JS動畫
:讓要移動的部分沒間隔一段時間(最優動畫時間是13~17MS)在原有的LEFT值基礎上減去步長(向讓動畫塊一些,步長就大一點)
知識點補充--定時器
window.setTimeout([function],[interval])
設置一個定時器,當到達指定時間後執行對應的方法(執行一次定時器就結束了)
window.setInterval([function],[interval])
設置一個定時器,當達到指定時間後執行對應的方法(之後沒間隔這麼長時間都要從新的執行定時器的方法,直到定時器清除爲止,執行不少次)
let n=0;
setInterval(()=>{
console.log(++n);
},1000)
複製代碼
定時器的返回值
定時器的返回值:當咱們設置定時器(無論是setTimeout仍是setInterval),都會有一個返回值,返回值是一個數字,表明當前是在瀏覽器中設置的第幾個定時器(返回的是定時器序號)
setTimeout和setInterval雖然是處理不一樣需求的定時器,可是都是瀏覽器的定時器,因此設置的時候,返回的序號是依次排列的
setInterval設置完成定時器會有一個返回值,無論執行多少次,這個表明序號的返回值不變(設置定時器就有返回值,執行多少次是定時器的處理)
let timer1=setTimeout(function(){},1000);
console.log(timer1);//=>1 表明版本號
let timer2=setInterval(function(){},1000);
console.log(timer2);//=>2 表明版本號
let timer3=setInterval(function(){},1000);
console.log(timer3);//=>3 表明版本號
複製代碼
定時器的清除
clearTimeout([定時器的排隊序號])
clearInterval([定時器的排隊序號])
let t1=setTimeout(function(){
console.log(t1);//=>1
clearTimeout(t1);
t1=null;//=>手動將以前存儲序號的變量賦值爲null
})
複製代碼
<style>
.wrapper{
width:300px;
height:100px;
margin:20px auto;
border:1px solid red;
position:relative;
}
.list{
position:absolute;
top:0;
left:0;
}
.wrapper li{
width:100px;
height:100px;
line-height:100px;
text-align:center;
}
li:nth-child(even){
background-color:red;
}
li:nth-child(odd){
background-color:blue;
}
</style>
<div class="wrapper">
<ul class="list clear" id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
複製代碼
let listBox=document.getElementById("list");
listBox.innerHTML+=listBox.innerHTML;
utils.css(listBox,"width",utils.css(listBox,"width")*2);
setInterVal(function(){
let cur=utils.css(listBox,"left");
cur-=2;
utils.css(listBox,"left",cur);
Math.abs(listBox.offsetLeft)===utils.css(listBox,"width")/2?utils.css(listBox,"left",0)
},13)
複製代碼
案例:勻速回到頂部
(function (){
let link=document.getElementById("link");
//=>當頁面在滾動的時候(鼠標滾輪/鍵盤按鍵/手動拖動滾動條/基於JS控制頁面滾動的時候...),咱們須要隨時獲取當前頁面捲去的高度,若是捲去的高度>一屏幕的高度,讓link顯示,不然隱藏
//=>window.onscroll:當頁面滾動的時候觸發的事件
window.onscroll=function(){
let scrollT=document.documentElement.scrollTop,
clientT=document.documentElement.clientTop;
if(scrollT>clientT){
link.style.display="block";
}else{
link.style.displey="none"
}
};
let isRun=false;//=>記錄當前是否正在運動,默認false沒有運動,當點擊A標籤開啓動畫的時候,讓其變爲true,動畫結束讓其變爲false,在它爲true的時候,咱們點擊A標籤不回話再作任何事情,防止重複點擊;
//=>若是重複點擊,會屢次執行函數,也就是會設置多個定時器,走的距離就是全部定時器累加的距離,因此速度回愈來愈快
link.onclick=function(){
if(isRun){
return;
}
isRun=true;//=>修改的是上級做用域的isRun的值,若是setInterval沒有結束,那麼isRun的值一直都爲true,再點擊的時候,函數執行,直接return,下面的都不會執行
let curT=document.documentElement.scrollTop,
time=500,
interval=17,
step=curT/time*interval;
let timer=setInterval(function(){
let curTop=document.documentElement.scrollTop;
if(curTop===0){
isRun=false;
clearInterval(timer);
}
curTop-=step;
document.documentElement.scrollTop=curTop;
}interval);
}
})()
複製代碼
讓子類的原型指向父類的一個實例
function A(){
this.x=100;
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x);
}
};
function B(){
this.y=200;
}
B.prototype=new A();
let f=new B();
複製代碼
存在的問題
1.
子類能夠重寫父類原型上的方法,致使父類的實例受到影響
2.
父類實例私有的屬性以及公有的屬性都變爲子類實例的共有屬性
3.
沒法使用子類原有原型的上的方法(子類的原型被重定向)
把父類在子類中做爲普通函數執行,讓A中的this變爲子類的實例,至關於給子類的實例增長一些父類實例的私有屬性和方法
function A(){
this.x=100;
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x);
}
};
function B(){//=>this:f
A.call(this);//=>把A執行,讓A中的this變爲f
this.y=200;
}
let f=new B();
複製代碼
父類實例私有的變爲子類實例私有的,父類共有的變爲子類共有的
Object.create()
Object類上的一個方法1.
建立一個空對象
2.
讓新建立的空對象的__proto__指向第一個傳遞進來的對象
let obj={
name:"哈哈"
};
console.log(Object.create(obj))
複製代碼
function A(){
this.x=100;
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x);
}
};
function B(){
A.call(this);
this.y=200;
}
B.prototype=Object.create(A.prototype);
//=>至關於把B的原型指向了新建立的空對象,而空對象的__proto__又指向了A的原型
let f=new B();
----------
爲何不直接用B.prototype=A.prototype?
//=>太容易重寫原型
//B.prototype.xxx=xxx,就會直接修改A的原型,可是使用Object.create的方式,修改B上的原型,B.prototype.xxx=xxx是在給空對象增長或者修改東西,不會影響A原型上的東西
複製代碼
ES6中建立的類是由本身標準語法的,基於這種語法建立出來的類只能NEW執行,不能當作普通函數執行
class Fn{//=>這個大括號至關於FN的原型
constructor(n,m)}{//=>constructor至關於Fn,因此這個括號裏就是函數體裏面的東西
let total=null;
total=n+m;
this.x=n;
this.y=m;
return total;
}
//=>給Fn的原型上設置方法(只能設置方法不能設置屬性)
getX(){
console.log(this.x);
}
//=>把Fn當作一個普通對象設置的Fn類上的私有方法(只能設置方法不能設置屬性)
static AA(){
console.log(this.y);
}
}
Fn.aa=100;
Fn.prototype.bb=200;
let f=new Fn(10,20);
複製代碼
extends實現了原型繼承
super();相似於call繼承
class A{
constructor(){
this.x=100;
}
getX(){
console.log(this.y);
}
}
A.aa=100;
class B extends A{//=>B的原型
constructor(){
super();
this.y=200;
}
getY(){
console.log(this.x);
}
}
let f=new B();
複製代碼
B的實例既能夠調取B原型上的公有屬性和方法,也能夠調取A上的公有屬性和方法
B的實例也擁有A的實例的私有屬性
B類既有本身的私有屬性,也能夠調取A類的私有屬性
練習題
class Animal {
constructor(name = 'John Doe', species = '物種'){
this.name = name; this.species = species;
}
sayHello(){
console.log('hello',this.name,this.species)
}
}
class Sheep extends Animal{
constructor(name = 'Jimmy',species = '羊'){
super(name, species);
//=>至關於Animal.call(this,name,species);
}
sayHello(){
console.log(super.sayHello);
console.log('child'); super.sayHello()//=>super指的是Animal.prototype
}
}
let sheep = new Sheep('Tom');
sheep.sayHello();
複製代碼
設定一個定時器,而且設定了等待的時間,當到達指定的時間,瀏覽器會把對應的方法執行
設置定時器會有一個返回值,這個值是一個數字,屬於定時器的編號,表明當前是第幾個定時器(無論是基於setTimeout仍是setInterval建立定時器,這個編號會累加)
可執行屢次的定時器,也被稱爲輪循定時器,每間隔interval這麼長的時間,都會把設定的方法從新執行一次,直到定時器被清除
語法
:setInterval([function],[interval])
只能執行一次的定時器
語法
:setTimeout([function],[interval])
定時器時間因子即便設置爲0也不是當即實行,仍是異步編程,每個瀏覽器都有一個本身最小的等待和反應時間(谷歌:5~6,IE:10~14)
let n=0;
setTimeout(()=>{
console.log(++n);
},0);
console.log(n);
//=>結果:0,1
複製代碼
均可以清除setInterval和setTimeout建立的定時器,本質是根據序號清除瀏覽器中設定的定時器
均可以清除setInterval和setTimeout建立的定時器,本質是根據序號清除瀏覽器中設定的定時器
JS中大部分都是同步編程
任務是按照順序依次處理,當前這件事沒有完全作完,下一件事是執行不了的
定義
:當前這件事沒有完全作完,須要等待一段時間才能繼續處理,此時咱們不等,繼續執行下面的任務,當後面的任務完成後,再去把沒有完全完成的事情完成
JS中經常使用的異步編程
定時器到達必定時間,也不必定執行
let n=0;
setInterval(()=>{
console.log(n);
},1000)
console.log(n);
while(1===1){
//=>死循環
}
複製代碼
瀏覽器是多線程的,JS是單線程的(瀏覽器只給JS執行分配一個線程)
單線程的特色就是一次只能處理一件事情
進程
每一個應用程序均可以理解爲一個進程,瀏覽器打開一個頁面,就至關於開闢一個進程,在一個進程中,咱們須要同時幹不少事情,此時咱們能夠分配多個線程去同時完成多項任務
JS在單線程中實現異步的機制
主要依賴於瀏覽器的任務隊列完成的,瀏覽器中有兩個任務隊列,主任務隊列用於供JS代碼自上而下執行,等待任務隊列用於存放異步操做任務
當主任務隊列完成後纔會到等待任務隊列中進行查找,主任務隊列完不成,無論等待任務隊列中是否有到達時間的,都不處理,繼續等待主任務隊列完成。
等待任務隊列中誰達到條件了(若是又不少都達到條件了,誰先達到的,就先處理誰),就把這個任務從新放到主任務隊列中去執行,把這個任務執行完,再去等待中找下一個,以此類推
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
setTimeout(() => {
console.log(4);
}, 100);
for (let i = 0; i < 90000000; i++) {
}
console.log(5);
複製代碼
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
for (let i = 0; i < 90000000; i++) {
}
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
----
循環以前的定時器,在循環尚未結束的時候時間就已經到了,而循環以後的定時器,是要等到循環結束了,才被放到等到任務序列中,也就是與循環以前的相比要完了200MS(循環的時間),因此即便下面的定時器的時間短,也是上面的定時器先到達時間,先被拿到主任務隊列內執行
複製代碼
這兩個方法配合使用能夠用來統計執行某個函數所用的時間
console.time('AA');
for (var i = 0; i < 90000; i++) {
for (var j = 0; j < 90000; j++) {}
}
console.timeEnd('AA');
複製代碼
獲取當前客戶端本機時間(當前獲取的時間不能做爲重要的參考依據)
let a=new Date();
for (var i = 0; i < 90000; i++) {
for (var j = 0; j < 90000; j++) {}
}
console.log(new Date()-a);
複製代碼
var time = new Date();//=>獲取當前客戶端本機時間(當前獲取的時間不能做爲重要的參考依據)
//=>獲取的結果是一個日期格式的對象:Sun Apr 01 2018 15:55:23 GMT+0800 (中國標準時間)
typeof new Date() ->'object'
//=>time.getFullYear() 獲取四位整數年
//=>time.getMonth() 獲取月(0-11表明1-12月)
//=>time.getDate() 獲取日
//=>time.getDay() 獲取星期(0-6表明週日到週六)
//=>time.getHours() 獲取小時
//=>time.getMinutes() 獲取分鐘
//=>time.getSeconds() 獲取秒
//=>time.getMilliseconds()獲取毫秒
//=>time.gettime() 獲取當前日期距離'1970-1-1 00:00:00'的毫秒差
複製代碼
var time = new Date('2017-10-22');//=>當newDate中傳遞一個時間格式的字符串,至關於把這個字符串轉換爲標準的時間對象格式(轉換完成後,就能夠調取上面咱們將的那些方法了)
//=>時間格式的字符串
'2017-10-22' (IE下識別不了)
'2017/10/22'
'2017/10/22 16:15:34'
1522569836707 (若是傳遞的是距離1970年的那個毫秒差,也是能夠識別轉換的,可是這個只能是數字,不能是字符串)
...
複製代碼
案例:京東倒計時搶購
let timeBox=document.querySelector(".timeBox"),
timeSpan=timeBox.querySelector("span"),
_serverTime=null,
autoTimer=null;
//=>獲取服務器當前的時間,注意縮短客戶端接收服務器端的時間
let queryTime=function (){
return new Promise((resolve)=>{
let xhr=new XMLHttpRequest();
xhr.open("head","temp.json",true);//=>"head"的方式會比"get"快
xhr.onreadystatechange=function(){
if(xhr.readyState===2 && xhr.status===200){//=>當readystate爲2的時候,響應頭信息就已經返回了,無需等到4,另外就算請求沒有成功也能夠獲得響應頭的信息,可是項目中通常都要加上這句話避免出現404頁面
_serverTime=new Date(xhr.getResponseHeader("date"));//=>請求頭上獲得的時間信息是格林尼治時間,要用new Date轉化成北京時間
resolve(_serverTime);
}
}
xhr.send(null);
})
}
//=>動態計算當前倒計時時間
let count=0;//=>記錄第幾回執行computedTime,由於第一次執行的時候就直接用服務器拿到的時間,第二次以後執行的時候才須要往上累加時間
let computedTime=function (){
if(count>0){
let time=_serverTime.getTime();//=>獲得距離1970/1/1 00:00:00的時間,再加上1s,再轉換回標準北京時間
time+=1000;
_serverTime=new Date(time);
}
count++;
let nowTime=_serverTime,
targetTime=new Date("2018/5/25 23:00:00"),
changeTime=targetTime-nowTime;//=>兩個標準時間相減,獲得的是毫秒差
if(changeTime<=0){
clearInterval(autoTimer);
}
let hours=Math.floor(changeTime/(1000*60*60));
changeTime=changeTime-hours*60*60*1000;
let minutes=Math.floor(changeTime/(1000*60));
changeTime=changeTime-minutes*60*1000;
let seconds=Math.floor(changeTime/1000);
hours<10?hours="0"+hours:null;
minutes<10?minutes="0"+minutes:null;
seconds<10?seconds="0"+seconds:null;
timeSpan.innerText=` ${hours}:${minutes}:${seconds} `;
}
queryTime().then(()=>{
computedTime();
autoTimer=setInterval(computedTime,1000);
})
//=>若是每次都向服務器發送請求得到當前服務器的時間,會形成服務器崩潰,因此在不刷新頁面的狀況下,咱們就向服務器請求一次數據,而後經過定時器手動累加時間,只有當頁面從新刷新的時候纔會從新向服務器發送請求獲得時間
複製代碼
Promise是ES6中新增的類(new Promise),目的是爲了管理JS中的異步編程,也將其稱爲"Promise設計模式"
Promsie自己是同步的,能夠管理異步操做,new Promise會建立一個Promise實例,當即會把當前函數體中的異步操做執行,必須傳遞一個回調函數進去,不傳遞會報錯
new Promise(()=>{
setTimeout(() => {
console.log(3);//=>最後輸出3
}, 2000);
console.log(1);//=>先輸出1
})
console.log(2);//=>再輸出2
複製代碼
new Promise的回調函數中會傳兩個參數(resolve,reject),異步操做執行成功,執行resolve方法;異步操做失敗了,執行reject方法
Promise原型上有then方法,第一個參數表明是異步執行成功要作的事情(即resolve),第二個參數表明的是異步執行失敗要作的事情(即reject)
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(100);
},1000);
}).then((res)=>{
console.log("ok",res);
},()=>{
console.log("no");
})
複製代碼
then中的對應的方法執行後返回的也是Promise實例(是新的實例,與以前的實例不是一個)能夠繼續調用then方法,並且第一個then中的回調函數執行的返回結果,會當作實參傳給第二個then中對應的回調函數的形參
let pro = new Promise((resolve, reject) => {
//=>執行一個異步操做
let xhr = new XMLHttpRequest();
xhr.open('get', 'js/1.js', true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
val = xhr.responseText;
resolve(val);
}
if (xhr.status !== 200) {
//=>失敗
reject();
}
};
xhr.send(null);
});
pro.then((res)=>{//=>至關於這個函數就是resolve
console.log(res);//=>輸出val,
},()=>{//=>至關於這個函數是reject
console.log("no");
}).then((res)=>{
console.log(res);//=>100
},()=>{})
複製代碼
若是調用多個then,異步操做成功或者失敗,先把第一個then中對應的成功或者失敗的方法執行,返回一個新的Promise實例,這個新的實例管控第一個then中方法執行的成功仍是失敗,若是成功了就執行第二個then中成功的方法執行,若是失敗了就執行了第二個then中失敗的方法,相似於樹狀圖
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data2.json',
success(result) {
resolve(result);
},
error(msg) {
reject('no');
}
});
});
promise1.then(
result => {
console.log('THEN1 OK', result);
return 100;
},
msg => {
console.log('THEN1 NO', msg);
return 100;
}
).then(
result => {
console.log('THEN2 OK', result);
},
msg => {
console.log('THEN2 NO', msg);
}
);
//=>若'json/data2.json'存在,輸出'THEN1 OK 獲取的數據',再輸出'THEN2 OK 100'
//=>若'json/data2.json'不存在,輸出'THEN1 NO xhr的實例',再輸出'THEN2 OK 100'(jQuery的ajax中若請求失敗,會把xhr實例做爲實參傳遞給失敗時執行的函數)
複製代碼
真實項目中,通常咱們不用then同時管理成功和失敗的方法,只管理成功的方法,失敗的方法由catch方法來管理,catch方法不只異步請求失敗會執行它,第一個then方法執行失敗也會執行它,也就是管着兄弟和爹
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data2.json',//=>不存在
success(result) {
resolve(result);
},
error(msg) {
reject('no');
}
});
});
promise1.then(result => {
console.log('THEN1 OK', result);
return 100;
}).catch(msg => {
console.log('CATCH1', msg);
return 100;
})
//=>輸出"catch1 no"
複製代碼
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data.json',//=>存在
success(result) {
resolve(result);
},
error(msg) {
reject('no');
}
});
});
promise1.then(result => {
console.log('THEN1 OK', result);
100();
return 100;
}).catch(msg => {
console.log('CATCH1', msg);
return 100;
})
"catch1 TypeError: 100 is not a function"
複製代碼
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data2.json',//=>不存在
success(result) {
resolve(result);
},
error(msg) {
reject('no');
}
});
});
promise1.then(result => {
console.log('THEN1 OK', result);
return 100;
}).catch(msg => {
console.log('CATCH1', msg);
return 100;
}).then(result => {
console.log('THEN2 OK', result);
100();
}).catch(msg => {
console.log('CATCH2', msg);
});
//=>輸出'CATCH1 no',
//=>'THEN2 OK 100'
//=>'CATCH2 TypeError: 100 is not a function'
複製代碼
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data2.json',//=>不存在
success(result) {
resolve(result);
},
error(msg) {
reject('no');
}
});
});
promise1.then(result => {
console.log('THEN1 OK', result);
return 100;
}).catch(msg => {
console.log('CATCH1', msg);
100();
return 100;
}).then(result => {
console.log('THEN2 OK', result);
}).catch(msg => {
console.log('CATCH2', msg);
});
//=>輸出'CATCH1 no'
//=>'CATCH2 TypeError: 100 is not a function'
複製代碼
catch方法和then方法中的回調函數執行的過程當中若是報錯瀏覽器不會報錯,會把報錯的內容當作實參傳遞給下一個then或者catch方法,即便當前的catch和then有return值也會被報錯覆蓋,把報錯的內容傳遞給下一個then或者catch方法,相似於JS中的異常捕獲(目的:把拋出異常的錯誤捕獲到,不讓其阻斷瀏覽器的繼續執行)
try{
1();
}catch (e){
//=>try中的代碼報錯了會執行catch
console.log(e.message);
} finally{
//=>無論try中的代碼成功仍是失敗都會執行
console.log("ok");
}
複製代碼
Promise上還有finally方法,無論上面的then或者catch方法執行成功或者失敗都會執行finally,可是上面的then或者catch方法的返回值不會傳遞給finally做爲實參,若是上面的then或者catch方法中的回調函數中有報錯的話,會直接在瀏覽器內報錯,可是即便這樣也不會阻止finally的執行
若是finally方法後面還有then或者catch的話,就當作有沒finally方法,管控的仍是前面的then和catch
let promise1 = new Promise((resolve, reject) => {
$.ajax({
url: 'json/data.json',//=>地址存在
success(result) {
resolve(result);
},
error: reject
});
});
promise1.then(result => {
console.log('THEN1 OK', result);
100();
return 100;
}).catch(msg => {
console.log('CATCH1', msg);
100();
return 100;
}).finally(result => {
console.log('THEN2 OK', result);
// 100();
}).then(result=>{
console.log("ok",result);
}).catch(result=>{
console.log("no",result);
});
//=>THEN1 OK []
//=>CATCH1 TypeError: 100 is not a function
//=>THEN2 OK undefined
//=>no TypeError: 100 is not a function
複製代碼
使用Promise解決回調地獄
有A,B,C三個請求,實現,A請求成功拿到數據後再執行B請求拿到數據後再執行C請求
let promise1=function (){
return new Promise(reslove){
$.ajax({
url:"url1",
method:"get",
cache:false
success:resolve
})
}
};
let promise2=function (){
return new Promise(reslove){
$.ajax({
url:"url2",
method:"get",
cache:false
success:resolve
})
}
};
let promise3=function (){
return new Promise(reslove){
$.ajax({
url:"url3",
method:"get",
cache:false
success:resolve
})
}
}
promise1().then(()=>{
return promise2();
}).then(()=>{
promise3();
})
複製代碼
定義
: 把一個函數A當作實參傳遞給另一個函數B,在B方法執行的時候,把A執行了,這種機制被稱爲"回調函數機制"
一、能夠給回調函數傳遞實參執行
二、能夠改變回調函數中的this指向
三、能夠在宿主函數(它在哪執行的,它的宿主函數就是誰)中接收回調函數執行的返回結果
let fn=(callback)=>{
callback&&callback.call(obj,100,200);
let res=callback(10,20);
console.log(res);
}
複製代碼
回調函數中的this通常是window,除非宿主函數執行回調函數的時候把this特殊指向了(箭頭函數除外:箭頭函數中的this是它的上下文)
重寫jQuery上的each方法
能夠遍歷數組,類數組,對象,若是是數組(類數組)和forEach方法相似,若是是對象和for in循環相似
let each=function(obj,callback){
if(obj.hasOwnProperty("length")){
for(let i=0;i<obj.length;i++){
let res=callback&&callback.call(obj[i],i,obj[i]);
if(res===false) break;
}else{
for(let key in obj){
if(!obj.hasOwnProperty(key)) break;
let res=callback&&callback.call(obj[key],key,obj[key]);
if(res===false) break;
}
}
}
}
複製代碼
重寫forEach方法
循環遍歷數組中的每一項,每遍歷一次把回調函數執行一次,並把當前項和對應的索引傳遞給回調函數,若是方法中傳遞第二個參數的話,那麼將回調函數中的this指向第二個參數
Array.prototype.myforEach=function myforEach(callback,context){
context=context||window;
for(let i=0;i<this.length;i++){
callback.call(context,this[i],i);
}
};
複製代碼
重寫map方法
循環遍歷數組中的每一項,每遍歷一次把回調函數執行一次,並把當前項和對應的索引傳遞給回調函數,並將當前項替換成回調函數的返回值,循環結束後以新數組的形式返回,若是方法中傳遞第二個參數的話,那麼將回調函數中的this指向第二個參數
Array.prototype.myMap=function myMap(callback,context){
context=context||window;
let ary=[];
for(let i=0;i<this.length;i++){
let res=callback&&callback.call(context,this[i],i);
ary.push(res);
}
return ary;
}
複製代碼
重寫filter方法
循環遍歷數組中的每一項,每遍歷一次把回調函數執行一次,並把當前項和對應的索引傳遞給回調函數,將全部回調函數返回值(Boolean後)爲true的當前項以新數組的形式返回,若是方法中傳遞第二個參數的話,那麼將回調函數中的this指向第二個參數
Array.prototype.myFilter=function myFilter(callback,context){
context=context||window;
let ary=[];
for(let i=0;i<this.length;i++){
let res=callback&&callback.call(context,this[i],i);
if(res){
ary.push(this[i]);
}
}
return ary;
}
複製代碼
重寫find方法
循環遍歷數組中的每一項,每遍歷一次把回調函數執行一次,並把當前項和對應的索引傳遞給回調函數,將全部回調函數返回值(Boolean後)爲ture的當前項返回,只要找到一個返回值爲true的就再也不往下找了
Array.prototype.myFind=function myFind(callback){
for(let i=0;i<this.length;i++){
let res=callback&&callback(this[i],i);
if(res){
return this[i];
}
}
}
複製代碼
重寫replace方法
重寫replace方法,第一個參數替換成第二個參數,若是第一個參數是正則,第二個參數是回調函數,正則每匹配一次就把回調函數執行一次,並把exec捕獲到的數組中的每一項依次傳遞給回調函數,回調函數的返回結果會替換被匹配到的內容,原有字符串不變
String.prototype.myReplace=function(reg,callback){
let str=this;
if(typeof reg==="string"&&typeof callback==="string"){
if(str.indexOf(reg)<0) return str;
let a=str.indexOf(reg[0]),
b=str.indexOf(reg[reg.length-1]);
str=str.substring(0,a)+callback+str.substring(b+1);
}else if(reg instanceof RegExp&&typeof callback==="function"){
if(!reg.global){
let regExec=reg.exec(this);
let res=callback(...regExec);
let c=regExec[0],
a=str.indexOf(c[0]),
b=str.indexOf(c[c.length-1]);
str=str.substring(0,a)+res+str.substring(b+1);
return str;
}
let regExec=reg.exec(this);
while (regExec){
let res=callback(...regExec);
let c=regExec[0];
let a=str.indexOf(c[0]),
b=str.indexOf(c[c.length-1]);
str=str.substring(0,a)+res+str.substring(b+1);
regExec=reg.exec(this);
}
}else if(typeof reg==="string"&&typeof callback==="function"){
let res=callback();
let a=str.indexOf(reg[0]),
b=str.indexOf(reg[reg.length-1]);
str=str.substring(0,a)+res+str.substring(b+1);
}
return str;
};
複製代碼