JavaScript的隐藏特性?

312

1
你是不是想说:“看到了那个问题吸引的声望和观点,我想问几乎完全相同的问题来提高自己的声望”?;-) - Bobby Jack
1
当然,悲观主义者。 :) 我考虑过将这个问题变成社区问题。此外,当你获得一定数量的积分后,所有的回报都会递减。 - Allain Lalonde
1
好的,看起来你并不“需要”声望!我猜我只是对C#这个问题有些困惑——它似乎并不是这个网站旨在解决的问题类型。 - Bobby Jack
3
是的,也许不是这样,但我发现答案中的知识非常棒。如果没有 Stack Overflow(SO),要让一般的 C# 程序员在一个地方接触到所有这些知识将会很难。玩耍多年才能获得同样的宝贵经验清单。 - Allain Lalonde
我喜欢这一系列的问题;我认为答案的“digg”式系统比论坛上的“+1”更好。更容易看出社区认为最重要的是什么。我相信这对于谷歌来说也是良好的链接诱饵! - Martin Clarke
7
我已经专业编写JavaScript 10年了,从这个帖子中我学到了一些东西。谢谢Alan! - Andrew Hedges
99个回答

373

你不需要为一个函数定义任何参数。你可以直接使用函数的arguments类数组对象。

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6

51
值得注意的是,访问参数对象相对较为昂贵 -- 最好的例子在Safari、Firefox和Chrome夜版中,仅仅引用arguments对象就会使调用函数变慢很多 -- 比如说,如果(false) arguments; 将会影响性能。 - olliej
48
同样地,arguments对象有一个“callee”属性,它指代当前函数本身。这使得使用匿名函数进行递归成为可能,很酷! - Vincent Robert
4
“f(x,y,z)”比“f([x,y,z])”更好看。 - Mark Cidade
3
@Nathan,“arguments”参数允许您弯曲和扭曲现有的函数,而无需知道参数。尝试在Google上搜索“Memoize Javascript”,您就能了解如何使用它。 - chakrit
16
请注意,"arguments.callee" 正在被弃用。 - ken
显示剩余5条评论

204

我可以引用道格拉斯·克罗克福德(Douglas Crockford)的优秀著作JavaScript高级程序设计中的大部分内容。

但是我只为你选取其中一个,那就是始终使用===!==而不是==!=

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

== 不具有传递性。如果您使用 ===,则对于所有这些语句,它将按预期返回 false。

Note:
- "==" 是相等比较运算符,在比较时会进行类型转换。 - "===" 是严格相等比较运算符,不会进行类型转换。

29
很遗憾许多人认为 Crockford 是无所不知的。虽然该家伙在大部分批评中都是正确的,但我不会像很多开发者那样毫无保留地支持他的观点。 - Jason Bunting
21
我同意Jason的警告。这本书本身非常有趣,也提供了很多好建议,但是DC过于自信他的做事方式是唯一正确的方式,其他任何方法都被视为“有缺陷”。如果你想看一些例子,请看他在JSLint Yahoo群组上的回应。 - Zilk
30
如果您对动态类型感到困惑并且只想要“真正”的相等,那么使用 === 而不是 == 是很好的建议。了解动态类型的人可以继续在我们知道需要强制转换的情况下使用 == ,例如 0 == '' 或 0 == '0'。 - thomasrutter
20
Well和===不涉及动态类型。 ==执行类型强制转换,这是一种不同的机制。如果你知道你想要将其转换为字符串/数字等,则应该明确进行转换。 - Rene Saarsoo
15
我认为==最令人害怕的部分是'\n\t\r ' == 0 => true... :D - sharat87
显示剩余10条评论

188

在 JavaScript 中,函数是一等公民:

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

使用函数式编程技术可以编写优雅的JavaScript代码

特别地,函数可以作为参数传递,例如Array.filter()接受一个回调函数:

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

您还可以声明一个“私有”函数,该函数仅存在于特定函数的范围内:

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}

3
在JavaScript中,有三种创建函数的方式:第一种是使用function关键字声明函数,例如:function sum(x, y, z){ return (x+y+z);};第二种是使用new Function()构造函数,例如:var sum = new Function("x", "y", "z", "return (x+y+z);");。 - Marius
6
“函数即数据”的概念在我的看法中绝对是非常受欢迎的。 - Jason Bunting
"new Function()" 和 "eval" 一样邪恶。不要使用。 - Nicolás
11
不确定这是否是隐藏功能......更像是核心功能。 - Claudiu
@Marius,Nicolas 在很少的情况下,您会想要使用new Function。虽然它比eval更好(您可以重复使用函数而不是每次解析代码,并且代码无法访问局部变量),但仍不建议使用(例如,它使调试更加困难)。 - Asaf
显示剩余2条评论

