你认为每个程序员都应该知道JavaScript的哪些“隐藏特性”?

在看到以下问题的优质答案后,我认为是时候向JavaScript请求它了。

HTML的隐藏特性 CSS的隐藏特性 PHP的隐藏特性 ASP的隐藏特性。网 c#的隐藏特性 Java的隐藏特性 Python的隐藏特性

尽管JavaScript可以说是目前最重要的客户端语言(问问谷歌就知道了),但令人惊讶的是,大多数web开发人员很少意识到它的强大。


当前回答

闭包:

function f() { 
    var a; 
    function closureGet(){ return a; }
    function closureSet(val){ a=val;}
    return [closureGet,closureSet];
}

[closureGet,closureSet]=f(); 
closureSet(5);
alert(closureGet()); // gives 5

closureSet(15);
alert(closureGet()); // gives 15

这里的闭包并不是所谓的解构赋值([c,d] =[1,3]等价于c=1;d=3;)但事实上,在closureGet和closurereset中出现的a仍然指向同一个变量。即使在closureSet已经分配了一个新值之后!

其他回答

要正确地从对象中删除一个属性,你应该删除该属性,而不是仅仅将其设置为undefined:

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

prop2属性仍然是迭代的一部分。如果你想完全摆脱prop2,你应该这样做:

delete obj.prop2;

在遍历属性时,prop2属性将不再出现。

这是jQuery的一个隐藏特性,而不是Javascript,但因为永远不会有“jQuery的隐藏特性”的问题……

你可以在jQuery中定义自己的:something选择器:

$.extend($.expr[':'], {
  foo: function(node, index, args, stack) {
    // decide if selectors matches node, return true or false
  }
});

对于使用:foo的选择,例如$('div.block:foo("bar,baz") span'),函数foo将被用于匹配选择器中已经处理的部分的所有节点。论证的意义:

node holds the current node index is the index of the node in the node set args is an array that is useful if the selector has an argument or multiple names: args[0] is the whole selector text (e.g. :foo("bar, baz")) args[1] is the selector name (e.g. foo) args[2] is the quote character used to wrap the argument (e.g. " for :foo("bar, baz")) or an empty string if there is no quoting (:foo(bar, baz)) or undefined if there is no argument args[3] is the argument, including any quotes, (e.g. "bar, baz") or undefined if there are no arguments stack is the node set (an array holding all nodes which are matched at that point)

如果选择器匹配,函数将返回true,否则返回false。

例如,下面的代码将支持基于全文regexp搜索选择节点:

$.extend($.expr[':'], {
  matches: function(node, index, args, stack) {
    if (!args.re) { // args is a good place for caching
      var re = args[3];
      if (args[2]) { // get rid of quotes
        re = re.slice(1,-1);
      }
      var separator = re[0];
      var pos = re.lastIndexOf(separator);
      var modifiers = re.substr(pos+1);
      var code = re.substr(1, pos-1);
      args.re = new RegExp(code, modifiers);
    }
    return $(node).text().match(args.re);
  }
});

// find the answers on this page which contain /**/-style comments
$('.answer .post-text code:matches(!/\\*[\\s\\S]*\\*/!)');

使用.filter()的回调版本也可以达到类似的效果,但自定义选择器要灵活得多,通常可读性也更好。

闭包的禅意

其他人也提到了关闭。但令人惊讶的是,有那么多人知道闭包,使用闭包编写代码,但仍然对闭包的真正含义有错误的认识。有些人混淆了一级函数和闭包。但也有人认为它是一种静态变量。

对我来说,闭包是一种“私有”全局变量。这是一种变量,一些函数将其视为全局变量,而其他函数则看不到。现在,我知道这是在快速和松散地描述底层机制,但这就是它的感觉和行为。说明:

// 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;
    }
})()

现在,增量、减量和值这三个函数共用一个变量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

*注:我不知道这里的正确术语。

您可以根据异常的类型捕获异常。引自MDC:

try {
   myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
   // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
   // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
   // statements to handle EvalError exceptions
} catch (e) {
   // statements to handle any unspecified exceptions
   logMyErrors(e); // pass exception object to error handler
}

注意:条件捕获子句是Netscape(因此也是Mozilla/Firefox)扩展,它不是ECMAScript规范的一部分,因此不能依赖于特定的浏览器。

还有一个几乎不为人知的JavaScript语法:

var a;
a=alert(5),7;
alert(a);    // alerts undefined
a=7,alert(5);
alert(a);    // alerts 7

a=(3,6);
alert(a);    // alerts 6

更多信息请点击这里。