Q1:javascript的閉包是如何工作的?
正如愛因斯坦所說的:
如果你不能把它解釋給一個六歲的小孩,說明你對它還不夠了解。
我曾嘗試向一個27歲的朋友解釋js
閉包並且完全失敗了。你會如何向一個有概念(例如,函式,變數等)的人解釋,來彌補閉包知識,但不理解閉包本身?
Answers:
無論何時你看到function
關鍵字在另一個函式內部,那麼內部函式將可訪問外部函式的變數。
1 2 3 4 5 6 7 8 9 10 11 |
function foo(x) { var tmp = 3; function bar(y) { alert(x + y + (++tmp)); // will alert 16 } bar(10); } foo(2); |
這將總是彈出16
,因為函式bar
可以訪問變數 x
,它是作為foo
引數定義的,也可以訪問變數tmp
。
這就是一個閉包。函式沒有任何返回的時候就被稱為閉包。簡單地訪問即時詞法作用域(immediate lexical scope
)外的變數建立了一個閉包。
1 2 3 4 5 6 7 8 9 10 |
function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); // will also alert 16 } } var bar = foo(2); // bar is now a closure. bar(10); |
上面的函式也會彈出16,因為 bar
仍然可以指向 x
和 tmp
,即使它不再直接範圍內。
然而,因為 tmp
仍然在bar
的閉包內部閒逛,它也正在增加。每次你呼叫bar
的時候它會被增加。
最簡單的閉包的例子是這個:
1 2 3 4 5 6 7 8 9 |
var a = 10; var b = 6; function test() { console.log(a); // will output 10 console.log(b); // will output 6 } test(); |
當一個js
函式被呼叫的時候,一個新的執行上下文環境就被建立了。函式引數和父物件一起,這個執行上下文也接收所有的外部宣告的變數(在上面的例子,'a'
和 'b'
都是)
建立多個閉包函式是可能的,或者通過返回他們的列表,或者通過設定他們的全域性變數。所有這些將指向同上面的x
和tmp
,他們不會拷貝他們本身。
這裡的數字 x
是字面量的數字。和js
其他字面量一樣,當foo
被呼叫,數字 x
就被複制到 foo
內作為它的 引數 x
另一方面,當處理物件的時候,js
總會使用引用。如果說,你用一個Object
來呼叫foo
,閉包將會返回最早引用的Object
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function foo(x) { var tmp = 3; return function (y) { alert(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; alert(x.memb); } } var age = 2; var bar = foo(age); // bar is now a closure referencing age. bar(10); |
果然,每次呼叫bar(10)
都將增加x.memb
。這也許不是所預期的,x
僅僅是指向同樣的物件 作為age
變數!經過幾次呼叫bar
之後,age.memb
將是2!這是與HTML
物件引用的記憶體洩漏的基礎
原文連結:http://stackoverflow.com/questions/111102/how-do-javascript-closures-work
Q2:我如何使用jQuery做一個重定向頁面?
jQuery
是沒有必要的,並且window.location.replace(...)
將最佳模擬HTTP
重定向。
這比使用window.location.href =
要好,因為replace()
並不把起始頁放入會話歷史(session history
)裡,這意味著使用者不會陷入永無休止的後退按鈕的窘境。如果你想要模擬人點選一個連結,請使用location.href
。如果要模擬一個HTTP
重定向,使用location.replace
。
例如:
1 2 3 4 5 |
// 類似HTTP重定向的行為 window.location.replace("http://stackoverflow.com"); // 類似點選一個連結的行為 window.location.href = "http://stackoverflow.com"; |
原文連結:http://stackoverflow.com/questions/503093/how-can-i-make-a-redirect-page-using-jquery
Q3:測試是否有東西被隱藏
問題描述:
1 2 3 |
在jQuery中,可以切換元素的可見性,使用方法.hide(), .show() 或者.toggle(). 使用jQuery,你如何測試一個元素是可見的還是隱藏的? |
Best Answers:
因為這個問題是指一種單一的元素,所以該程式碼可能更適合:
1 2 |
// 檢查display:[none|block], 忽略 visible:[true|false] $(element).is(":visible"); |
Other Answers:
你可以使用hidden
選擇器:
1 2 |
// 匹配的是隱藏的所有元素 $('element:hidden') |
和visible
選擇器:
1 2 |
// 匹配所有可見的元素 $('element:visible') |
問題連結:http://stackoverflow.com/questions/178325/testing-if-something-is-hidden
Q4:”use strict”在js中的作用是什麼,其背後的思考是什麼?
問題描述:
最近,我執行我的一些JavaScript
程式碼通過Crockford
的JSLint
的,它給了以下錯誤:
1 |
Problem at line 1 character 1: Missing "use strict" statement. |
做了一些搜尋,我意識到是有些人新增了“use strict”
到他們的JavaScript
程式碼中。有一次,我新增了該宣告,錯誤就停止出現了。不幸的是,谷歌並沒有透露太多這字串宣告的歷史的背後。當然,它一定和javascript
如何被瀏覽器解析有關係,但我不知道效果會怎樣。
那麼,什麼是"use strict"
;所有和它仍然相關聯的涵義是什麼?
當前任何瀏覽器是否對"use strict"
做出反應;該字串或是在將來做使用?
Best Answers:
這篇文章也許對你有幫助:
John Resig – ECMAScript 5 Strict Mode, JSON, and More
引用一些有趣的部分:
1 |
嚴格模式是`ECMAScript 5`中的一項新特徵,允許你把一段程式或功能放置在"strict"工作環境中。這種嚴格上下文環境防止某些行為被採取並引發更多的異常。 |
並且:
1 2 3 4 5 |
嚴格的模式有助於幾個方面: 它捕獲了一些常見的編碼錯誤,丟擲異常。 它阻止,或丟擲錯誤,當相對“不安全”的行為被採用(例如獲取全域性物件)。 它禁用那些混淆的或者考慮不周的特徵 |
另外請注意,你可以在整個檔案中申請嚴格模式
…或者你可以僅在特定的函式中使用它(仍然是引用John Resig
的文章):
1 2 3 4 5 6 7 8 9 |
// 非嚴格的程式碼... (function(){ "use strict"; // 嚴格定義你的庫... })(); // 非嚴格的程式碼 |
如果你有混合使用新舊程式碼,它可能會有所幫助;-)
所以,我認為這是一個有點像"use strict"
,你可以在Perl
(因此得名?)中使用:它通過檢測更多可能導致破壞的事情來幫助你少犯錯誤。
Q5:如何檢測一個字串包含另一個子字串?
問題描述:
在javascript
中,我如何檢測一個字串包含另一個子字串。通常我會想到String.contains()
方法,但似乎沒有一個。
Best Answers:
indexOf
返回一個字串在其他字串中的位置。如果沒找到,它會返回-1
1 2 |
var s = "foo"; alert(s.indexOf("oo") > -1); |
原文地址:http://stackoverflow.com/questions/1789945/how-can-i-check-if-one-string-contains-another-substring
Q6:我如何在JavaScript中獲得查詢字串的值?
問題描述:
是否有一個通過jQuery
無外掛查詢字串值的方式(或者沒有)。
如果是,怎麼做?如果不是,是否有一款可以這麼做的外掛?
Best Answers:
你不需要通過jQuery
就可以達到那個目的。你可以僅僅使用純javascript
:
1 2 3 4 5 6 |
function getParameterByName(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } |
用法:
1 |
var prodId = getParameterByName('prodId'); |
問題連結:http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
Q7:var functionName = function() {} vs function functionName() {}
問題描述:
我最近開始維護別人的JavaScript
程式碼。我修復bug
,增加功能,也試圖整理程式碼並使其更加一致。
之前的開發人員使用兩種函式宣告方式,我無法弄清是否這背後有或沒有解決的原因。
兩種方法是:
1 2 3 4 5 6 7 |
var functionOne = function() { // Some code }; function functionTwo() { // Some code } |
使用這兩種不同方法的原因是什麼,以及各自的利弊是什麼?
Best Answers:
所不同的是functionOne
被定義在執行時,而functionTwo
被限定在分析時的指令碼塊。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<script> // Error functionOne(); var functionOne = function() { }; </script> <script> // No error functionTwo(); function functionTwo() { } </script> |
這也意味著在嚴格的模式下,你不能有條件地使用第二語法定義函式:
1 2 3 4 5 6 7 |
<script> "use strict"; if (test) { // Error function functionThree() { doSomething(); } } </script> |
如果沒有"use strict"
這將不會導致一個錯誤 並且 functionThree
將被定義無關test
的值。
原文連結:http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname
Q8:JavaScript 中應該用 “==” 還是 “===”?
問題描述:
我用JSLint
來檢查javascript
,當我在做類似比較idSele_UNVEHtype.value.length == 0
的時候,接著它返回許多建議用===
(三個等號)來替換==
(兩個等號)
用 ===
來取代==
是否有效能優勢?
當有許多比較操作符存在的時候,任何效能的改進都將很受歡迎。
如果沒有型別轉換髮生,效能會超過==
?
Best Answers:
恆等式(===)操作符
參考文獻:JavaScript教程:比較運算子
==
操作符在做任意按需型別轉換後將比較相等性,而===
操作符並不會, ===
運算子將不做轉換,所以如果兩值不一樣型別===
將返回false
。這種情況下,===
將更快,並可能比==
返回不同的結果。在所有其他情況下的效能都是一樣的。
引用 Douglas Crockford
的JavaScript: The Good Parts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
javascript擁有兩套等性運算子: `===`和`!==`,和他們邪惡的雙胞胎 `==`和`!=`。好的那一個會按你所期望的方式工作。如果兩個運算元是相同的型別,具有相同的值,那麼`===`產生`true`,`!==`產生`false`。當運算元具有相同型別時,邪惡雙胞胎做正確的事,但是如果他們是不同型別,它們試圖強制值。他們這麼做的規格是複雜難記的,這裡有一些有趣的例子: '' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true |
我的建議是不要使用邪惡的雙胞胎。相反,總是用===
和!==
。所有的比較只是產生虛假的= = =運算子。用===
操作符的所有的比較僅顯示false
更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var a = [1,2,3]; var b = [1,2,3]; var c = { x: 1, y: 2 }; var d = { x: 1, y: 2 }; var e = "text"; var f = "te" + "xt"; a == b // false a === b // false c == d // false c === d // false e == f // true e === f // true |
特殊情況下,當你比較字面量和物件的時候,考慮到它的toString
或者valueOf
方法。例如,考慮比較由字串建構函式建立的字串物件和字串字面量
1 2 |
"abc" == new String("abc") // true "abc" === new String("abc") // false |
這裡的==
操作符正在檢查這兩個物件的值並返回true
,但是鑑於它們不是相同型別並且===
返回false
。哪一個是正確的?這實際上取決於你想要比較什麼。我的建議是完全繞過這個問題,只是不使用字串建構函式建立字串物件。
參考: http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3
Q9:克隆一個物件的最有效的方法是什麼?
問題描述
克隆一個js
物件的最有效的方法是什麼?我已經見過obj = eval(uneval(o));
被使用,但是目前僅有Firefox支援。在 Mootools 1.2
,我已經做了類似obj = JSON.decode(JSON.encode(o));
的事情,但是存在效率問題
我也見過遞迴複製功能的各種缺陷。我很驚訝,沒有規範的解決方案存在。
Best Answers:
注:這是另一個答覆,沒有對這個問題作出恰當的回應。如果你希望快速複製一個物件請參考:[Corban’s advice in hisanswer][4] 他對這個問題的回答。
我想指出,jQuery
中的.clone()
方法只克隆DOM
元素。為了克隆JavaScript
物件,你需要這麼做:
1 2 3 4 5 |
// 淺拷貝 var newObject = jQuery.extend({}, oldObject); // 深拷貝 var newObject = jQuery.extend(true, {}, oldObject); |
更多資訊請參考:http://api.jquery.com/jQuery.extend/
我還想指出,深拷貝其實比上面所示聰明得多 – 它是能夠避免很多陷阱(例如,想深擴充套件DOM
元素)。它被頻繁地用於jQuery
的核心並且在外掛裡也有重大的作用
Other answers:
似乎沒有一個內建的方法,你可以嘗試:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function clone(obj) { if(obj == null || typeof(obj) != 'object') return obj; var temp = obj.constructor(); // changed for(var key in obj) { if(obj.hasOwnProperty(key)) { temp[key] = clone(obj[key]); } } return temp; } |
Q10:如何從一個JavaScript物件中刪除一個屬性
問題描述:
我是這麼建立一個物件的:
1 |
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; |
以new myJSONObject
結束的移除屬性regex
的最好方法是什麼?
1 |
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI"}; |
Best Answers:
1 2 3 4 5 6 |
delete myJSONObject.regex; // or, delete myJSONObject['regex']; // or, var prop = "regex"; delete myJSONObject[prop]; |
Other Answers:
1 2 3 4 5 |
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; delete myJSONObject.regex; alert ( myJSONObject.regex); // alerts: undefined |
這種方法在火狐和IE
下起作用,我個人認為在其他瀏覽器也起作用