基礎(chǔ)篇
—————————————————————————————————————————————————
history:
用來控制網(wǎng)頁前進(jìn)和后退,根據(jù)的是網(wǎng)頁歷史紀(jì)錄
history.back(); //后退 history.forward();//前進(jìn)
無刷新更改URL:
history.pushState(data:json,title:string,url:string);// 會存儲在url歷史中 history.replaceState(data:json,title:string,url:string);// 不會存儲。。。 data是你要存放的數(shù)據(jù),可以使用history.state獲取,title是標(biāo)題,為空則不改變,url是新url
location:
用來控制頁面跳轉(zhuǎn) location.replace("xx");//跳轉(zhuǎn) location.href = 'xxxx';//同上 location.reload();//刷新頁面
定時器:
- var id = setInterval(callback,ms);//每隔ms毫秒執(zhí)行一次函數(shù)(回調(diào)函數(shù)只寫函數(shù)名)
- var id = setTimeout(callback,ms);//在ms毫秒后執(zhí)行一次函數(shù)
- clearInterval(timer);//清理掉setInterval定時器
- clearTimeout(timeout);//讓setTimeout定時器失效
- window.requestAnimationFrame(callBack);//專門為動畫設(shè)置的定時器(效果比setInterval流暢,每秒執(zhí)行60次,大部分瀏覽器中,每秒執(zhí)行次數(shù)和顯示器刷新率一致)
事件綁定的方法:
直接使用元素的onclick屬性:
<button onclick="btnhandler(this)"> click me </button>
綁定一個事件:
getElementById("xx").onclick = function(e){
xxxxxxxx;
}
事件監(jiān)聽:
document.getElementById("xxx").addEventListener('click',function(e){
xxxxxx;
})
注意:事件名稱前不加on
區(qū)別: 使用內(nèi)聯(lián)onclick屬性似乎只能傳遞自身而不能傳遞事件對象 事件監(jiān)聽可以在一種事件上綁定多個方法
注意: 當(dāng)元素是動態(tài)生成的時候,在元素生成前綁定的事件無效,如:
$('.btn').click(function (e){ ...... });
$('body’).append('<button class="btn">...</button>'); // 單擊事件不能綁定到新的元素上面
手動調(diào)用事件:
element.onclick() || element.onclick.call() ; jquery方式:$(sel).click();
onchange當(dāng)表單的值改變時觸發(fā)(需鼠標(biāo)抬起,不是即時的) oninput當(dāng)表單控件受到改變時觸發(fā)(即時的)
事件對象:
事件對象自動傳遞給回調(diào)函數(shù) element.onclick = function(e){};// e就是事件對象 e的常見屬性: e.target;//獲取觸發(fā)此事件的元素(不一定是綁定元素) e.currentTarget//獲取觸發(fā)此事件的元素(一定是綁定元素) e.offsetX ||e.offsetY ;//獲取鼠標(biāo)基于target元素內(nèi)部的偏移x和y e.clientX ||e.clientY ;//獲取鼠標(biāo)基于瀏覽器視窗的偏移x和y e.keyCode ||e.which;//返回鍵盤上的字符的代碼 事件回調(diào)中的this:指向事件的觸發(fā)元素
----如果事件處理函數(shù)的綁定在元素生成之前,則此元素不能綁定事件處理函數(shù),需重新設(shè)置
獲得和設(shè)置元素的行內(nèi)樣式(只針對行內(nèi)樣式):
var a = document.getElementById("xxx").style.width; document.getElementById("xxx").style.width = '500px'//注意加上單位
獲得作用在元素身上的樣式:
原生方式:
element.currentStyle.width || getComputedStyle( element,null).width ; 前者是ie專用,后者是w3c標(biāo)準(zhǔn),注意:用這種方法只能獲取不能設(shè)置
jquery 方式:
$(sel).css(styleName);// 注意數(shù)據(jù)類型以及單位 注:行內(nèi)樣式一定是起作用的樣式,所以用js設(shè)置元素樣式都是設(shè)置行內(nèi)樣式
js獲取元素位置及大?。?/h2>
- element.offsetTop;// 獲取元素相對于定位父元素(left,top屬性基于的元素)的頂部的距離
- element.scrollTop// 元素的滾動距離(該元素需要有滾動條,如果沒有則為0)【可寫】
- element.clientTop// 不常用
// 使用變換(transform)不會改變上述屬性的值 // 它們受left,top,margin等css屬性的影響,但不一定等于它們
- element.offsetHeight// 元素的高度(包括邊框,滾動條),返回?zé)o單位的number值
- element.clientHeight// 不包括邊框滾動條的高度,如果邊框無滾動條,則同上
- element.scrollHeight// 如果有滾動條,則獲取滾動內(nèi)容的高度,沒有滾動條則同上【可寫】
// 建議使用offsetHeight,因?yàn)槠渌嘏帕形恢脮r是會考慮邊框和滾動條的
offsetParent// 用于定位的基元素(默認(rèn)為最近的設(shè)置過position的父元素)
滾動動態(tài)加載內(nèi)容:
window.onscroll = function(e){ // 頁面滾動事件(一般加給window)
// 頁面被卷起來的高度距離頂部或底部的距離
var juan = document.documentElement.scrollTop; // 獲取頁面被卷起來的高度,documentElement相當(dāng)于html標(biāo)簽
var total = document.documentElement.scrollHeight; // 獲取頁面總高度
var visul = window.innerHeight; // 獲取可見區(qū)的高度(即瀏覽器顯示出來的高度)
var bot = total - juan - visul; // bot就是可見區(qū)下面的高度(這是我們需要的)
........ // 當(dāng)bot小于某值時,加載新元素
}
注:document的類型是Document,document.documentElement才是常規(guī)的Element類型的DOM元素 注:onscroll事件觸發(fā)次數(shù)比較頻繁,可以考慮節(jié)流(一段時間內(nèi)只執(zhí)行一次)
js實(shí)現(xiàn)拖動:
需要給被拖動元素和window同時添加mousemove事件,因?yàn)榧词雇蟿訒r鼠標(biāo)在元素之外,也應(yīng)該能實(shí)現(xiàn)拖動。 具體實(shí)現(xiàn): 1.鼠標(biāo)按下目標(biāo)元素時,存儲clientX,clientY,以及被拖動元素的引用 2.鼠標(biāo)移動時,設(shè)置被拖動元素的left為當(dāng)前clientX - 預(yù)先存儲的clientX,clientY同理 3.釋放鼠標(biāo)時,清除之前存儲的數(shù)據(jù)
獲取body標(biāo)簽對應(yīng)的DOM :document.body
獲取html標(biāo)簽對應(yīng)的DOM :document.documentElement
圖片懶加載:
就是先不設(shè)置src,而是將路徑放到其他屬性中(如data-src),等到圖片處于顯示區(qū)或接近顯示區(qū)時,再設(shè)置src
HTML DOM事件在:http://www.runoob.com/jsref/dom-obj-event.html
右鍵點(diǎn)擊事件
oncontextmenu
表單綁定事件的考慮:
- onkeydown// 按下按鍵時立即觸發(fā),該事件一般綁定在document/window上,因?yàn)榧词贡唤壎ǖ谋韱螞]有獲得焦點(diǎn),該事件也會執(zhí)行
- onkeypress// 按下按鍵時立即觸發(fā),只有被綁定的元素獲得焦點(diǎn)了,才會執(zhí)行事件(適用于動態(tài)search)
- onchange// 表單值改變時執(zhí)行,按下按鍵時不是立即觸發(fā),而是等到輸入完畢時才會觸發(fā)(輸入完畢指的是按下回車或表單失去焦點(diǎn))
- oninput// 表單值改變時立即觸發(fā)
實(shí)例:
window.keydown = function(e){ //鍵盤事件一般和窗口綁定
var ev = window.event || e; //獲得事件對象(IE和其他瀏覽器均可用)
var word = String.fromCharCode(ev.keyCode); //將ascii碼轉(zhuǎn)換成字符
alert(word);
}
動畫事件:
事件 描述
- animationend 該事件在 CSS 動畫結(jié)束播放時觸發(fā)
- animationiteration 該事件在 CSS 動畫重復(fù)播放時觸發(fā)
- animationstart 該事件在 CSS 動畫開始播放時觸發(fā)
- transitionend 該事件在 CSS 完成過渡后觸發(fā)。
目前,需要根據(jù)瀏覽器種類加前綴
事件流:
當(dāng)元素位置重疊的時候,點(diǎn)擊重疊的位置,每個元素的事件會按照一定的順序觸發(fā)。 若只想讓第一個事件觸發(fā),則可在那個事件的方法體中加入以下代碼: e.stopPropagation();//中斷此次事件的后續(xù)操作 若顯示層級位于表層的元素沒有事件而里層元素有綁定事件,那么事件不會觸發(fā),因?yàn)槭录鞑皇且粋€通路。這在給父元素加鼠標(biāo)事件時很常用
事件相互影響的問題: 例如:如按空格讓視頻暫停,在文本框中輸入空格也可能會讓視頻暫停,這是因?yàn)槭录芭莸缴霞?,只需要在文本框上的鍵盤事件上中斷事件流即可
事件委托:
例如,在一個ul中為要每個li設(shè)置點(diǎn)擊事件,只需給ul設(shè)置點(diǎn)擊事件即可,li的事件會冒泡至ul上,通過this|e.target獲取li的DOM對象
瀏覽器默認(rèn)事件: 如:點(diǎn)擊a標(biāo)簽后,瀏覽器會默認(rèn)跳轉(zhuǎn)到指定頁面;點(diǎn)擊鼠標(biāo)右鍵,會彈出上下文菜單等
阻止默認(rèn)事件:
建立onclick事件方法,加入var ev=window.event; ev.preventDefault();
阻止a標(biāo)簽的默認(rèn)事件:
<a href="javascript:void(0)">鏈接</a>
在事件處理函數(shù)中this的用法:
this在事件處理函數(shù)中指向事件源對象(觸發(fā)事件的元素對象) 當(dāng)元素被批量選中時,this指針對這些元素的事件處理非常有用 使用e.target也能獲取事件源對象// e表示事件對象 e.currentTarget表示最原始的觸發(fā)這個事件的對象(根據(jù)冒泡機(jī)制,只要條件符合,子元素也會觸發(fā)父元素身上的事件)
深入理解事件機(jī)制:
事件的傳遞分成三個階段: PHASE1.捕獲:事件從祖先元素開始(從window開始)向內(nèi)傳遞 PHASE2.目標(biāo):事件已經(jīng)到達(dá)目標(biāo)(最內(nèi)層的命中事件的元素) PHASE3.冒泡:事件向外(祖先)冒泡至window 默認(rèn)的偵聽器是偵聽冒泡階段的事件。
以點(diǎn)擊事件為例,鼠標(biāo)點(diǎn)擊后,會從window對象開始,檢索其子對象的區(qū)域是否包含點(diǎn)擊點(diǎn),html,body...直到某個元素的所有子元素的區(qū)域都不包含該點(diǎn)但自身包含該點(diǎn),則此元素為目標(biāo)元素,接著,從目標(biāo)元素開始,依次執(zhí)行點(diǎn)擊事件回調(diào),直到window對象。
ClickHandler(window,new MouseEvent(x,y));
bool ClickHandler(DOM * dom, MouseEvent * e){
List<DOM*> children = dom->children;
bool hit = false;
for(int i=0;i<children.length();i++){
hit = ClickHandler(children[i],e) ;
if(hit){
e->phase = 3;
e->currentTarget = children[i];
dom->eventListener('click').call(e);
return true;
}
}
if(dom.area.include(e->x,e->y)){
e->target = e->currentTarget = dom;
e->phase = 2;
dom->eventListener('click').call(e);
return true;
} else {
return false;
}
}
日期對象:
js中時間日期是以對象的形式實(shí)現(xiàn)的 var time = new Date();//獲得客戶端當(dāng)前的時間,返回一堆字符串,還可以用時間戳構(gòu)造(注意:客戶端的時間可能是不準(zhǔn)確的) var time = new Date(年,月,日,時,分,秒);//創(chuàng)建一個具體的時間 方法:
- getTime();//獲得從1970年1月1日到對象時間的毫秒數(shù)(時間戳)
- get年月日時分秒的英文();//獲得對應(yīng)的時間橙分,如getDate()獲得日數(shù)
- Date.now()返回毫秒級時間戳
- toLocalDateTimeString()// 返回本地化的日期時間字符串(對于北京時間,會變成12小時制)
抽取字符串中的數(shù)字:
parseInt(str);// 會提取字符串中的整數(shù)部分,遇到非整數(shù)會立即停止提?。贿m合去掉css中的單位 parseFloat(str)// 同上,可以提取小數(shù)
Number.toFixed(n)// 保留n位小數(shù),為0則只保留整數(shù) Number.round()// 返回最接近的整數(shù)(相當(dāng)于四舍五入) Number.floor()// 向小取整
定義一個匿名函數(shù),自動執(zhí)行:
(function (){
//代碼塊
}());
或者
(function (){
// 代碼塊
})();
可以在前面加上 ; 提升可靠性
常用DOM操作:
- appendChild(e)// 尾插
- insertBefore(e,ch)// 在子節(jié)點(diǎn)ch前插入e
- removeChild(e)// 刪除子節(jié)點(diǎn)
- replaceChild(new,old)// 替換子節(jié)點(diǎn)
- ------------------------------------------------------
- parentNode// 父節(jié)點(diǎn)
- children// 子節(jié)點(diǎn)集合
- childNodes// 子節(jié)點(diǎn)集合
- firstChild// 第一個子節(jié)點(diǎn)
- lastChild// 最后一個子節(jié)點(diǎn)
- previousSibling// 前一個兄弟節(jié)點(diǎn)
- nextSibling// 下一個兄弟節(jié)點(diǎn)
- -------------------------------------------------------
- setAttribute(name,value)// 設(shè)置元素的屬性
- getAttribute(name)// 獲取屬性
- hasAttribute(name)// 屬性是否存在
- -------------------------------------------------------
- dataset// 獲取以data-開頭的屬性(返回對象,只讀)
- classList// 獲取類名(類數(shù)組對象,只讀)
jquery篇
—————————————————————————————————————————————————
獲取元素:
兄弟:$(sel).siblings(sel); 父級:$(sel).parent(sel);// 只能抓上一級 前輩:$(sel).parents(sel);// 可能是多個 第一個:$(sel).first(); 第n個:$(sel).eq(n); 孩子:$(sel).chlidren(sel);// 注意只能抓下一級
取序號:$(sel).index();
迭代器:
$(sel).each(function (i,e)){ // i是序號,e是元素,只有一個參數(shù)時,表示序號
// 代碼
}
$.each(obj,function (i,e)){ // i是序號,e是元素,只有一個參數(shù)時,表示序號
// 代碼
}
注:js中數(shù)組API的回調(diào)函數(shù)通常是function(e,i){},即序號在后
DOM節(jié)點(diǎn)操作:
- append('xxxx'); // 在節(jié)點(diǎn)文本后添加內(nèi)容,返回原來的jQuery對象,而不是添加的
- appendTo(jQuery) // 將元素節(jié)點(diǎn)添加至指定jQuery對象的尾部
- prepend('xxxx'); // 在節(jié)點(diǎn)文本前添加內(nèi)容,返回原來的jQuery對象,而不是添加的
- before('xxxx'); // 在節(jié)點(diǎn)之前添加內(nèi)容(一般是新節(jié)點(diǎn))
- after('xxxx'); // 在節(jié)點(diǎn)之后添加內(nèi)容(一般是新節(jié)點(diǎn))
關(guān)于表單元素:注意table標(biāo)簽內(nèi)會自動加一個tbody標(biāo)簽,獲取<tr>元素:$('table tbody tr');
jquery動畫:
hide(time,callback) show(...) fadeIn(...) fadeOut(...) toggle動畫:toggle() toggleFade() toggleSlide() 指根據(jù)display來判斷做什么動畫
animate(json,timer,[timeFunc,callback]); obj:格式是{attrName:styleValue, ...},表示元素要達(dá)到的樣式 timer:int類型,表示動畫的毫秒數(shù) timeFunc:速度函數(shù),有ease,linear等 callback: 回調(diào)函數(shù)
獲取內(nèi)容:
html()// 獲取或設(shè)置innerHTML text()// 獲取或設(shè)置innerTEXT,會自動轉(zhuǎn)義 val();// 獲取或設(shè)置value(只能用于表單)
獲取寬高和位置:
position();//獲取匹配元素相對父元素的偏移,返回的對象包含兩個整型屬性:top 和 left height(); width();
返回數(shù)字,單位為px
jquery對象轉(zhuǎn)化為DOM元素對象:
jquery對象不能使用DOM對象的屬性和方法,jquery是對dom對象的封裝,使用jquery的0號元素即可獲得原來的DOM對象 $(sel)[0].setEventListener(....);
定義一個在頁面加載完成后立即執(zhí)行的函數(shù):
$(function (){
// 函數(shù)體
});
高級篇
—————————————————————————————————————————————————
函數(shù)中的this:
指向主調(diào)對象,或者window,其值是在運(yùn)行時可知的
函數(shù)對象和實(shí)例對象:
函數(shù)對象:即Function類型的對象 實(shí)例對象:new 函數(shù)名()后生成的對象
為函數(shù)對象添加方法:
function Foo(){
this.func = function (){ // 這是為實(shí)例添加方法:var obj = new Foo(); obj.func()
...
}
function func(){ // 沒有為任何對象添加方法,該函數(shù)僅在foo內(nèi)部可用,這是錯的:foo.func() (×)
...
}
}
Foo.func = function (){ // 這是為函數(shù)添加方法:foo.func()
...
}
js原型:
·所有函數(shù)都有prototype對象 ·prototype對象是一個Object類型的對象 ·該object對象中有一個constructor對象,指向該函數(shù)對象 ·可以為prototype對象設(shè)置屬性,這些屬性實(shí)際是給實(shí)例對象訪問的
示例:
var func = function (){
}
var f = new func();
func.prototype.print = function (){
console.log("print...");
}
f.print(); // 控制臺輸出print...
console.log(func.prototype.constructor === func) // true
所有實(shí)例對象都有一個__proto__屬性,也是object類型的,該屬性和其函數(shù)原型(構(gòu)造函數(shù))的prototype屬性是一樣的,它們共享一份Object對象,即函數(shù)對象.prototype = 實(shí)例對象.__proto__,在上述例子中就是func.prototype === f.__proto__
使用對象屬性(或方法)時,先測試對象本身有無此方法,若沒有,則在__proto__中查找,直到找到,或不存在。這種查找鏈就是原型鏈(原型鏈?zhǔn)褂玫氖莀_proto__而不是prototype)。
實(shí)例(接上例): f.toString(); // func中無toString方法,其原型中也無,于是通過__proto__到Object的原型中找,在Object中找到了toString方法,。
Function和Object的原型:
·Function和Object是系統(tǒng)內(nèi)置的函數(shù)。 ·所有函數(shù)對象都是Function類型的實(shí)例(通過new Function()得到) ·Object是內(nèi)置的函數(shù)對象,也是Function類型的實(shí)例對象 ·Function也是函數(shù)對象,它也是Function類型的實(shí)例對象 由以上三點(diǎn)可知: ·所有的函數(shù)對象都有prototype和__proto__兩個屬性,有prototype是因?yàn)樗泻瘮?shù)都有prototype對象,有__proto__是因?yàn)樗荈unction類型的實(shí)例 ·所有函數(shù)對象的__proto__都等于Function對象的prototype,因?yàn)樗泻瘮?shù)對象都是Function對象的實(shí)例 ·Function對象的prototype和__proto__是相等的 ·prototype和__proto__的類型是Object,而Object本身也有prototype和__proto__屬性,Object的__proto__屬性等于Function對象的prototype(前面說過),Object對象的prototype屬性中有很多內(nèi)置的方法:
- constructor: Object()
- hasOwnProperty: hasOwnProperty()
- isPrototypeOf: isPrototypeOf()
- toString: toString()
- valueOf: valueOf()
Object對象的prototype屬性不是Object類型的,而且該屬性的__proto__屬性為null,它是原型鏈的終點(diǎn)。
恒成立(假設(shè)用戶定義了一個函數(shù)函數(shù),名為Func):
Func instanceof Function // 因?yàn)镕unc.__proto__ == Function.prototype
Func instanceof Object // 因?yàn)镕unc.__proto__.__proto__ == Object.prototype
Function instanceof Function // 因?yàn)镕unction.__proto__ == Function.prototype
Object instanceof Function // 因?yàn)镺bject.__proto__ == Function.prototype
Function instanceof Object // 因?yàn)镕unction.__proto__.__proto__ == Object.prototype
Object instanceof Object // 因?yàn)镺bject.__proto__.__proto__ == Object.prototype
instanceof探幽:
L instanceof R當(dāng)且僅當(dāng)
L.__proto__......__proto__ === R.prototype
至少有一個__proto__
函數(shù)執(zhí)行上下文:
函數(shù)(或全局代碼)執(zhí)行前,會初始化上下文,包括:
- 確定this
- 變量提升:var定義的變量會在同級代碼執(zhí)行前先初始化為undefined
- 函數(shù)提升:函數(shù)定義會在同級代碼執(zhí)行前先初始化
- 變量提升先于函數(shù)提升
例:
function foo(){
console.log(c) // undefined
var c = 1;
}
注:如果沒有定義變量,就直接使用,會在作用域鏈上查找,而不是在自身作用域上創(chuàng)建。 例1(以下是全局代碼):
function foo(){
username = 'zhangshan';
}
會設(shè)置window.username為'zhangshan',與函數(shù)中的this是誰無任何關(guān)系
例2:
function foo(){
this.username = 'zhangshan';
}
直接調(diào)用foo()時,效果同上(直接調(diào)用某個函數(shù)時,調(diào)用者一定是windows)
閉包:
js支持函數(shù)的嵌套定義,內(nèi)部的函數(shù)叫子函數(shù),外部的函數(shù)叫父函數(shù)。 當(dāng)子函數(shù)引用了父函數(shù)中的變量,就會在子函數(shù)中產(chǎn)生一個閉包,包含了被引用的變量。 來看這個例子:
function foo(){
var msg="hello";
return function(){
return msg + " world";
}
}
var a = foo();
console.log(a()); // a能否正確使用msg?
foo()執(zhí)行完后,變量msg應(yīng)該被釋放,但是子函數(shù)引用了msg,產(chǎn)生了閉包,所以msg的生命周期變長,不會被釋放,所以執(zhí)行a()可以正確輸出msg的值。 產(chǎn)生閉包需要同時滿足: 1.存在函數(shù)嵌套 2.子函數(shù)中使用了父函數(shù)的變量 3.調(diào)用父函數(shù)
事件輪詢:
js是單線程的。 定時器回調(diào),DOM事件回調(diào),Ajax回調(diào)都會放在回調(diào)隊列中,待程序順序執(zhí)行完畢時,才會執(zhí)行。 注:并不是回調(diào)都是異步任務(wù),比如Promise()的參數(shù)function會同步執(zhí)行
Object對象:
Object.create(obj,[property]) //使用指定對象作為__proto__產(chǎn)生一個新對象。
Object.defineProperty(obj,propname,conf) // 給obj定義屬性propname,conf為配置項(xiàng)。 // 該函數(shù)可以監(jiān)視某個對象的改變,這是很多MVVM框架實(shí)現(xiàn)數(shù)據(jù)綁定的原理
Object.assign(target,source); // 復(fù)制source的所有屬性到target并返回
詳詢:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
Function對象:
Function.property.call(obj,param); Function.property.apply(obj,[params]); Function.property.bind(obj,param);
//均是 給函數(shù)指定this,其中bind不會執(zhí)行,而是返回該函數(shù)。
new探幽:
使用某個構(gòu)造函數(shù)new一個對象A實(shí)際上就是設(shè)置對象A的__proto__為構(gòu)造函數(shù)的prototype,然后將this設(shè)置為A來執(zhí)行構(gòu)造函數(shù)。 手動實(shí)現(xiàn)new的方式:
function NEW(f){ // f為構(gòu)造函數(shù)
var obj = Object.create(f.prototype);
f.call(obj);
return obj;
}
函數(shù)對象賦值注意:
var $ = document.querySelector;
$(...) // Illegal invocation
原因: document.querySelector()的this是document而$()的this是不確定的. 解決:var $ = document.querySelector.bind(document);
與或運(yùn)算符、相等性:
如果某個變量(或表達(dá)式的結(jié)果)的值為undefined,null,'',0,false,則為假值,非上述值則為真值 即js的假值有多種,但!假值都是true,同理真值有無數(shù)種,但!真值都是false 空對象{}和空數(shù)組[]為真值
js的與或運(yùn)算(&&,||)并不產(chǎn)生true或false,而是: 在處理或運(yùn)算時,返回第一個為真的值,若全為假,則返回最后一個假值 在處理與運(yùn)算時,返回第一個為假的值,若全為真,則返回最后一個真值 在處理非運(yùn)算時,一定返回true或false
關(guān)于相等性的研究請參考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness
例: var obj = createSomething() || {};// 若createSomething()返回假值,則將obj初始化為{}
例(將雙等==改成全等===的結(jié)果也是一樣的):
[undefined] == [undefined] // false,實(shí)際上無論數(shù)組里面是什么,該表達(dá)式始終返回false
undefined == false // false
undefined || false // false
!undefined == true // true
undefined && false // undefined
false && undefined // false
undefined || null // null
'11.000' == 11 // true
ES6:
let關(guān)鍵字:
和var一樣,定義變量,區(qū)別是: 1.支持塊級作用域 2.不能變量提升
const關(guān)鍵字:
定義常量,不能修改
解構(gòu)賦值:(假定obj為 {name:'zhangshan',age:20})
例1:
let {name,age} = {'zhangshan',15} // 創(chuàng)建name,age兩個對象并依次賦值
let {name,age} = obj // 創(chuàng)建name,age兩個變量,并按obj中的字段名賦值
let [a,b,c] = [1,2,3] // 創(chuàng)建a,b,c三個變量,按索引號賦值
例2:
function foo({name,age}){....} // 同第二個,按字段名賦值
foo(obj)
字串模板:
使用``包含,并使用${name}標(biāo)記變量,自動拼接。
var str = `我叫${obj.name},今年${obj.age}歲`;
對象內(nèi)的屬性和方法可以簡略:
let obj = {
name, // 直接將外部作用于的name賦給它,下同
age,
setName(name){ // 相當(dāng)于function setName(name){}
this.name = name
}
}
數(shù)組/對象の賦值(使用...):
let a1 = ['a','b','c'];
let a2 = [...a1];
let a3 = [...a2,...a1];
let o1 = {a:123,b:456};
let o2 = {...o1}
可變參數(shù)(rest):
function foo(...value); // value會變成參數(shù)數(shù)組
function foo(arg1,...value); // value會變成除arg外的參數(shù)數(shù)組
...運(yùn)算符:
...expression // 如果...后接一個可迭代對象,則此語句的作用是將該對象的所有可迭代屬性變成當(dāng)前對象內(nèi)的屬性
例:
如果func()函數(shù)返回一個可迭代對象,則上述語句表示將func()返回的對象中的所有屬性變成obj的
默認(rèn)參數(shù):
function point(x = 0,y = 0){
};
箭頭函數(shù)(lambda):
let foo = (params)=>{
statment;
}
foo(123); 注:lambda表達(dá)式中的this為它所在作用域中的this,且不能用call()更改,而一般函數(shù)的this需要在運(yùn)行時確定. 當(dāng)只有一個參數(shù)和一行語句時可簡略:param => expression;
雙箭頭:
let bar = param1 =>param2 => { statment;}
表示外層的箭頭函數(shù)的返回值是一個函數(shù)對象,也就是內(nèi)層的箭頭函數(shù) 即執(zhí)行bar()會得到內(nèi)層的函數(shù)對象
iterator和for...of:
for...of語句可以遍歷實(shí)現(xiàn)了Iterator接口的對象(可迭代對象)。 例:
let arr = [2,3,4,5,5,6];
for(let e of arr){
// using e;
}
數(shù)組,偽數(shù)組(類數(shù)組),set,map實(shí)現(xiàn)了Iterator接口,Object沒有實(shí)現(xiàn)該接口,但可以手動實(shí)現(xiàn)。 手動實(shí)現(xiàn)Iterator的方式:需要實(shí)現(xiàn)next方法,該方法返回此格式的對象{value:dataType,done:boolean},value是元素的值,done表示是否是最后一個元素
let it = Symbol.iterator;
Object.prototype[it] = function (){
let next = ()=>{
return {value:....,done:....}
}
return {next};
}
注:使用for...in也可以迭代Object對象,使用Object.keys(obj)可獲取對象的key數(shù)組
promise:
是一種異步操作的解決方案,假設(shè)op1()和op2()是異步操作(回調(diào)函數(shù)),op2()需要依賴op1()先執(zhí)行。則op1和op2不能順序執(zhí)行,op2應(yīng)該位于op1的函數(shù)體中,如下例:
setTimeout(function op1(){
// do something...
setTimeout(function op2(){
// do something...
},2000);
},2000);
如果回調(diào)層數(shù)過多,則會給編程帶來很大麻煩。使用promise解決方法如下:
// 定時器1的業(yè)務(wù)代碼
function func1(){
console.log('func1 do something');
}
// 定時器2的業(yè)務(wù)代碼
function func2(){
console.log('func2 do something');
}
function timeoutTask(timeoutFunc,delay){
// 返回一個Promise對象,其初始化參數(shù)為一執(zhí)行體(函數(shù)),倆參數(shù)分別表示執(zhí)行成功和失敗
return new Promise((success,error)=>{
setTimeout(function (){
timeoutFunc();
success(); // 執(zhí)行成功
},delay);
})
}
// then方法接收兩個執(zhí)行體,分別對應(yīng)上一步執(zhí)行成功和失敗的回調(diào),then方法可以鏈?zhǔn)秸{(diào)用
timeoutTask(func1,2000).then(()=>timeoutTask(func2,2000),null);
async和await關(guān)鍵字:
是最常用異步操作的解決方案, async是配合promise使用的。 await后可以跟一個promise對象,只有promise對象resolve了,此表達(dá)式才會向下執(zhí)行 實(shí)例:Ajax異步獲取用戶個人信息,和用戶的文件列表,而且獲取文件列表的前提是已獲取用戶信息。
(async function (){ // 使用async修飾函數(shù)
let user = await getUser(123); // 只有await關(guān)鍵字后的Promise對象為resolve狀態(tài),才會向下執(zhí)行,await表達(dá)式會返回resolve()的參數(shù)(即promiseValue)
let files = await getFiles(user);
// use files data...
})(); // 若不手動返回promise對象,async函數(shù)會強(qiáng)制返回一個promise對象,原本的返回值會作為promiseValue
await只能用在async塊中。
class關(guān)鍵字:
定義類
class Foo{
static msg = "Foo class"; // 靜態(tài)屬性
static getMsg = () => msg; // 靜態(tài)方法
constructor(){ // 構(gòu)造函數(shù)
this.name = 'foo';
}
setName(name){ // 普通函數(shù)
this.name = name
}
}
在類定義中的普通函數(shù)會自動原型化,再也不用手動操作原型了;靜態(tài)屬性相當(dāng)于直接在類對象(非實(shí)例對象)本身添加
const foo = new Foo();
foo.setName('bar'); // ok
Foo.setName('bar'); // Foo.setName is not a function
Foo.msg = 'abc class'; // ok
foo.getMsg(); // foo.getMsg is not a function
extends繼承:
class Bar extends Foo {
}
機(jī)制幾乎和Java一模一樣; 支持super();
淺復(fù)制和深復(fù)制:
淺復(fù)制:一層復(fù)制,復(fù)制單層元素的值 深復(fù)制:多層遞歸復(fù)制
注:只有進(jìn)行了成員復(fù)制才能算拷貝,一般的對象間賦值只是指針的傳遞,根本不算拷貝。 例:
let a = [1,{name:"zhangshan"}];
let b = a.concat(); // concat是淺復(fù)制
b[0] = 2;
b[1].name:"lishi";
console.log(a); // [1, {name: "lishi"}]
注:concat是淺復(fù)制,分別復(fù)制每一個元素的值,對于值類型的元素,復(fù)制其值,對于對象,復(fù)制其地址。 深復(fù)制的實(shí)現(xiàn):
function deepCopy(data){
let ret;
if(data instanceof Array){
ret = [];
} else if(data instanceof Object){
ret = {};
} else {
return data;
}
for(let i in data){ // i為key或索引,如果是for...of,則i為值
ret[i] = deepCopy(data[i]);
}
return ret;
}
使用JSON也可實(shí)現(xiàn)深復(fù)制
|