162
你可以使用 in 运算符检查一个对象是否存在某个键:
var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

如果您觉得对象文字太难看,您可以将其与无参数函数提示结合使用:
function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true

22
检查键是否存在的代码并不聪明,它只能检查键是否存在,而不能检查值是否存在。x in list; 之所以有效,是因为 x[1] != null,而不是因为值1存在。 - Armin Ronacher
1
我已经有一段时间没有使用这种技术了,所以我忘记了我以前实际上使用过对象字面量。感谢您的纠正。 - Mark Cidade
34
注意:in 运算符也会测试原型链!如果某人在 Object.prototype 上放了一个名为 '5' 的属性,第二个例子即使你调用 '5 in list(1, 2, 3, 4)' 也会返回 true...最好使用 hasOwnProperty 方法:list(1, 2, 3, 4).hasOwnProperty(5) 将返回 false,即使 Object.prototype 有属性 '5'。 - Martijn
3
为了获得最通用的解决方案,可以测试一个对象是否具有其自身的属性,即使它被命名为“hasOwnProperty”,您需要完全使用以下方式:Object.prototype.hasOwnProperty.call(object, name); - Kris Kowal
这个(连同hasOwnProperty)的最佳用途是在3状态检查中... queue[item] = false; 会使 (item in queue) === true,但仍保留 (queue[item] === false) ... 在某些情况下非常方便(而且看起来比使用hasOwnProperty更清晰)。 - chakrit
1
@Kris,除非有人覆盖Object.prototype.hasOwnProperty ;) - Nick

153

给变量赋默认值

您可以在赋值表达式中使用逻辑或运算符||来提供默认值:

var a = b || c;

如果bfalsy值(即nullfalseundefined0空字符串NaN),变量a将获得变量c的值,否则变量a将获得变量b的值。这在函数中经常很有用,当您想为参数提供默认值以防未被赋值时:
function example(arg1) {
  arg1 || (arg1 = 'default value');
}

在事件处理程序中的IE回退示例:

function onClick(e) {
    e || (e = window.event);
}

下面这些语言特性已经存在很长时间,所有JavaScript实现都支持它们,但直到ECMAScript第5版才被纳入规范: debugger语句 描述在:§ 12.15 debugger语句 此语句允许您通过编程方式在代码中放置断点:
// ...
debugger;
// ...

如果存在或处于活动状态的调试器,它将立即在该行上中断。
否则,如果调试器不存在或未激活,则此语句没有可观察的效果。 多行字符串字面量 描述在:§ 7.8.4 字符串字面量中。
var str = "This is a \
really, really \
long line!";

你必须小心,因为紧跟在\后面的字符必须是一个行终止符,如果在\后面有空格,代码看起来可能完全一样,但会引发SyntaxError


28
如果它被认为是false,而不是null,那么就不会这样。例如:a = 0 || 42; 将给你42。这类似于Python中的or运算符,而不是C#中的??运算符。如果你想要C#的行为,可以这样写:a = (b === null) ? c : b; - Armin Ronacher
如果你在ASP.NET上开发,它也可以在Visual Studio中使用 :) - chakrit
2
我希望有一个适用于未定义的合适的“||”运算符。今天我因为这个问题而受到了打击,因为我想创建一个模拟重载方法的功能,使得最后一个参数是可选的,并且可以使用默认值代替。 - egaga
这个技巧被默认的Google Analytics代码片段所使用。 var _gaq = _gaq || []; 它可以防止过于热心的用户覆盖自己的工作。 - Yahel
2
我不知道多行字符串字面量技术。太棒了,谢谢。 - Charlie Flowers

145

3
那是个好问题。这与大多数类C语言非常重要的区别。 - Martin Clarke
9
你可以始终使用"var tmp = function() { /* 块级作用域 */ }();"。这种语法看起来不太美观,但它是有效的。 - Joeri Sebrechts
3
如果仅限于 Firefox 浏览器,你也可以使用 "let"。参考链接:https://dev59.com/AnVD5IYBdhLWcg3wL4cA - Eugene Yokota
10
(function() { var x = 2; })(); alert(typeof x); //undefined这段代码定义了一个立即执行函数,函数中创建了一个变量x并赋值为2。但由于x是在函数内部声明的局部变量,所以在函数外部无法访问该变量,因此当使用typeof操作符检查变量类型时,返回的结果为undefined。 - Pim Jager
@Pim:JSLint说:“将调用移动到包含函数的括号中。”以及“在'function'和'('之间预期恰好有一个空格。” - Hello71
显示剩余3条评论

