摘要:版本假設字符每個字符編碼小于等于為字符串長度。將數組的元素依次傳入一個函數中執行,然后把它們的返回值組成一個新數組返回。復制代碼造輪子的同學注意數組的空元素不會再上述方法中遍歷出來。復制代碼方法,對數組進行洗牌。
contains方法:判定一個字符串是否包含另一個字符串。常規思維,使用正則,但每次都要用new RegExp來構造,太麻煩,性能太差。轉而使用原生字符串方法。如indexOf , lastIdexOf , search
function contains (target, it) {
return target.lastIndexOf(it) != -1; //indexOf改成search, lastIndexOf也可以 }
復制代碼
在mootools版中,我們看到它支持更多的參數,目的是判定一個元素的className是否包含某個特定的class。眾所周知,元素可以添加多個class,中間以空格隔開,使用mootoos的contains就很方便檢測包含關系了。
function contains (target, str, separator) {
return separator ? ( separator + target + separator).indexOf(separator + str +separator) > -1 : target.indexOf(str) > -1; }
復制代碼
repeat方法: 將一個字符串重復n次,如repeat("ruby",2)得到rubyruby
版本1:利用空數組的join方法
function repeat (target, n) {
return (new Array(n + 1)).join(target); }
復制代碼
版本2.....6...
版本7,遞歸在瀏覽器下做了優化 ,包括ie6,屬于最好的實現方式之一
function repeat (target, n) {
if (n == 1){ return target } var s = repeat(target, Math.floor(n/2)); s += s; if (n % 2) { s += target; } return s; }
復制代碼
byteLen方法:取得一個字符串所有字節的長度。這是一個后端轉過來的方法。在前端,我們要用戶填寫文本,需要字節有限制。
版本1:假設字符每個字符Unicode編碼小于等于255,byteLength為字符串長度。再遍歷字符串,遇到unicode編碼大于255時,為byteLength加1
function byteLen (target) {
var byteLength = target.length, i = 0; for ( ; i < target.length ; i++) { if (target.charCodeAt(i) > 255) { byteLength++; } } return byteLength; }
復制代碼
truncate方法,用于對字符串進行截斷處理,當超過限定長度,默認添加三個點號等
function truncate (target, length , truncation) {
length = length || 30; truncation = truncation === void(0) ? "..." : truncation; return target.length > length ? target.slice(0, length - truncation.length) + truncation : String(target); }
復制代碼
camelize方法,轉換為駝峰命名風格
function camelize (target) {
if (target.indexOf("_") < 0 && target.indexOf("_") < 0) { return target; //提前判斷,提高響應效率 } return target.replace(/[-_][^-_]/g , function(match){ return match.charCodeAt(1).toUpperCase(); }) }
復制代碼
underscored方法。轉換為下劃線風格
function underscored(target){
return target.replace(/([a-zd])([A-Z])/g , "$1_$2").replace(/-/g , "_").toLowerCase(); }
復制代碼
dasherize方法,轉換為連字符風格,亦指css變量風格(承上面的方法)
function dasherize(target){
return underscored(target).replace(/_/g, "-"); }
復制代碼
capitalize方法,首字母大寫
function capitalize(target) {
return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase(); }
復制代碼
stripTags方法,移除字符中的html標簽。但有一個缺陷,如果其中有script標簽,會把不該顯示的腳本也顯示出來。
function stripTags(target){
return String(target || "") .replace(/<[^>]+>/g, ""); }
復制代碼
escapeHTML和unescapeHTML略
escapeRegExp方法:將字符串安全格式轉換為正則表達式的源碼
function escapeRegExp(target){
return target.replace(/([-.*+?^${}()|[]/])/g, "$1"); }
復制代碼
pad方法,與trim方法相反,pad可以為字符串的某一端添加字符串。常見的是在日歷的月份前面加補0,因此,被稱為fillZero。
function pad(target,n){
var zero = new Array(n).join("0"); var str = zero + target; var resulet = str.substr(-n); return resulet; }
復制代碼
高級方法,也是mass Framework使用的版本,支持更多的參數。允許從左邊或從右填充。以及使用什么內容進行填充。
function pad (target, n, filling, right, radix){
var num = target.toString(radix || 10); filling = filling || "0"; while (num.length < n){ if(!right){ num = filling + num; } else { num += filling; } return num; } }
復制代碼
wbr方法,為目標字符串添加wbr換行。不過需要注意的是,它不是為每個字符串都插入字樣,而是相當于在組成文本節點的報語法中的每個字符后插入字樣。如果是aabbcc,返回aabbcc,在opear瀏覽器上,默認的css不會添加上wbr樣式,需要在css上添加,wbr:after{content:"00200B"}解決此問題
function wbr (target){
return String(target).replace(/(?:<[^>]+>) | (?:?[0-9a-z]{2,6};) | (.{1})/gi,"$&").replace(/> /g,">"); }
復制代碼
format方法,在c語言中,有一個printf方法,我們可以在后面添加不同的類型的參數嵌入到將要輸出的字符串中。這是非常有用的方法,因為在javascript中涉及到大量這樣字符串拼接的工作 ,如果涉及邏輯,我們可以用模板,如果輕量點,我們可以用這個方法。
在不同的框架中名字不同,prototype.js 叫interpolate,Base2叫format,mootools叫substitute。
function format (str, object){
var array = Array.prototype.slice.call(arguments, 1); return str.replace(/?#{([^{}]+)}/gm,function(match, name) { if(match.charAt(0) == "") return match.slice(1); var index = Number(name) if(index >= 0) return array[index]; if (object && object[name] !== void 0) return object[name]; return ""; }); } var a = format("resulet is #{0}, #{1}",22,33) console.log(a) // resulet is 22, 33var b = format ( "#{name} is a #{sex} #{am}" ,{ name:"wangjie", sex:"man", am:"111" }); console.log(b) // wangjie is a man 111
復制代碼
它支持兩種傳參方法,如果字符串的占位符為0,1,2這樣的非零整數,要求傳入兩個或以上的參數,否則就傳入一個對象,鍵名為占位符。
quote方法,在字符串的兩端加上雙引號。然后內部需要轉義的地方都要轉義。用于接裝JSON的鍵名或模析系統中
//code.google.com/jQuery-jsonvar escapeable = /["x00-x1fx7f-x9f]/g,
meta = { "":"", " ":" ", " ":" ", "f":"f", " ":" ", """:""", "":"" }; function quote(target){ if (target.match(escapeable)){ return """ + target.replace(escapeable,function(a) { var c = meta[a]; if(typeof c === "string") { return c; } return "u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4) }) + """; } return """ + target + """; }
復制代碼
當然,如果瀏覽器支持原生的JSON,我們直接用JSON.stringify就行了,另外,FF在JSON發明之前,就支持String.prototype.quote與String.quote方法了,我們使用quote之前判定瀏覽器是否內置這些方法
字符串好像沒有打的瀏覽器兼容問題,有的話是IE6,IE7不支持用數組中括號取它的每一個字符,需要用charAt來取。IE678不支持垂直分表符,因此有如下hack
var isIe678 = !+"v1";
復制代碼
修復舊版本IE中的trim函數。這是一個很常用的操作,通常我們需要把表單的兩側空白清除掉
版本1,用了兩次正則,實際速度非常驚人,主要得益于瀏覽器的內部優化。base2使用這種優化,引起了其它瀏覽器的跟風。于是正則的實現再也比不過字符串方法了。一個著名的例子,字符串拼接。直接相加比Array做成的StringBuffer還快。而StringBuffer技術在早些年備受推崇。
function trim(str){
return str.replace(/^ss*/, "").replace(/ss*$/, ""); }
復制代碼
版本2
利用兩個候選操作符鏈接兩個正則,這樣做就失去了瀏覽器優化的機會。由于看起來很優雅,很多類庫都使用它。如jQuery,mootools
function trim(str){
return str.replace(/^s+|s+$/g, ""); }
復制代碼
版本3
更好的改進版
function trim(str){
var str = str.replace(/^ss*/, ""), ws = /s/, i = str.length; while (ws.test(str.charAt(--i))) return str.slice(0, i + 1); }
復制代碼
2.數組的擴展與修復
得益于Prototype.js的ruby式數組方法的侵略,讓jser()的前端工程師大開眼界,原來對數組的操作是如此的豐富多彩。原來的javascript數組方法就是基于棧與隊列的一套方法,像splice()還是很晚的時候加入的。讓我們回顧一下用法。
pop()方法,出棧操作,刪除并返回數組的最后一個元素
push()方法,出棧操作,向數組的末尾添加一個或更多元素,并返回新的長度。
shift()方法,出隊操作,刪除并返回數組的第一個元素
unshift()方法,入隊操作,向數組的開頭添加一個或更多的元素,返回新的長度
slice()方法,切片操作,從數組中分離出一個子數組,功能類似字符串的substring、slice、substr這三兄弟。此方法也常用于轉換類數組對象為真正的數組
sort()方法,對數組元素進行排序,有一個可選參數,為比較函數。
reverse()方法,顛倒數組中元素的順序。
splice()方法,用于用于同時對原數組進行增刪操作,數組的remove方法就是基于它而寫的
concat()方法,用于把原數組與參數合并成一個新數組,如果參數為數組,那么它會把其第一維的元素放入新的數組中。因此我們可以利用它實現數組的平坦化操作和克隆操作。
join()方法,把數組的所有元素放入一個字符串。元素通過指定的分隔符進行分隔。你可以想象成字符串的split的反操作。
在ecma262v5中,它把標準瀏覽器早已經實現的幾個方法進行了入戶處理。從此,我們可以安心的使用forEach()方法,不用擔心他們被廢棄掉了。
indexOf()方法,定位操作。同上,不是從后遍歷。索引操作可以說是字符串的同名方法的翻版,存在就返回非負操作。不存在就返回-1.
forEach()方法。迭代操作。將數組的元素依次傳入一個函數中執行,prototype.js對應的名字為 each。
map()方法,收集操作。將數組的元素依次傳入一個函數中執行,然后把它們的返回值組成一個新數組返回。prototype.js對應的名字為collect.
fliter()方法。過濾操作,將數組的元素依次傳入一個函數中執行,然后把返回值為true的那個元素放入新的數組中返回。prototype.js中它有三個名字,select、filter、findAll
some()方法,只要數組中有一個元素滿足條件(放進函數返回true)。那么它就返回true.prototype.js對應的名字為any
every()方法,只有數組的元素滿足調條件(放進給定函數返回true)它才返回true。prototype.js對應的名字為any
reduce()方法,歸化操作。將數組中的元素歸化為一個簡單的數值。prototype.js對應的名字為inject
reduceRight()方法:歸化操作,將數組中的元素歸化為一個簡單的數值。同上,不過是從后遍歷。
由于許多擴展也基于這些新的標準方法,因此我們先給出IE678兼容方案,全部在數組原型上修復他們。
Array.prototype.indexOf = function(item, index){ var n = this.length, i = ~~index; if(i<0) i += n; for(; i= 0; i--) if (this[i] === item) return i; return -1; }
復制代碼
像forEach map filter some every這幾個方法,在結構上非常相似,我們可以這樣生成他們。
function iterator (vars, body, ret){
var fun = "for (var " + vars + "i = 0,n = this.length; i < n; i++ ){" + body.replace("_", "((i in this) && fn.call(scope,this[i],i,this))") + "}" + ret return Function ("fn,scope", fun); } Array.prototype.forEach = iterator("","_",""); Array.prototype.filter = iterator("r=[],j=0", "if(_)r[j++]=this[i]", "return r"); Array.prototype.map = iterator("r=[],", "r[i]=_" , "return r"); Array.prototype.some = iterator("","if(_)return true", "return false"); Array.prototype.every = iterator("","if(!_)return false","return true")
復制代碼
造輪子的同學注意:數組的空元素不會再上述方法中遍歷出來。
[1,2,,4].forEach(function(e){ console.log(e) })
復制代碼
接下來,我們將對數組的擴展進行總結,除去上述的
prototype.js的數組擴展:eachSlice , detect , grep , include , inGruopsOf , invoke, max, min, partition, pluck , reject, sortBy , zip , size, clear, first, last, compact, faltten , without, uniq , intersect, clone, inspect
Right.js 的數組擴展有 include, clean , clone , conpact, empty , first , flatten , includes, last, max , merge , min , random, reject, shuffle , size , sortBy, sum , uniq ,walk, without
mootools的數組擴展,clean, clone , associate , link , contains, append, getLast , getRandom, include, combine, erase, empty, flatten, min, max, mean, sum, erase, insert.
Ext的數組擴展, contains, pluck, clean, qunique, form , remove, include, merge,insersect, difference, flatten, min , max, mean, sum, erase, insert
Underscore.js 的數組擴展, detect, reject, invoke , pluck, sortBy, groupBy, sortedIndex, first, last, compact, flatten,without , union, intersection , difference, quiq, zip
qooxdoo數組擴展, insertAfter, insertAt, insertBefore , max , min , remove , removeAll , removeAt, sum , unique.
百度七巧板擴展, contains ,empty , find , remove , removeAt , unique
我們可以發現,Prototype.js 的一套方法影響深遠, 許多庫都有它的影子。我們可以根據需要與框架宗旨指定自己的數組擴展, 我們在這些方面考慮如下: 至少包含:平坦化, 去重, 亂序,移除這幾個操作,其次是兩個集合間的操作,如取并集。差集,交集。 下面是各種具體實現。
contains方法, 判定數組是否包含指定的目標
function contains(target, item){
return target.indexOf(item) > -1 }
復制代碼
removeAt方法,移除數組中指定位置的元素,返回布爾表示成功與否
function removeAt(target, index){
return !!target.splice(index, 1).length }
復制代碼
remove方法,移除數組中第一個匹配傳參的那個元素,返回布爾表示成功與否。
function remove(target, ietm){
var index = target.indexOf(ietm); if(~index) return removeAt(target,index); returnfalse; }
復制代碼
shuffle方法,對數組進行洗牌。若不影響原數組,可以先拷貝一份出來操作,有關洗牌,可以參考 博文:http://bost.ocks.org/mike/shu...
function shuffle(target){
var j, x, i = target.length; for(; i > 0; j = parseInt(Math.random() * i) , x = target[--i],target[i] = target[j] = x) { } return target }
復制代碼
random方法,從數組中隨機選出一個元素出來
function random(target){
return target[Math.floor(Math.random() * target.length)]; }
復制代碼
flatten方法,對數組進行平坦化處理,返回一個一維的新數組
function flatten(target){
var resulet = []; target.forEach(function(item){ if (Array.isArray(item)) { resulet = resulet.concat(flatten(item)); } else{ resulet.push(ietm) } }); return resulet; }
復制代碼
unique方法,對數組去重,返回一個沒有重復元素的新數組
function unique(target){
var resulet = []; loop: for (var i = 0, n = target.length; i < n; i++){ for (var x = i + 1; x < n; x++){ if (target[x] === target[i]) continue loop; } resulet.push(target[i]); } return resulet; }
復制代碼
compact方法,過濾數組中的null和undefined,但不影響數組。
function compact (target) {
return target.filter(function(el){ return el != null; }); }
復制代碼
pluck方法,獲得對象數組中的每個元素的指定屬性,組成數組返回
function pluck(target, name){
var resulet = [], prop; target.forEach(function(ietm){ prop = ietm[name]; if (prop != null) resulet.push(prop); }); return resulet; }
復制代碼
groupBy方法:根據指定條件(如回調或對象的某個屬性)進行分組,構成對象返回
function groupBy(target, val){
var resulet = {}; var iterator = $.isFunction(val) ? val : function (obj){ return obj[val]; }; target.forEach(function(value, index){ var key = iterator (value, index); (resulet[key] || resulet[key] = [])).push(value); }); return resulet }
復制代碼
sortBy方法:根據指定條件進行排序,通常用于對象數組
function sortBy(target, fn, scope){
var array = target.map(function(ietm, index){ return { el: ietm, re: fn.call(scope, ietm, index) }; }).sort(function(left, right){ var a = left.re, b = right.re; return a < b ? -1 : a > b ? 1: 0; }) return pluck(array, "el"); }
復制代碼
union方法,對兩個數組取并集
function union (target, array){
return unique(target.concat(array)); }
復制代碼
intersect方法:對兩個數組取交集
function intersect(target, array){
return target.filter(function(n){ return ~array.indexOf(n); }); }
復制代碼
diff方法,對兩個數組取差集
function diff(target, array){
var resulet = target.slice(); for (var i = 0, i < resulet.length; j++) { for (var j = 0; j < resulet.length; j++) { if (resulet[i] === array[j]){ resulet.splice(i, 1); i--; break; } } } return resulet; }
復制代碼
min方法,返回數組的最小值,用于數字數組
function min (target){
return Math.min.apply(0, target); }
復制代碼
max方法,返回數組中的最大值。用于數字數組
function max(target){
return Math.max.apply(0, target); }
復制代碼
3.數值的擴展與修復
數值沒有什么好擴展的,而且javascript的數值精度問題一向臭名昭著,修復不是一兩行代碼的事情。先看擴展。
Prototype.js為它添加了8個原型方法,Succ是加1,times是將回調重復執行制定次數,toPaddingString與上面提到的字符串擴展方法pad作用一樣,toColorPart是轉十六機制,abs,ceil,floor,是從Math中提取出來的
mootools的情況,limit是從數值限在一個閉開間中,如果大于或小于其邊界,則等于其最大值或最小值,times與prototype.js用法相似,round是Math.round的增強版,添加了精度控制,toFloat,toInt是從window中偷學來的。
看看mass Framework對數字的擴展
limit方法,確保數值在[n1,n2]閉區間之內,如果超出界限,則置換為離它最近的最大值或最小值。
function limit(target, n1, n2){
var a = [n1, n2].sort(); if (target < a[0]) target = a[0]; if(target > a[1]) target = a[1]; return target; }
復制代碼
nearer方法,求出距離數值最近的那個數。
function nearer(target, n1, n2){
var diff1 = Math.abs(target - n1), diff2 = Math.abs(target - n2); return diff1 < diff2 ? n1 : n2 }
復制代碼
Number下唯一要修復的方法是toFixed,它是用來校正精確度,最后的那個數會四舍五入操作,但在一些瀏覽器中,并未這么操作。 簡單修復可以這樣處理
if(0.9.toFixed(0) !== "1") {
Number.Prototype.toFixed = function(n) { var power = Math.pow(10, n); var fixed = (Math.round(this*power)/power).toString(); if(n == 0) return fixed; if(fixed.indexOf(".") < 0) fixed += "."; var padding = n + 1 (fixed.length - fixed.indexOf(".")); for (var i = 0; i < padding; i++) fixed += "0"; return fixed; } }
復制代碼
關于javascript誤差運算不在這里呈現了,但在工作中,我們盡量避免小數操作與大數操作,或者轉交后臺處理,實在避免不了,可以引入專業的庫來實現。
4.函數的擴展與修復
V5對函數的唯一擴展就是bind函數,眾所周知,這來自prototype.js,此外,其它重要的函數都來自prototype.js
prototype.js的函數擴展如下:
argumentNames:取得函數的形參,以字符串形式返回,這只要用于其類工廠的方法鏈設計
bind,不用多描述,劫持作用域,并預先添加更多的參數。
bindAsEventListener 如bind相似,但強制返回函數的第一個參數為事件對象,這是用于修復IE多投事件API與標準API的差異。
curry 函數柯里化,用于一個操作分成多步進行,并可以改變原函數的行為。
wrap:AOP 的實現。
delay:setTimeout的偷懶寫法。
defer:強制延遲0.01秒才執行原函數
methodize:將一個函數變成其調用對象的方法,這也是為其類工廠的方法服務。
首先我們看bind方法,它用到了著名的閉包(所謂閉包,就是引用著外部變量的內部函數),比如下面這個函數
[
復制代碼
](javascript:void(0);)
var observable = function(val){
var cur = val; //一個內部變量function field(neo) { if (arguments.length){ //setterif (cur !== neo) { cur = neo } } else { //getterreturn cur; } } field(); return field; }
復制代碼
它里邊的field函數將于外部的cur構成一個閉包。prototype.js中的bind方法只要依仗原來=函數與經過切片話的args構成閉包,而這個方法就是名副其實的curry柯里化,用戶最初的那個傳參,劫持到返回函數修正this的指向。
Function.Prototype.bind = function(context) { if (arguments.length < 2 && context == void 0) returnthis; var _method = this, args = [].slice.call(arguments, 1); returnfunction() { return _method.apply(context, args.context.apply(args, arguments)); } }
復制代碼
因為有這個原型擴展,我們才可以修復ie的多投事件API attachEvent回到的this問題,它總是指向window對象,而標準的瀏覽器的的addEventListener中的this則其調用對象
var addEvent = document.addEventListener ?
function (el, type, fn, capture){ el.addEventListener (type, fn, capture) } : function (el, type, fn) { el.attachEvent("on" + type, fn.bind(el, event)) }
復制代碼
ECMA62 V5對其認證以后,唯一的增強是對調用者進行監測,確保它是一個函數。順便總結一下這三個東西。
call是obj.method(a, b, c)到method(obj,[a, b, c])的變換,它要求第二個參數必須存在,一定是數組或Arguments這樣的類數組,NodeList這樣具有爭議性的東西就不能傳入進去! 因此,jQuery對兩個數組或類數組的合并就使用jQuery.merge,放棄使用Array.prototype.push.apply。
bind就是apply的變種,保證返回值是一個函數。
這三個方法非常有用,我們設法將其還原出來。
var bind = function(bind) {
return { bind: bind.bind(bind), call: bind.bind(bind.call), apply: bind.bind(bind.apply) } } (Function.Prototype.bind)
復制代碼
那么怎么使用它們呢,比如我們想合并兩個數組,直接調用concat方法:
var concat = bind.apply([].concat);
var a = [1, [2,3], 4]; var b = [1, 3];
復制代碼
使用bind.bind方法可以將它們的結果進一步平坦化
var concat = bind.apply([].concat);
console.log(concat(b,a)); //=> [1,3,1,2,3,4]
復制代碼
又如切片化操作,它經常用于轉換類數組對象為純數組
var slice = bind([].slice)
var array = slice({ 0: "aaa", 1: "bbb", 2: "ccc", 3: "ffffd" length: 4 }); console.log(array) //=> ["aaa","bbb","ccc","ffffd"]
復制代碼
更常用的操作是轉換arguments對象,目的是為了使用數組的一系列方法
function test() {
var args = slice(arguments) console.log(args)//=> [1,2,3,4,5] } test(1, 2, 3, 4, 5)
復制代碼
我們可以將hasOwnProperty提取出來,判定對象是否在本地就擁有某屬性
var hasOwn = bind.call(Object.Prototype.hasOwnProperty);
hasOwn([],"xx") //false//使用bind.bind就需要多執行一次var hasOwn2 = bind.bind(Object.Prototype.hasOwnProperty); hasOwn2([],"xx")() //false
復制代碼
上面的bind.bind的行為就是一種curry,它給了你一種傳參的機會,這樣你就可以在內部判定參數的個數,決定是否繼續返回函數還是結果。這在設計計算器的連續運算上非常有用。從此角度,我們可以得到一條信息,bind著重作用域的劫持,curry在于參數的不斷補充。
我們可以編寫一個curry,當所有步驟輸入的參數個數等于最初定義時的函數形參個數,就執行它。
function curry(fn) {
function inner(len, arg) { if (len == 0) return fn.apply(null, arg); returnfunction(x) { return inner(len - 1, arg.concat(x)); }; } return inner(fn.length, []); } function sum(x, y, z, w){ return x + y + z + w; } curry(sum)("a")("b")("c")("d"); //=> "abcd"
復制代碼
不過這里我們假定了用戶每次都只傳入一個參數,我們可以改進下
function curry2(fn) {
function inner (len, arg){ if (len <= 0) return fn.apply(null, arg); returnfunction() { return inner (len - arguments.length, arg.concat(Array.apply([],arguments))); } } return inner(fn.length, []); }
復制代碼
這樣,我們就可以在中途傳遞多個參數,或不傳遞參數
curry2(sum)("a")("b","c")("d"); //=> "abcd"
curry2(sum)("a")()("b","c")()("d"); //=> "abcd"
復制代碼
不過,上面的函數形式有個更帥氣的名稱,叫self-curry,或recurry.它強調的是遞歸自身來補全參數。 與curry相似的partial。curry的不足 參數總是通過push的方式來補全,而partial則是在定義時所有參數都已經有了,但某些位置上的參數值是個占位符,我們在接下來的傳參只是替換掉它們。博客上專門有《partial application in javascript》來介紹這個內容。
Function.Prototype.partial = function(){ var fn = this, args = Array.prototype.slice.call(arguments); returnfunction() { var arg = 0; for (var i = 0 ; i < args.length && arg < arguments.length; i++) if (args[i] === undefined) args[i] = arguments[args++]; return fn.apply(this, args); } }
復制代碼
它是使用undefined作為占位符的。
var delay = setTimeout.partial(undefined, 10);
//接下來的工作就代替掉第一個參數 delay(function() { console.log("A call to this function will be temporarily delayed") })
復制代碼
curry、partial應用場景在前端世界應用的并不多,前端講究的是即時顯示,許多API都是同步的,后端由于IO操作等耗時夠長,像node.js提供了大量的異步函數來提高性能,防止堵塞。但是過多的異步函數必然帶來回調嵌套的問題。因此,我們需要curry等函數變換。將嵌套減少到可以接受的程度。在ajax中會講述他們的使用辦法。
函數的修復,這涉及到方法,apply和call,這兩個方法的本質就是生成一個新的函數。將原函數與用于的傳參放到里面執行而已,在javascript中創造一個函數有很多辦法,常見的有函數聲明和函數表達式,次之是函數構造器,再次之是eval,setTimeout....
5.日期的擴展與修復
Date構造器是javascript中傳參最豐富的構造器。大致分為四種:
new Date();
new Date(value); //傳入毫秒鼠new Date(dateString) new Date(year, month, day/*, hour, minute, second, minllisecond*/)
復制代碼
其中,第三種可以玩N多花樣,個人建議只使用"2009/07/12 12:34:56",后面的分秒可以省略。這個所有的瀏覽器都支持,此構造器的兼容列表可見此文。
http://dygraphs.com/date-form...
若要修正它的傳參,可能是個龐大的工程。并且影響Object.prototype.toString的類型的判斷。因此,不建議修正。es5.js中的源碼,可以參考
https://github.com/kriskowal/...
javascript的日期是抄自java.util.Date,但是Date這個類的很多方法對時區等支持不夠,且不少都過時,java程序員也推薦使用calnedar類代替Date類。javascript可以選擇余地比較小。如對屬性使用了前后矛盾的偏移量。月份與小時都是基于0.月份中的天數則是基于1,而年則是從1900開始的.
接下來,我們為舊版的瀏覽器添加幾個ecma262標準化日期方法吧
if(!Date.now) {
Date.now = function(){ return + new Date; } } if (!Date.prototype.toISOString) { voidfunction() { function pad (number) { var r = String(number); if (r.length === 1) { r = "0" + r ; } return r } Date.prototype.toJSON = Date.prototype.toISOString = function() { returnthis.getUTCFllYear() + "_" + pad(this.getUTCMonth() + 1) + "_" + pad(this.getUTCDate()) + "T" + pad(this.getUTCHours()) + ":" + pad(this.getUTCMinutes()) + ":" + pad(this.getUTCSeconds()) + "." + String((this.getUTCMilliseconds()/1000).toFixed(3)).clice(2, 5) + "Z"; } }(); }
復制代碼
IE67 中,getYear, setYear方法存在bug.這個修起來比較簡單:
if ((new Date).getYear() > 1900){
Date.prototype.getYear = function(){ returnthis.getFullYear() - 1900; }; Date.prototype.setYear = function(year){ returnthis.setFullYear(year); //+1900 }; }
復制代碼
至于擴展,由于涉及本地化的原因,外國許多日期庫都需要改一改才能用。其中以dataFormat這個很有用的方法為最。先給一些常用的擴展。
傳入兩個Date類型的日期,求其相隔的天數
var getDatePeriod = function(start, finish){
return Math.abs(start * 1 - finish * 1) / 60 / 60 / 1000 / 24; }
復制代碼
傳入一個Date類型的日期,判斷它所在月的第一天。
var getFirstDateInMouth = function(date) {
returnnew Date(Date.getFullYear(), Date.getMonth(), 1); }
復制代碼
傳入一個Date類型的日期,判斷它所在月的最后一天。
var getLastDateInMouth = function(date) {
returnnew Date(Date.getFullYear(), Date.getMonth() + 1, 0); }
復制代碼
判斷是否是閏年
Date.prototype.isLeapYear = function(){ returnnew Date(this.getFullYear(),2 ,0).getDate() == 29; }
復制代碼
獲得當前月份的天數
function getDaysInMotn1(date) {
switch (Date.getMonth()) { case 0: case 2: case 4: case 6: case 7: case 9: case 11: return 31; case 1: var y = Date.getFullYear(); return y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28; default : return 30; } } function getDaysInMonth2(date) { returnnew Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); }
復制代碼
dateFormat方法太長,此處略。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96861.html
摘要:春招結果五月份了,春招已經接近尾聲,因為到了周五晚上剛好有空,所以簡單地記錄一下自己的春招過程。我的春招從二月初一直持續到四月底,截止今天,已經斬獲唯品會電商前端研發部大數據與威脅分析事業部京東精銳暑假實習生的騰訊的是早上打過來的。 春招結果 五月份了,春招已經接近尾聲,因為到了周五晚上剛好有空,所以簡單地記錄一下自己的春招過程。我的春招從二月初一直持續到四月底,截止今天,已經斬獲唯品...
摘要:扁平化嵌套數組實現描述將嵌套多層的數組展開平鋪成只有一層的數組。方法一知識點方法二知識點方法三知識點展開語法其它方法數組去重描述將數組中重復的元素過濾掉。對于函數防抖,門外有人頻繁敲門,門衛按最后一次敲門來決定是否開門。知識點發布訂閱模式 1. 扁平化嵌套數組/flat實現 描述:將嵌套多層的數組展開平鋪成只有一層的數組。 let array = [1, [1, 2, 3], [1, ...
摘要:為了避免它,只需分配將要使用的必要構造函數。示例對于此示例,就需要保持父構造函數繼續正常工作。結論手動設置或更新構造函數可能會導致不同且有時令人困惑的后果。為了防止它,只需在每個特定情況下定義構造函數的角色。 hr小姐姐說一共有1輪筆試 + 3輪技術面 + 1輪hr面,面試地點在中關村天使大廈,崗位是1-3年前端 筆試 筆試分為多選 簡答 判斷 手寫代碼四部分,下面只寫了印象比較深的幾...
摘要:面經因為我完全沒有面試經驗,從來沒有經歷過面試,于是想著在去這類大公司面試之前先找成都的小公司練練手,積累點面試經驗。于是三月份開始就有成都的小公司開始約我面試。 前序 從我高考成績出來那一刻開始,從我在高考志愿上填上計算機科學與技術這幾個當時在心中堪稱神圣的幾個字開始,我就已經把進入中國互聯網最高殿堂BAT作為我整個大學奮斗的目標,哪怕我就讀的是一所位于內陸的雙非一本大學我也認為我能...
摘要:最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現,。后面以這道題為引線面試官可能會追問什么是執行上下文的判斷,的區別手寫一個函數實現斐波那契數列首先拷一個阮神在他教程里的一個寫法。 最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現bind,promise。手寫ajax,手寫一些算法。翻閱了很多書籍和博客。 這里做一個總結改進,算是對我后面大概為期一個月找...
閱讀 792·2021-09-22 16:01
閱讀 2084·2021-08-20 09:37
閱讀 1693·2019-08-30 15:54
閱讀 1689·2019-08-30 15:44
閱讀 826·2019-08-28 18:23
閱讀 3005·2019-08-26 12:17
閱讀 1005·2019-08-26 11:56
閱讀 1539·2019-08-23 16:20