JavaScript 平時(shí)記錄
1. 數(shù)組所有元素的所有組合
var context = 'a,b,c,d'; var contexts = context.split(','); //這個(gè)for循環(huán)沒有body, a.push()方法返回的是push后a的長(zhǎng)度 for (var a = []; a.push([]) < contexts.length;); // b的值是所有元素可能的組合情況數(shù),如3個(gè)元素共7中組合 var b = Math.pow(2, contexts.length) - 1; for (var i = 1; i <= b; i++) { var c = []; for (var s = i, k = 0; s > 0; s >>= 1, k++) { /** * 找出當(dāng)前這種組合的序號(hào),如i=5時(shí),二進(jìn)制101,找出兩個(gè)1所在的序號(hào)0,2; * 左移:所有位數(shù)往左移,(左邊)移出位被丟棄,右邊的空位一律補(bǔ)0,如10左移2位:1000; * 右移:所有位數(shù)往右移,(右邊)移出位被丟棄,左邊空位補(bǔ)0或補(bǔ)符號(hào)位: * MSDN中明確說明,右移對(duì)于無符號(hào)類型左邊空位強(qiáng)制補(bǔ)零,對(duì)于有符號(hào)類型左邊空位強(qiáng)制補(bǔ)符號(hào)位。 **/ if (s & 1 == 1) { c.push(contexts[k]); } } a[c.length - 1].push(c.join("")); } console.log(a);
1,JS中的this
見下面例子,注意函數(shù)中的函數(shù) 中的this指的是window對(duì)象了!!!
document.addEventListener('click', function (e) {
console.log(this);//this->document,添加在誰(shuí)上的事件this就是指的誰(shuí)
(function () {
console.log(this);//this->window
})();
});
var o = {
a : function () {
console.log(this);//this->o,this指代對(duì)象o
var b = function () {
console.log(this);//this->window
}()
}
};
o.a();//o['a']()
2,定時(shí)器函數(shù) setTimeout() 函數(shù)說明 (JavaScript單線程相關(guān))
語(yǔ)法:
var timeoutID = scope.setTimeout(function[, delay, param1, param2,....]);
var timeoutID = scope.setTimeout(function[, delay]);
var timeoutID = scope.setTimeout(code[, delay]);
參數(shù)說明:
function:function是你想要在delay毫秒之后執(zhí)行的 回調(diào)函數(shù)。
code:這是一個(gè)替代語(yǔ)法,你可以使用字符串代替function,在delay毫秒之后執(zhí)行字符串 (使用該語(yǔ)法是不推薦的, 原因和使用eval()一樣,有安全風(fēng)險(xiǎn))。
delay: 可選延遲的毫秒數(shù) (一秒等于1000毫秒),函數(shù)的調(diào)用會(huì)在該延遲之后發(fā)生。如果省略該參數(shù),delay取默認(rèn)值0。實(shí)際的延遲時(shí)間可能會(huì)比 delay 值長(zhǎng),原因請(qǐng)查看Reasons for delays longer than specified。param1, ..., paramN可選附加參數(shù),一旦定時(shí)器到期,它們會(huì)作為參數(shù)傳遞給function或 執(zhí)行字符串(setTimeout參數(shù)中的code)
例子:
這個(gè)函數(shù)有兩種用法,第一個(gè)參數(shù)可以是一個(gè)函數(shù)名稱,也可以是字符串形式的代碼。見下面兩個(gè)例子:
setTimeout("location.reload()", 5000)//5秒之后執(zhí)行代碼, 刷新頁(yè)面
setTimeout(reload, 4000); //4秒之后執(zhí)行reload函數(shù)
如果這么寫:setTimeout(location.reload(), 5000);效果是這樣的:頁(yè)面一直不停刷新,不會(huì)等5秒之后才刷新。原因是:沒有用字符串形式的第一個(gè)參數(shù)實(shí)際上就是立即執(zhí)行此代碼,即刷新頁(yè)面,刷新頁(yè)面后,又重新執(zhí)行setTimeout()這個(gè)函數(shù),而這個(gè)函數(shù)又一次立即執(zhí)行l(wèi)ocation.reload(),如此循環(huán)....如果需要傳參,則第一個(gè)參數(shù)需要使用匿名函數(shù)形式
深度解析JavaScript中的settimeout()和setInterval()函數(shù):
https://blog.csdn.net/chiuwingyan/article/details/80322289
http://www.rzrgm.cn/xiaohuochai/p/5773183.html
小結(jié)一下:setTimeout()比setInterval()穩(wěn)定,一般不使用setInterval()而是使用鏈?zhǔn)秸{(diào)用setTimeout()模擬setInterval()。原因是JavaScript引擎是單線程的,主要分為主線程和事件隊(duì)列。同步操作是在主線程上執(zhí)行的,異步操作一般是首先放在事件隊(duì)列中,等JavaScript主線程空閑了才會(huì)去事件隊(duì)列中取出代碼放入主線程中去執(zhí)行。定時(shí)器函數(shù)屬于異步事件,參數(shù)里設(shè)置的時(shí)間并不是延遲多少秒去執(zhí)行回調(diào)函數(shù),這個(gè)時(shí)間代表的是延遲多少秒把回調(diào)函數(shù)放入到異步事件隊(duì)列中,等到主線程空閑再被執(zhí)行。這意味著至少要等這么多時(shí)間后才會(huì)執(zhí)行回調(diào)函數(shù)。
一個(gè)例子:下面的代碼會(huì)輸出什么結(jié)果?
for (var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 100 * i); } 結(jié)果是打印出10個(gè)10!解釋如下:setTimeout在若干毫秒后執(zhí)行一個(gè)函數(shù)并且是在for循環(huán)結(jié)束后。for循環(huán)結(jié)束后,i的值為10.所以當(dāng)函數(shù)被調(diào)用的時(shí)候,它會(huì)打印出10! 如果想打印出1~9,有兩個(gè)方法,1,將var變成let關(guān)鍵詞(ES6才開始支持)或者 2,使用立即執(zhí)行函數(shù)捕捉每次循環(huán)的i的值。代碼如下: for (var i = 0; i < 10; i++) { (function(j){ setTimeout(function () { console.log(j); }, j * 10); })(i); }
setInterval()函數(shù)的問題:假如設(shè)置了一個(gè)每隔100ms執(zhí)行一次的定時(shí)器,第一次執(zhí)行到該定時(shí)器時(shí),會(huì)在100ms之后將回調(diào)函數(shù)加入到事件隊(duì)列中,再過100ms又會(huì)將這個(gè)回調(diào)函數(shù)加入到事件隊(duì)列中,而如果主線程在此期間一直沒有空閑,那么事件隊(duì)列中的回調(diào)函數(shù)就一直不會(huì)被拿到主線程中取執(zhí)行。可能出現(xiàn)的情況就是主線程空閑的時(shí)候會(huì)一次性將這些回調(diào)函數(shù)同時(shí)執(zhí)行而沒有任何時(shí)間間隔。JavaScript引擎對(duì)此的處理辦法是:當(dāng)使用setInterval()定時(shí)器時(shí),只有當(dāng)事件隊(duì)列中沒有該定時(shí)器的任何實(shí)例時(shí),才會(huì)將定時(shí)器中的回調(diào)函數(shù)加入到事件隊(duì)列中。 這確保了最小的時(shí)間間隔,但是引發(fā)的另一個(gè)問題是可能 有些間隔 被跳過了。如果功能需求是每個(gè)定時(shí)器函數(shù)都必須執(zhí)行,那么就不能滿足需求了。所以一般都使用遞歸調(diào)用settimeout()定時(shí)器模擬setInterval()的效果。不會(huì)出現(xiàn)上面的兩個(gè)問題。
3, html標(biāo)簽里寫事件 傳 值
<select name="type" onchange="show_sub(this.options[this.options.selectedIndex].value)">
<option value="0">請(qǐng)選擇主菜名</option>
<option value="1">白菜</option>
<option value="2">蘿卜</option>
</select>
js代碼比較簡(jiǎn)單
<script>
function show_sub(v){
alert(v);
}
</script>
最重要的知識(shí)點(diǎn)是獲在select onchange時(shí)獲取option的value值: this.options[this.options.selectedIndex].value
4,JS中的"0" 是true還是false
if ('0') alert("'0' is true");if ('0' == false) alert("'0' is false");結(jié)果是,兩次都 alert 了!那么 '0' 到底是 true 還是 false 呢?
答案是:在js做比較的時(shí)候,有這樣的三條規(guī)則:
- 如果比較的兩者中有boolean,會(huì)把 boolean 先轉(zhuǎn)換為對(duì)應(yīng)的 number,即 0 和 1(false是0,1是true)
- 如果比較的雙方中有一方為number一方為string,會(huì)把string轉(zhuǎn)換為數(shù)字
- 把string直接轉(zhuǎn)換為boolean的時(shí)候,空字符串‘’轉(zhuǎn)換為 false,除此外的一切字符串轉(zhuǎn)換為 true
5,瀏覽器兼容的enter事件
<input type="text" id="text"> <script> document.getElementById("text").onkeypress = function(e) { e = e || window.event; key = e.keyCode || e.which || e.charCode; alert("按鍵碼: " + key + " 字符: " + String.fromCharCode(key));
if (key == 13) {enter事件} };
6,JavaScript立即執(zhí)行某個(gè)函數(shù) 深度思考 https://www.tangshuang.net/2020.html
幾種方式立即執(zhí)行函數(shù) 在javascript中定義一個(gè)函數(shù),并且立即去執(zhí)行它。(這個(gè)情況雖然看上去很瘋狂,但是實(shí)際上一定會(huì)用到,因?yàn)楹瘮?shù)一旦執(zhí)行完,內(nèi)部的局部變量會(huì)被釋放,內(nèi)存也釋放出來。)我們可能第一種想到的方法是: // 第一種 function a() {} a(); 沒錯(cuò),這個(gè)太簡(jiǎn)單不過了。 當(dāng)然,還有另外一種相對(duì)高深的辦法: window.onload = function() {} 這段代碼表示在網(wǎng)頁(yè)加載完之后立即執(zhí)行function中的代碼,但這里面隱含了另外一層意思,也就是可以把函數(shù)賦值給變量,使變量成為一個(gè)其他語(yǔ)言意義上的類。 // 第二種 var a = function(){}a(); 不過這也給了我們另外一個(gè)思路: function fun() {} var a = fun(); a(); 給我們留下一個(gè)思考: function(){}; // javascript語(yǔ)句中以function開始沒有實(shí)際的效果 一旦某條語(yǔ)句以function開始,這條語(yǔ)句沒辦法賦值給某個(gè)變量去執(zhí)行它(說到這里,函數(shù)名可以可以理解為一個(gè)被賦值為某個(gè)函數(shù)的變量而已)。 下面是真相的時(shí)候: function a() {} a(); 如果函數(shù)名是一個(gè)被賦值的變量(也就是a),那么為何不將其實(shí)際的值替換掉變量名呢(也就是把a(bǔ)()替換為function()())?于是,上面這段代碼變?yōu)椋? function(){}(); // 前面加粗部分代表a 但是在前面已經(jīng)提到了,function開始的語(yǔ)句沒有實(shí)際的效果,因此,上面這個(gè)語(yǔ)句不會(huì)有實(shí)際效果。不僅如此,這句代碼還會(huì)拋出錯(cuò)誤提示:SyntaxError: Unexpected token。 此處括號(hào)的正確理解 造成上述這個(gè)異常的原因是,javascript對(duì)語(yǔ)句的結(jié)束并不是以;作為標(biāo)識(shí),在這種普通情況下,}被作為語(yǔ)句結(jié)束的標(biāo)識(shí),因此,上述語(yǔ)句被解釋為: function(){};(); 因此在執(zhí)行()時(shí),會(huì)拋出表達(dá)式錯(cuò)誤。而如果我們執(zhí)行: function(){};(1); 則不會(huì)出錯(cuò)。原因在于:語(yǔ)法正確。 我理解的(),在javascript中有兩種:一種是確定優(yōu)先級(jí),另一種是分組。當(dāng)然,在聲明函數(shù)和函數(shù)使用的時(shí)候也會(huì)用到(),但這是一種語(yǔ)法,而不是運(yùn)算。確定優(yōu)先級(jí)就是括號(hào)內(nèi)的表達(dá)式先于括號(hào)外的表達(dá)式運(yùn)算,例如: 1+(2*5)和(1+2)*5或(1+2)*(2+3) 而分組一般是在正則表達(dá)式中使用的概念,例如: /<(.*)ok(this) is myhouse(.*)>/ 在進(jìn)行匹配的時(shí)候,上面的小括號(hào)將匹配結(jié)果分為三組進(jìn)行返回,在替換的時(shí)候,可以對(duì)每個(gè)組分別進(jìn)行替換。因此,分組的概念,應(yīng)該和本文沒有關(guān)系。因此,本文中的(),只有兩種理解,一種是運(yùn)算符,一種是語(yǔ)法。 在上面的代碼中(1);中的();很明顯是一個(gè)運(yùn)算符,括號(hào)內(nèi)必須有表達(dá)式,否則就是語(yǔ)法錯(cuò)誤。 我們?cè)诨氐缴厦娴拇a,如果我們給function加上()會(huì)怎樣? (function(){}); 恭喜你,你的函數(shù)初始化,雖然從結(jié)果上并沒有什么卵用,而且和直接function(){}也沒有什么不同,只不過是把function(){}提高了運(yùn)算的優(yōu)先級(jí)而已。 可是,當(dāng)我們執(zhí)行下面的代碼的時(shí)候,情況就大不相同了: (function(){})(); 代碼是從左往右執(zhí)行的,就像a() || b();一樣如果a()為真,就不執(zhí)行b()了。同樣的道理,上面的代碼中,紅色部分作為一個(gè)表達(dá)式,執(zhí)行完畢,代表著一個(gè)函數(shù)已經(jīng)初始化完畢,如果我們回到:function(){}();,也就是前文拋出錯(cuò)誤的那個(gè)語(yǔ)句你就會(huì)發(fā)現(xiàn),神奇的事情發(fā)生了,紅色部分儼然就是我們要的a,所以整個(gè)語(yǔ)句合起來也就是:a();,就這樣,函數(shù)被執(zhí)行了。 在這條代碼中,第二個(gè)()不再是運(yùn)算符,而是函數(shù)的括號(hào)。而第一個(gè)(),則是一個(gè)運(yùn)算符,提高了內(nèi)部function的運(yùn)算優(yōu)先級(jí),內(nèi)部被優(yōu)先執(zhí)行,得到結(jié)果后,與第二個(gè)()構(gòu)成函數(shù)語(yǔ)法,執(zhí)行了函數(shù)。 我們?cè)倩仡^來看()運(yùn)算符的作用,來看一下下面這個(gè)代碼: ()(); 這是一個(gè)神奇的代碼,世界上不會(huì)有任何程序員這樣去用,當(dāng)然,它也會(huì)報(bào)錯(cuò)。但是我們?nèi)绾握_去理解這種情況呢?世界上是否存在下面這種javascript代碼: (a+b)(c+d); 從來沒有見過。如果世界上存在一種運(yùn)算,就是沒有任何運(yùn)算,那么上面是成立的,但是,如果這種假設(shè)不成立的話,上面的代碼就是錯(cuò)誤的。我們從來沒有見過(1+2)(3+4),雖然我們小學(xué)的時(shí)候?qū)戇^這樣的算式,但是在代碼中是不存在的。 因此,我們換一個(gè)思維,不要只把它當(dāng)做運(yùn)算,而是運(yùn)算和函數(shù)的結(jié)合呢?在你的瀏覽器中運(yùn)行下面這段代碼試試: (1+2)(3+4);// TypeError: (1 + 2) is not a function 提示的不是語(yǔ)法錯(cuò)誤,而是數(shù)據(jù)類型錯(cuò)誤,第二個(gè)括號(hào) 前面的不是一個(gè)函數(shù)。也就是說,第二個(gè)括號(hào)前面的,如果是函數(shù)類型,就正確了!那么世界上有沒有一種算法,使運(yùn)算后返回值為函數(shù)呢?比如 fun1+fun2=fun3?好像我還從來沒有遇到過,因此,想在第一個(gè)括號(hào)中構(gòu)建一種運(yùn)算使該代碼成立,還需要高高手來實(shí)現(xiàn)。唯一的解決辦法,就是在 第一個(gè)括號(hào)中委以函數(shù),也就是(function(){})(3+4),而3+4不過僅僅是作為前面這個(gè)函數(shù)的參數(shù)予以運(yùn)行。 匿名函數(shù)的立即執(zhí)行 當(dāng)你以為挖到寶藏的時(shí)候,下面的解釋或許讓你再一次開了腦洞。我們提到function開頭的語(yǔ)句雖然初始化函數(shù),但是函數(shù)并不被執(zhí)行,其運(yùn)行效果相當(dāng)于什么也沒發(fā)生。 為了提交它的優(yōu)先級(jí),我們?cè)儆靡淮?)吧: (function(){}()); 這次,我們直接把函數(shù)表達(dá)式和后面的()放在一個(gè)()里面,這下子奇跡也發(fā)生了,空號(hào)內(nèi)部是一個(gè)表達(dá)式,表達(dá)式的意思就是}不代表結(jié)束,所以我們前文提到的}表示語(yǔ)句結(jié)束的論斷不起作用了。()內(nèi)部必須運(yùn)算完成,才能結(jié)束這次表達(dá)式運(yùn)算,所以上面代碼中的紅色部分又再次先運(yùn)算了,運(yùn)算完又和()組成了a(),于是,函數(shù)又執(zhí)行了。 OK,我們現(xiàn)在終于get到了終點(diǎn):表達(dá)式必須運(yùn)行完成,才會(huì)結(jié)束表達(dá)式。這簡(jiǎn)直就是天一樣的玄機(jī),牢牢記住表達(dá)式這個(gè)概念之后,我們?cè)賮砜聪旅娴膸讉€(gè)代碼: !function(){}(); +function(){}(); -function(){}(); ~function(){}(); …… 沒錯(cuò),上面的!+-~,全部代表表達(dá)式,!表示非,~表示按位非。你可以想出全部的表達(dá)式符號(hào)(當(dāng)然必須得考慮運(yùn)行是否合法,比如/0就不合法,分母不能為0),從而實(shí)現(xiàn)上面的這個(gè)效果。 于是,我們看到幾乎所有的插件,都會(huì)用上面的其中一種方式來定義整個(gè)代碼。 正是因?yàn)檫@個(gè)原因,上面的所有代碼,都可以讓function(){}內(nèi)部的代碼立即執(zhí)行。 遺留問題:第二個(gè)括號(hào)內(nèi)的參數(shù) 在多數(shù)插件中,我們可以看到如下的代碼: !function(){}(jQuery); 基本上我們都看懂了,但是第二個(gè)括號(hào)內(nèi)有個(gè)jQuery代表什么意思呢? 你想一下下面這個(gè)用法: function a(var) {} a(1); 然后把第二行的a替換為function(var){},結(jié)果就變成了function(var){}(1); 沒錯(cuò),第二個(gè)括號(hào)內(nèi)的值,是原本函數(shù)的特定參數(shù)。所以,上面那個(gè)jQuery的,我們可以將它還原為: var fun = function(a) {} fun(jQuery); 就是這樣了。但是,jQuery是什么呢?是一個(gè)對(duì)象啊!所以下面的代碼就來了: !function($){ // 在function中,$實(shí)際上就是jQuery,所以用$盡情玩耍吧。 }(jQuery); 難道你以為到此就結(jié)束了嗎?不,看看下面的代碼: !function(fun){}(function($){}); 什么鬼?你以為我想表達(dá)什么?其實(shí),這是很多插件中的一種寫法,用以兼容不同的加載模式(CommonJS、CMD、CMD),具體是這樣的: !function(fun){ "use strict"; if(typeof define === 'function' && define.amd) { define(['jquery'], fun) } else { fun((typeof(jQuery) != 'undefined') ? jQuery : window.Zepto) } }(function($){ "use strict"; // 真正的插件代碼都在這里 }); 這是一個(gè)雙重傳值的過程。第一重,第一個(gè)function(fun)中的fun是第二個(gè)function($),因此,在第一個(gè)function中的代碼中fun($)和第二個(gè)function($)是等效的。第二重,第二個(gè)function($)中的$參數(shù),是在第一個(gè)函數(shù)中進(jìn)行傳遞過來的,第一個(gè)函數(shù)中,define(['jquery'],fun)和fun(jQeury)實(shí)際上在執(zhí)行第二個(gè)函數(shù),既然如此,真正的插件代碼就應(yīng)該在第二個(gè)函數(shù)中去寫,第一個(gè)函數(shù)僅僅是通過多個(gè)判斷,返回正確的調(diào)用模式而已。 實(shí)際上,了解了上述之后,本文的題目是為了立即執(zhí)行某個(gè)函數(shù),在實(shí)踐中,還有很多做法可以在申請(qǐng)一個(gè)函數(shù)后立即執(zhí)行它,比如: (function(){}).call(); 好了,這個(gè)問題就闡述到這里,可能也有一些不足的地方,歡迎大家指正。
7, JavaScript中的數(shù)組或?qū)ο?循環(huán)方法總結(jié)
1, 普通for循環(huán) [數(shù)組,對(duì)象] //注意,將長(zhǎng)度賦給一個(gè)變量,防止每次循環(huán)都要算一下長(zhǎng)度。for (var i=0, len=arr.length; i < len; i++){}
2, for in 【數(shù)組,對(duì)象】//注意 for (var i in arr){} 中的i類型始終是string類型的,有時(shí)候需要int類型時(shí)要注意。
3, array.forEach(function(value, index){})【數(shù)組】// ES5推出的數(shù)組自帶的循環(huán),主要功能是遍歷數(shù)組,實(shí)際性能比f(wàn)or 還弱。forEach這種方法也有一個(gè)小缺陷:你不能使用break語(yǔ)句中斷循環(huán),也不能使用return語(yǔ)句返回到外層函數(shù)
4,array.map(functino(value, index){})【數(shù)組】//也是ES5推出的,支持return 語(yǔ)句
5,for ... of 【數(shù)組】//ES6新增功能
6,jQuery的靜態(tài)方法$.each(array/obj, function(index, value){})
7, underScoreJS中的方法:_.each(array/obj, function(index, value){})
8, 關(guān)于 jQuery的 tmpl 模板插件的說明
var html = $("#menu_tmpl").tmpl({data:retval.data}).outerHTML();
$("#phpNav").html(html);
使用tmpl()方法時(shí),一定要用對(duì)象模式,不容易出問題! (本身這里的參數(shù)只能是對(duì)象格式,而不能是數(shù)組)
5
5
5
5
5
5
5
5
posted on 2017-09-27 11:04 everest33 閱讀(350) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)