144

您可以使用[]而不是.来访问对象属性。

这允许您查找与变量匹配的属性。

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

您也可以使用此方法来获取/设置对象属性,其名称不是一个合法的标识符。

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

一些人不知道这一点,最终使用eval() 像这样,这是一个非常糟糕的想法:

var propname = "a";
var a = eval("obj." + propname);

这种方式更难阅读,更难发现错误(无法使用jslint),执行速度更慢,并且可能导致XSS攻击。


eval是邪恶的,虽然很少必要。 - Doug Domeny
我从不使用eval,并记得当我发现它时感到非常高兴。 - user55776
总之,对象属性可以通过点和下标符号访问。 - Russ Cam
9
有趣的是,点引用实际上是方括号引用的语法糖。根据规范,foo.bar 的行为与 foo["bar"] 相同。而且需要注意的是,所有内容都是字符串属性。即使进行数组访问 array[4],数字 4 也会被转换为字符串(至少根据 ECMAScript v3 规范如此)。 - Claudiu
我想每个JS程序员都应该知道这个。 - Cem Kalyoncu

144

如果您在Google上搜索关于某个JavaScript主题的良好参考资料,请在查询中包含“mdc”关键字,您的第一个结果将来自Mozilla开发者中心。我不带任何离线参考书或书籍。我总是使用“mdc”关键字技巧直接找到我要找的内容。例如:

谷歌:javascript array sort mdc
(在大多数情况下,您可以省略“javascript”)

更新: Mozilla开发者中心已更名为Mozilla开发者网络。 "mdc"关键字技巧仍然有效,但很快我们可能需要开始使用“mdn”


我们做了什么才配得上被链接到 LMGTFY... - MiseryIndex
50
哇,太棒了!比那个糟糕的W3Schools好多了... - DisgruntledGoat
11
如果你使用Firefox浏览器,你甚至不需要在谷歌上搜索,只需在地址栏中输入“array mdc”并按下回车键即可。 - Sasha Chedygov
2
最好的部分是这个堆栈溢出问题在搜索结果的第一页 :) - Jiaaro
5
关于这个:http://promotejs.com/,这是一个基层SEO倡议,旨在进一步提高MDC结果在Google搜索结果中的排名。 - Yahel
3
现在是MDN文档中心,因此'mdc'关键字仍然有效 :) - Aleadam

143

对于一些人来说可能有点显而易见...

安装 Firebug 并使用 console.log("hello")。这比使用随机的alert(); 要好得多,我记得几年前经常这样做。


12
发布代码之前,别忘了删除控制台语句,因为其他人可能没有安装Firebug。 - Chris Noe
4
更好的做法是在日志语句前加上 ";;;" 这个标记,然后使用 minify 工具就可以自动处理了。至少我使用的 Perl 模块有这个功能,并且声称这是常见的做法。 - Kev
10
Josh说:这样行不通,因为没有定义控制台。你可以检查typeof console !== "undefined"或者window.console。 - Eli Grey
23
始终包括: 如果 (typeof('console') == 'undefined') { console = { log: function() { } }; },然后你就可以继续使用 console.log,它什么也不会做。 - gregmac
1
或者更好的方法是:函数日志(msg){如果(控制台)控制台。log(msg)}否则警报(msg +“\n嘿!安装Firebug,这样您就不会收到这个烦人的消息!”);} - Jason S
显示剩余6条评论

120

私有方法

一个对象可以拥有私有方法。

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());

16
那并不是一个私有函数,更像是本地作用域内的函数变量。 - Keith
6
按照我能想到的所有操作定义,确实是这样一个方法。它是一段具有名称的代码块,可以访问实例状态,并且只能被该实例看到。你对私有方法的定义是什么? - Allain Lalonde
14
@Zach,完全正确!在使用基于类的面向对象语言工作多年后,很容易忘记它们只是面向对象概念的一种实现。当然,试图将准基于类的面向对象塞入JS的各种库也没有什么帮助... - Shog9
5
想知道一下,person1 是否有一篇法律博客?;-) - travis
4
感谢您的支持,这句话是对《逮捕令》剧集的引用赞赏。 - Dom M.
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接