你认为每个程序员都应该知道哪些JavaScript“隐藏功能”?
在看过以下问题的优秀答案之后,我想是时候问一下JavaScript了。
虽然JavaScript现在可以说是最重要的客户端语言(只需询问谷歌),但令人惊讶的是,大多数Web开发人员很少欣赏它真正的强大之处。
你认为每个程序员都应该知道哪些JavaScript“隐藏功能”?
在看过以下问题的优秀答案之后,我想是时候问一下JavaScript了。
虽然JavaScript现在可以说是最重要的客户端语言(只需询问谷歌),但令人惊讶的是,大多数Web开发人员很少欣赏它真正的强大之处。
JavaScript中的时间戳:
// Usual Way
var d = new Date();
timestamp = d.getTime();
// Shorter Way
timestamp = (new Date()).getTime();
// Shortest Way
timestamp = +new Date();
Date.now()
- bennedich你可以使用左侧的 [] 分配本地变量。如果你想从一个函数中返回多个值而不创建一个不必要的数组,这将非常方便。
function fn(){
var cat = "meow";
var dog = "woof";
return [cat,dog];
};
var [cat,dog] = fn(); // Handy!
alert(cat);
alert(dog);
这是JS核心的一部分,但不知何故,直到今年我才意识到它。
function fn(){
return {cat:"喵喵",dog:"汪汪"}; // 很好用!
};
var snd = fn();
alert(snd.cat);
alert(snd.dog);
- PlynxJavascript中的所有对象都是实现为哈希表,因此它们的属性可以通过索引器进行访问,反之亦然。此外,您可以使用 for/in 运算符枚举所有属性:
var x = {a: 0};
x["a"]; //returns 0
x["b"] = 1;
x.b; //returns 1
for (p in x) document.write(p+";"); //writes "a;b;"
当你想从一个数组中删除一个元素时,可以使用delete运算符,如下所示:
var numbers = [1,2,3,4,5];
delete numbers[3];
//numbers is now [1,2,3,undefined,5]
正如您所看到的,该元素已被移除,但由于该元素被替换为undefined值,因此数组中留下了一个空洞。
因此,为了解决这个问题,不要使用delete,而是使用splice数组方法...如下:
var numbers = [1,2,3,4,5];
numbers.splice(3,1);
//numbers is now [1,2,3,5]
splice的第一个参数是数组中的序数[index],第二个参数是要删除的元素数量。这个主题中有几篇答案展示了如何通过其原型扩展Array对象。这是一个不好的想法,因为它会破坏for (i in a)
语句。
那么如果你在代码中没有使用for (i in a)
呢?这样做只有在你自己编写的代码是你运行的唯一代码时才可以,但在浏览器中这种情况并不太可能发生。如果人们开始像这样扩展他们的Array对象,Stack Overflow将开始充斥着一堆神秘的JavaScript错误。
详细信息请参见此处。
在一个函数中,你可以返回函数本身:
function showSomething(a){
alert(a);
return arguments.callee;
}
// Alerts: 'a', 'b', 'c'
showSomething('a')('b')('c');
// Or what about this:
(function (a){
alert(a);
return arguments.callee;
})('a')('b')('c');
我不知道什么时候它会有用,但无论如何,这很奇怪而有趣:
var count = function(counter){
alert(counter);
if(counter < 10){
return arguments.callee(counter+1);
}
return arguments.callee;
};
count(5)(9); // Will alert 5, 6, 7, 8, 9, 10 and 9, 10
JavaScript 中 Date() 的工作方式让我非常兴奋!
function isLeapYear(year) {
return (new Date(year, 1, 29, 0, 0).getMonth() != 2);
}
这是一个真正的“隐藏功能”。
编辑:根据评论建议,删除了“?”条件以符合政治正确性。之前是:... new Date(year, 1, 29, 0, 0).getMonth() != 2 ? true : false ... 请查看评论了解详细信息。
cond ? true : false
(或反之)而没有注意到那是多么愚蠢的事情。 - Konrad Rudolph!(year % 4 != 0 || (year % 100 == 0 && year % 400 != 0))
。 - dolmen我最喜欢的技巧是使用apply
来执行一个对象的方法并保持正确的"this"变量。
function MakeCallback(obj, method) {
return function() {
method.apply(obj, arguments);
};
}
var SomeClass = function() {
this.a = 1;
};
SomeClass.prototype.addXToA = function(x) {
this.a = this.a + x;
};
var myObj = new SomeClass();
brokenCallback = myObj.addXToA;
brokenCallback(1); // Won't work, wrong "this" variable
alert(myObj.a); // 1
var myCallback = MakeCallback(myObj, myObj.addXToA);
myCallback(1); // Works as expected because of apply
alert(myObj.a); // 2
闭包的禅意
其他人已经提到了闭包。但是令人惊讶的是,有很多人知道有关闭包的知识、使用闭包编写代码,但仍然对闭包的真正含义存在误解。有些人将一级函数与闭包混淆。而另一些人则将其视为静态变量的一种形式。
对我来说,闭包就是一种类似于“私有”全局变量的东西。也就是说,某些函数将其视为全局变量,而其他函数则无法访问它。虽然这样描述底层机制可能有些不严谨,但它的行为和感觉就是如此。下面是一个例子:
// Say you want three functions to share a single variable:
// Use a self-calling function to create scope:
(function(){
var counter = 0; // this is the variable we want to share;
// Declare global functions using function expressions:
increment = function(){
return ++counter;
}
decrement = function(){
return --counter;
}
value = function(){
return counter;
}
})()
现在,三个函数increment
、decrement
和value
共享变量counter
,而不需要counter
成为实际的全局变量。这就是闭包的真正本质:
increment();
increment();
decrement();
alert(value()); // will output 1
上面的示例并不是一个真正有用的闭包用法。事实上,我会说以这种方式使用它是一种反模式。但它在理解闭包的本质方面是有用的。例如,当大多数人尝试执行以下操作时,他们会陷入困境:
for (var i=1;i<=10;i++) {
document.getElementById('span'+i).onclick = function () {
alert('this is span number '+i);
}
}
// ALL spans will generate alert: this span is span number 10
这是因为他们不理解闭包的本质。他们认为他们将i
的值传递给函数,而实际上函数共享一个单一的变量i
。就像我之前说的,这是一种特殊的全局变量。
要解决这个问题,您需要“分离”*闭包:
*原文中使用了斜体,此处翻译为中文的“分离”。
function makeClickHandler (j) {
return function () {alert('this is span number '+j)};
}
for (var i=1;i<=10;i++) {
document.getElementById('span'+i).onclick = makeClickHandler(i);
}
// this works because i is passed by reference
// (or value in this case, since it is a number)
// instead of being captured by a closure
*注意:我不知道这里的正确术语。
以下是一些快捷方式:
var a = []; // equivalent to new Array()
var o = {}; // equivalent to new Object()