摘要:序列化為字符串之后它的各個屬性已經(jīng)被解除了引用,重新相當于創(chuàng)建了一個新的對象。類似于的,的命令行終端。基本思路函數(shù)的使用以及協(xié)議。
多行注釋的陷阱
由于正則表達式字面量的存在,多行注釋可能會產(chǎn)生陷阱,例如以下程序?qū)伋鲥e誤:
/* var a = /h*/.test("hello"); */
正則結(jié)束前的那個星號將被解析為注釋結(jié)束符,從而.被認為是不合法的.所以盡量避免使用多行注釋
整型js采用IEEE754標準表示數(shù)字,整型也是按照64位浮點數(shù)進行處理的,也就意味著2===2.0,這種設(shè)計的一個優(yōu)點是避免了整型的溢出.JavaScript中精確的整型的范圍是(-2^53,2^53),ES6中的2個常量:Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER。
Math.pow(2,53) +1 === Math.pow(2,53) // true遍歷對象的屬性
for-in循環(huán)可以枚舉對象以及它原型上的屬性,我們可以通過hasOwnProperty()進行過濾,例如:
for(var key in obj){ // 以下的過濾還可以使用typeof obj[key] !== "function" if(obj.hasOwnProperty(key)){ console.log(key,"=>",obj[key]); } }函數(shù)
帶有緩存的函數(shù)在js中函數(shù)就是對象,對象是"名/值"對的集合并擁有一個連接到原型對象的隱藏連接.對象字面量產(chǎn)生的對象連接到Object.prototype.函數(shù)對象連接到Function.prototype(該原型對象本身連接到Object.prototype).每個函數(shù)在創(chuàng)建時附有2個附加的隱藏屬性:函數(shù)的上下文和實現(xiàn)函數(shù)行為的代碼.
因為函數(shù)是對象,所以它們可以像其他任何值一樣被使用.函數(shù)可以存放在變量,對象和數(shù)組中,函數(shù)可以被當做參數(shù)傳遞給其他函數(shù),函數(shù)也可以再返回函數(shù),函數(shù)也可以擁有方法.函數(shù)與普通對象的不同之處僅僅在于它可以被調(diào)用.
函數(shù)可以使用對象緩存之前的計算結(jié)果從而減少不必要的計算,這是程序優(yōu)化的一種方式,例如,對于斐波那契數(shù)列我們可以這樣優(yōu)化:
var fibonacci = function(){ var memo = [0,1] var fib = function(n){ var result = memo[n] if(typeof result !== "number"){ result = fib(n - 1) + fib(n - 2) memo[n] = result } return result } return fib }()
我們可以將這種形式推廣到一般函數(shù):
var memoizer = function(memo,fundamental){ var shell = function(n){ var result = memo[n] if(typeof result !== "number"){ result = fundamental(shell,n) memo[n] = result } return result } return shell } var fib = memoizer([0,1],function(shell,n){ return shell(n-1) + shell(n-2) }) var fac = memoizer([1,1],function(shell,n){ return n * shell(n-1) })繼承
當一個函數(shù)對象被創(chuàng)建時,Function構(gòu)造器產(chǎn)生的函數(shù)對象會運行類似這樣的一些代碼:
this.prototype = {constructor:this};
新函數(shù)對象被賦予一個prototype屬性,其值是包含在一個constructor屬性并且屬性值為該函數(shù)的新對象.該prototype對象是存放繼承特征的地方.因為javascript語言沒有提供一種方法去確定哪個函數(shù)是打算用來做構(gòu)造器的,所以每個函數(shù)都會得到一個prototype對象(非常重要).
通過偽類的方式實現(xiàn)繼承本質(zhì)上來說就是子類的原型等于父類的實例,實例如下:
var SuperType = function(){ this.superValue = "supper value" } var SubType = function(){ this.subValue = "sub value" } SubType.prototype = new SuperType() var sub = new SubType() console.log(sub.subValue) // subvalue console.log(sub.superValue) // supervalue數(shù)組
javascript中并沒有真正的數(shù)組,數(shù)組本質(zhì)上也是對象
請看下面的例子:
var arr = [1,2,3,4,5,6] console.log(arr.length) // 6 arr.abc = false // 給數(shù)組增加屬性 console.log(arr) // [1, 2, 3, 4, 5, 6, abc: false] console.log(arr.length) // 6
由運行的結(jié)果可以看出給數(shù)組添加了一個abc屬性,盡管字面上的長度有所增加,但是數(shù)組的實際長度并沒有改變!
typeof [] // "object"
所以為了區(qū)分數(shù)組和對象我們應(yīng)該可以采用以下的函數(shù):
let isArray = value => !!value && typeof value === "object" && value.constructor === Array正則表達式 分組
觀察以下匹配url的正則表達式:
"use strict" let parse_url = /^(?:([A-Za-z]+):)?(/{0,3})([0-9.-A-Za-z]+)(?::(d+))?(?:/([^?#]*))?(?:?([^#]*))?(?:#(.*))?$/ let url = "http://www.ora.com:80/goods?q=1#fragment" let result = parse_url.exec(url) let names = ["url","schema","slash","host","port","path","query","hash"] for(let i = 0;i < names.length;i++){ console.log(names[i] + ":",result[i]) }
(?:([A-Za-z]+):)?這個因子匹配一個協(xié)議名,但僅當它之后跟隨一個冒號(:)的時候才匹配(?:...)表示一個非捕獲型分組(noncapturing group),通常用非捕獲分組來代替少量不優(yōu)美的捕獲型分組是很好的方法,因為捕獲會有性能上的缺失.后綴?表示這個分組是可選的.(...)表示一個捕獲型分組(capturing group).一個捕獲型分組將復(fù)制它所匹配的文本,并將其放入到result數(shù)組中.每個捕獲型分組都將被指定一個編號,第一個捕獲分組的編號是1,所以該分組所匹配的文本拷貝將出現(xiàn)在result[1]中;下一個因子(/{0,3})是捕獲分組2.
常用正則匹配數(shù)字
pattern_number = /^-?d+(?:.d*)?(?:e[+-]?d+)?$/i正則表達式轉(zhuǎn)義
1指向分組1所捕獲到的文本的一個引用,所以它能夠再次匹配,例如我們用下面的正則表達式來搜索文本中重復(fù)的單詞:
var doubled_words = /[A-Za-zu00c0-u1fffu2800-ufffd-]+s+1/gi正則表達式分組 捕獲型
一個被包圍在圓括號中的正則表達式選擇.任何匹配這個分組的字符將被捕獲.每個捕獲分組都被指定了一個數(shù)字,第一個捕獲(的是分組1,第二個捕獲(的是分組2
非捕獲型有一個(?:前綴,僅做簡單匹配,并不會捕獲所匹配文本,會有微弱的性能優(yōu)勢,不會干擾捕獲型分組的編號.
關(guān)于語言本身的一些探討 位運算由于javascript中所有數(shù)字都是浮點型,所以使用位運算會降低程序性能,因為需要將數(shù)字轉(zhuǎn)化為整型后執(zhí)行運算然后轉(zhuǎn)化回去.
巧妙使用位運算可以創(chuàng)造很多的奇淫技巧。例如以下的轉(zhuǎn)化為整數(shù)的代碼:
let parseInt = num => num | 0 // 還可以這樣 let parseInt = num => num >>> 0 // 甚至,我們可以這樣 let parseInt = num => ~~num
以上的parseInt實現(xiàn)可以傳入任意的數(shù)據(jù)類型,如果數(shù)據(jù)類型不匹配將會被轉(zhuǎn)化為0,避免了原生的parseInt中的NaN的問題,但是局限在于只能處理32位的整數(shù)。
JSON.stringify和JSON.parse的妙用我們可能見到這樣的函數(shù):
let f = uid => { let user = global.__user[uid] let game = global.__game[uid] let userInfo = JSON.parse(JSON.stringify(user)) let gameInfo = JSON.parse(JSON.stringify(game)) let ret = { user: userInfo, game: gameInfo } return ret }
思考上述的過程是不是存在重復(fù)?為什么要將一個對象變成字符串,然后再將字符串解析為對象?我們明明可以直接使用那個對象?其實let objs = JSON.parse(JSON.stringify(obj))執(zhí)行的是對象的深度克隆操作。序列化為字符串之后它的各個屬性已經(jīng)被解除了引用,重新JSON.parse相當于創(chuàng)建了一個新的對象。當然對象的克隆本身有很多方法,例如:lodash的_.clone
數(shù)組復(fù)制數(shù)組復(fù)制其實有很多方法:
var arr2 = arr1.concat(); var arr2 = arr1.filter(n => true); var arr2 = arr1.map(n => n);js實現(xiàn)node的REPL模式
一個簡易的JavaScript解釋器。類似于ruby的irb,Scala的命令行終端。
基本思路:eval函數(shù)的使用以及UDP協(xié)議。實現(xiàn)如下:
server.js
"use strict" const dgram = require("dgram") let udp = dgram.createSocket("udp4") const PORT = 8888 const ADDRESS = "127.0.0.1" udp .on("message",(data,rinfo) => { let cmd = data.toString().trim() console.log(`get cmd [${cmd}] from ${rinfo.address} : ${rinfo.port}`) let evalRes try { evalRes = new Buffer("=> " + JSON.stringify(eval(cmd)) + " javascript>") } catch (ex) { console.trace("udp 2>", ex.stack) evalRes = new Buffer(ex.stack) } udp.send(evalRes,0,evalRes.length,rinfo.port,rinfo.address) }) .on("error",err => { console.trace(err.stack) udp.close() }) .on("close",() => { process.exit() }) .on("listening",() => { let addr = udp.address() console.log(`command server listen on ${addr.address} : ${addr.port}`) }) .bind(PORT,ADDRESS)
client.js
"use strict" const dgram = require("dgram") let udp = dgram.createSocket("udp4") const stdin = process.stdin const PORT = 8888 const ADDRESS = "127.0.0.1" stdin.resume() stdin.setEncoding("utf-8") console.log("javascript>") udp.on("message",(msg,rinfo) => { try { msg = JSON.parse(msg.toString()) } catch (e) { msg = msg.toString() } console.log(msg) }) stdin.on("data",chunk => { let msg = new Buffer(chunk) udp.send(msg,0,msg.length,PORT,ADDRESS) })生成隨機字母數(shù)字字符串
function generateRandomAlphaNum(len) { var rdmString = ""; for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2)); return rdmString.substr(0, len); }
隨機背景色toString(36)表示10個阿拉伯數(shù)字和26個小寫英文字母
"#"+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6)在js中如何優(yōu)雅實現(xiàn)sleep
promise
function sleep(delay){ return function(){ return new Promise(function(resolve, reject){ setTimeout(resolve, delay); }); } } var promise = new Promise(function(resolve){ console.log("do something"); resolve(); }).then(sleep(2000)).then(function(){ console.log("after sleep 2000"); });
generator
function sleep(ms) { return function (cb) { setTimeout(cb, ms); }; } co(function *() { var now = Date.now(); yield sleep(2000); expect(Date.now() - now).to.not.be.below(2000); })();
參見知乎
underscore.js中的_.after方法該方法可以根據(jù)傳入的times參數(shù)的不同生成需要調(diào)用多次才執(zhí)行的實際函數(shù)的函數(shù),這是偏函數(shù)的典型應(yīng)用
var _ = require("underscore") var count = 5; var fiveCountCallback = _.after(count,function(){ console.log("after 5 count and execute this function") }) var timer = 0 setInterval(function(){ console.log(timer++) fiveCountCallback() // 每1s執(zhí)行一次該函數(shù),但是真正執(zhí)行該函數(shù)卻是在55后 }, 1000) console.log("this will print first")
其內(nèi)部實現(xiàn)如下:
_.after = function(times, func) { return function() { if (--times < 1) { return func.apply(this, arguments); } }; };對象的鍵
對象的鍵如果是數(shù)字,則按照數(shù)字進行升序排序。
obj = {"100":"a","99":"b"} // { "99": "b", "100": "a" } "100" > "99" // false
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80138.html
摘要:進制之謎眾所周知,計算機在設(shè)計之初,出于各方面角度考慮,最終采用二進制的格式來存儲數(shù)據(jù)。同樣的情況,也會出現(xiàn)在十進制和二進制的轉(zhuǎn)換中。當我們在計算機中,聲明一個變量為,其實該數(shù)字作為二進制保存在計算機中,并不真的是。 前言 經(jīng)常使用JavaScript用來處理數(shù)字的程序員都知道,JavaScript的Number.toFixed,這一函數(shù),在格式化數(shù)字時,會自動進行四舍五入,例如: 1...
摘要:主要講述了中關(guān)于變量聲明和代碼編寫時你可能沒它留意的一些坑。但是換行符并不會被忽略,換行符起到了分號的功能。需要注意的是,大小寫敏感,和是兩個不同的變量。保留字中有一批稱為保留字的家伙是不能用做變量的,用了在一些瀏覽器中很可能會報錯。 今天翻譯的這篇文章依舊比較基礎(chǔ),是這個系列文章的第三篇。主要講述了JavaScript中關(guān)于變量聲明和代碼編寫時你可能沒它留意的一些坑。 那些熟悉PHP...
摘要:在操作中存在著許多跨瀏覽器方面的坑,本文花了我將近一周的時間整理,我將根據(jù)實例整理那些大大小小的坑。在火狐中,與等效的是。對象的屬性則表示文檔的根節(jié)點。不區(qū)分和在下使用和時會同時返回或與給定值相同的元素。 js在操作DOM中存在著許多跨瀏覽器方面的坑,本文花了我將近一周的時間整理,我將根據(jù)實例整理那些大大小小的坑。 DOM的工作模式是:先加載文檔的靜態(tài)內(nèi)容、再以動態(tài)方式對它們進行刷新,...
閱讀 3421·2021-11-24 09:39
閱讀 1808·2021-11-17 09:33
閱讀 3539·2021-10-12 10:12
閱讀 5044·2021-09-22 15:51
閱讀 1122·2019-08-30 13:11
閱讀 3584·2019-08-30 10:59
閱讀 576·2019-08-30 10:48
閱讀 1323·2019-08-26 13:48