Q1:javascript的闭包是如何工作的?
正如爱因斯坦所说的:
如果你不能把它解释给一个六岁的小孩,说明你对它还不够了解。
我曾尝试向一个27岁的朋友解释js
闭包并且完全失败了。你会如何向一个有概念(例如,函数,变量等)的人解释,来弥补闭包知识,但不理解闭包本身?
Answers:
无论何时你看到function
关键字在另一个函数内部,那么内部函数将可访问外部函数的变量。
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
)外的变量创建了一个闭包。
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
的时候它会被增加。
最简单的闭包的例子是这个:
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
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
对象引用的内存泄漏的基础
Q2:我如何使用jQuery做一个重定向页面?
jQuery
是没有必要的,并且window.location.replace(...)
将最佳模拟HTTP
重定向。
这比使用window.location.href =
要好,因为replace()
并不把起始页放入会话历史(session history
)里,这意味着用户不会陷入永无休止的后退按钮的窘境。如果你想要模拟人点击一个链接,请使用location.href
。如果要模拟一个HTTP
重定向,使用location.replace
。
例如:
// 类似HTTP重定向的行为
window.location.replace("http://stackoverflow.com");
// 类似点击一个链接的行为
window.location.href = "http://stackoverflow.com";
Q3:测试是否有东西被隐藏
问题描述:
在jQuery中,可以切换元素的可见性,使用方法.hide(), .show() 或者.toggle().
使用jQuery,你如何测试一个元素是可见的还是隐藏的?
Best Answers:
因为这个问题是指一种单一的元素,所以该代码可能更适合:
// 检查display:[none|block], 忽略 visible:[true|false]
$(element).is(":visible");
Other Answers:
你可以使用hidden
选择器:
// 匹配的是隐藏的所有元素
$('element:hidden')
和visible
选择器:
// 匹配所有可见的元素
$('element:visible')
Q4:"use strict"在js中的作用是什么,其背后的思考是什么?
问题描述:
最近,我运行我的一些JavaScript
代码通过Crockford
的JSLint
的,它给了以下错误:
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
引用一些有趣的部分:
严格模式是`ECMAScript 5`中的一项新特征,允许你把一段程序或功能放置在"strict"工作环境中。这种严格上下文环境防止某些行为被采取并引发更多的异常。
并且:
严格的模式有助于几个方面:
它捕获了一些常见的编码错误,抛出异常。
它阻止,或抛出错误,当相对“不安全”的行为被采用(例如获取全局对象)。
它禁用那些混淆的或者考虑不周的特征
另外请注意,你可以在整个文件中申请严格模式
...或者你可以仅在特定的函数中使用它(仍然是引用John Resig
的文章):
// 非严格的代码...
(function(){
"use strict";
// 严格定义你的库...
})();
// 非严格的代码
如果你有混合使用新旧代码,它可能会有所帮助;-)
所以,我认为这是一个有点像"use strict"
,你可以在Perl
(因此得名?)中使用:它通过检测更多可能导致破坏的事情来帮助你少犯错误。
Q5:如何检测一个字符串包含另一个子字符串?
问题描述:
在javascript
中,我如何检测一个字符串包含另一个子字符串。通常我会想到String.contains()
方法,但似乎没有一个。
Best Answers:
indexOf
返回一个字符串在其他字符串中的位置。如果没找到,它会返回-1
var s = "foo";
alert(s.indexOf("oo") > -1);
Q6:我如何在JavaScript中获得查询字符串的值?
问题描述:
是否有一个通过jQuery
无插件查询字符串值的方式(或者没有)。
如果是,怎么做?如果不是,是否有一款可以这么做的插件?
Best Answers:
你不需要通过jQuery
就可以达到那个目的。你可以仅仅使用纯javascript
:
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, " "));
}
用法:
var prodId = getParameterByName('prodId');
Q7:var functionName = function() {} vs function functionName() {}
问题描述:
我最近开始维护别人的JavaScript
代码。我修复bug
,增加功能,也试图整理代码并使其更加一致。
之前的开发人员使用两种函数声明方式,我无法弄清是否这背后有或没有解决的原因。
两种方法是:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
使用这两种不同方法的原因是什么,以及各自的利弊是什么?
Best Answers:
所不同的是functionOne
被定义在运行时,而functionTwo
被限定在分析时的脚本块。例如:
<script>
// Error
functionOne();
var functionOne = function() {
};
</script>
<script>
// No error
functionTwo();
function functionTwo() {
}
</script>
这也意味着在严格的模式下,你不能有条件地使用第二语法定义函数:
<script>
"use strict";
if (test) {
// Error
function functionThree() { doSomething(); }
}
</script>
如果没有"use strict"
这将不会导致一个错误 并且 functionThree
将被定义无关test
的值。
Q8:JavaScript 中应该用 "==" 还是 "==="?
问题描述:
我用JSLint
来检查javascript
,当我在做类似比较idSele_UNVEHtype.value.length == 0
的时候,接着它返回许多建议用===
(三个等号)来替换==
(两个等号)
用 ===
来取代==
是否有性能优势?
当有许多比较操作符存在的时候,任何性能的改进都将很受欢迎。
如果没有类型转换发生,性能会超过==
?
Best Answers:
恒等式(===)操作符
参考文献:JavaScript教程:比较运算符
==
操作符在做任意按需类型转换后将比较相等性,而===
操作符并不会, ===
运算符将不做转换,所以如果两值不一样类型===
将返回false
。这种情况下,===
将更快,并可能比==
返回不同的结果。在所有其他情况下的性能都是一样的。
引用 Douglas Crockford
的JavaScript: The Good Parts
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
更新:
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
方法。例如,考虑比较由字符串构造函数创建的字符串对象和字符串字面量
"abc" == new String("abc") // true
"abc" === new String("abc") // false
这里的==
操作符正在检查这两个对象的值并返回true
,但是鉴于它们不是相同类型并且===
返回false
。哪一个是正确的?这实际上取决于你想要比较什么。我的建议是完全绕过这个问题,只是不使用字符串构造函数创建字符串对象。
原文链接:http://stackoverflow.com/ques...
Q9:克隆一个对象的最有效的方法是什么?
问题描述
克隆一个js
对象的最有效的方法是什么?我已经见过obj = eval(uneval(o));
被使用,但是目前仅有Firefox支持。在 Mootools 1.2
,我已经做了类似obj = JSON.decode(JSON.encode(o));
的事情,但是存在效率问题
我也见过递归复制功能的各种缺陷。我很惊讶,没有规范的解决方案存在。
Best Answers:
注:这是另一个答复,没有对这个问题作出恰当的回应。如果你希望快速复制一个对象请参考:[Corban's advice in his
answer][4] 他对这个问题的回答。
我想指出,jQuery
中的.clone()
方法只克隆DOM
元素。为了克隆JavaScript
对象,你需要这么做:
// 浅拷贝
var newObject = jQuery.extend({}, oldObject);
// 深拷贝
var newObject = jQuery.extend(true, {}, oldObject);
更多信息请参考:http://api.jquery.com/jQuery....
我还想指出,深拷贝其实比上面所示聪明得多 - 它是能够避免很多陷阱(例如,想深扩展DOM
元素)。它被频繁地用于jQuery
的核心并且在插件里也有重大的作用
Other answers:
似乎没有一个内置的方法,你可以尝试:
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对象中删除一个属性
问题描述:
我是这么创建一个对象的:
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
以new myJSONObject
结束的移除属性regex
的最好方法是什么?
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI"};
Best Answers:
delete myJSONObject.regex;
// or,
delete myJSONObject['regex'];
// or,
var prop = "regex";
delete myJSONObject[prop];
Other Answers:
var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myJSONObject.regex;
alert ( myJSONObject.regex); // alerts: undefined
这种方法在火狐和IE
下起作用,我个人认为在其他浏览器也起作用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。