最近在看關於拖延症的一本書《拖拉一點也無妨》,后面得出結論是自己寫博客大部分處於兩種狀態,心情很好和心情很不好的時候。因為正常狀態下感覺寫博客吧,是件很麻煩的事情,不如去看看電影看看漫畫啥的。最近在看漫畫《進擊的巨人》和《一拳超人》,感覺是兩種極端,哈哈。
最近在進行某個項目的重寫工作,前后端都要重新構架重寫,時間給了一個月。項目的現狀大概是后端一個類有一萬行左右,包含幾十個方法。每個方法從一兩百行到上千行不等,大部分方法是沒有參數和返回值的,全局的操作幾百個成員變量。業務需求不明確,沒人能說得清,反正任務就是在不影響現有的功能的情況下重構+重寫。現有的功能有啥?也沒人能說得清。你說測試怎么驗收通過?反正測試也說不清。
前端也面臨着同樣的情況,基本上都是全局的function湊合成的,幾個文件加起來也有1萬+行。同樣沒人能說得清到底有啥東西。咱作為光榮的“接盤俠”現在就要負責處理這些留下的寶貴遺產了。前端重寫+后端重寫+數據庫SQL性能調校。
前端打算引入EventProxy和Seajs來重新整理了。
好吧,閑話扯到這里,現在開始繼續順帶的內容了,javascript中的this
一、Javascript中的this
話說javascript中的this是個變態吧,總結一下:
隱式的改變this的指向的方法
1.直接用括號()調用function的方式,這時this指向的是全局對象。
2.作為對象的方法調用,那么就是指向調用方法的對象。下面就是通過改變this來借用方法。
function addToArray() { arguments.slice = Array.prototype.slice; var add = arguments.slice(0); return add.concat(); }
可能有些人沒看明白,咱的文章習慣打破砂鍋問到底嘛,再舉幾個例子 :
我們知道Function類型是javascript中的頂級類型,可以定義自己的屬性和方法。假如有這么一個方法
Function.prototype.test = function () {
console.log(this === Function.prototype)
}
這種寫法我相信有一點js經驗的人都應該見過,這樣寫就可以給所有的函數實例加上了test方法,可具體是怎么實現的呢?我想很多人就說不清楚了。
上面這種寫法,如果這樣調用,會顯示什么呢?
Function.prototype.test()
答案是 true !
這沒什么好奇怪的,因為此時調用test方法的的確是Function類的prototype屬性的對象。但如果你想想,如果this指向的是prototype的話,那么test方法為什么會在每個函數實例中都能調用呢?
因為我們的確不會像上面這樣直接調用test方法,而是通過Function類的實例來調用test方法,這時候有東西悄悄發生了變化。沒錯,這就是this的指向。
如果有人還記得我上篇文章談談javascript中的prototype與繼承的話,就知道javascript中的對象就是一個指向prototype的指針和一個自身的屬性列表。
所以作為函數類的實例,其實是通過指針的方式隱式借用了Function類的prototype屬性中的所有方法。這時this指向的就不再是prototype對象,而是這個實例。
用代碼來表示,類似於
this.test = Function.prototype.test
這里的this指向的是函數類的實例,因此調用的時候,結果就為false。
function myFunction(){} myFunction.test()
顯式的改變this的一些方法和關鍵字
1.call
function addToArray() { var add = Array.prototype.slice.call(arguments,0); return add.concat(); }
2.apply
function addToArray() { var add = Array.prototype.slice.apply(arguments,[0]); return add.concat(); }
3.bind (ECMA Script5)
它可以看做是call 和apply的延遲版本,如果不存在的話,可以這么實現
簡單版本
if (!Function.prototype.bind) { Function.prototype.bind = function (target) { var func = this; return function () { func.apply(target, arguments); } } }
其實在ECMA Script5的規定中bind是可以預填參數的,考慮到性能的話,相對復雜一些。大部分情況下我們調用bind只是希望改變this的作用域,如果全部調用了slice和concat方法,那么性能就會相對不好。根據arguments的length不同,可以分2種綁定一共4種調用的case,在大部分情況下去獲取更好的性能。
if (!Function.prototype.bind) { (function () { var slice = Array.prototype.slice; Function.prototype.bind = function (target) { var func = this; if (arguments.length > 1) { var args = slice.call(arguments, 1); return function () { var allArgs = args; if (arguments.length > 0) { allArgs = args.concat(slice.call(arguments)); } return func.apply(target, allArgs); }; } return function () { if (arguments.length > 0) { return func.apply(target, arguments); } return func.call(target); }; }; }()); }