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

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

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

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


当前回答

jQuery和JavaScript:

变量名可以包含许多奇数字符。我使用$字符来标识包含jQuery对象的变量:

var $links = $("a");

$links.hide();

jQuery的对象链接模式非常好,但是应用这个模式可能会让人有点困惑。幸运的是JavaScript允许你断行,就像这样:

$("a")
.hide()
.fadeIn()
.fadeOut()
.hide();

一般的JavaScript:

我发现通过使用自执行函数来模拟作用域很有用:

function test()
{
    // scope of test()

    (function()
    {
        // scope inside the scope of test()
    }());

    // scope of test()
}

其他回答

闭包的禅意

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

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

// 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

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

您还可以使用前面提到的原型链spoon16扩展(继承)类和重写属性/方法。

在下面的例子中,我们创建了一个类Pet并定义了一些属性。我们还重写了继承自Object的. tostring()方法。

在此之后,我们创建了一个Dog类,它扩展了Pet并重写了. tostring()方法,再次改变了它的行为(多态性)。此外,我们还向子类添加了一些其他属性。

在此之后,我们检查继承链以显示Dog仍然是Dog类型、Pet类型和Object类型。

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

这个问题的两个答案都是从Ray Djajadinata的一篇很棒的MSDN文章中修改的代码。

为变量分配默认值

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

var a = b || c;

只有当b为false (if为null, false, undefined, 0,空字符串或NaN)时,变量a才会得到c的值,否则a将得到b的值。

这通常在函数中很有用,当你想在没有提供参数的情况下给参数一个默认值:

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

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

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

以下语言特性已经伴随我们很长时间了,所有JavaScript实现都支持它们,但直到ECMAScript第5版才成为规范的一部分:

调试器语句

§12.15调试器语句描述

这个语句允许你通过以下方式在代码中添加断点:

// ...
debugger;
// ...

如果有调试器存在或处于活动状态,则会导致调试器立即在这一行上中断。

否则,如果调试器不存在或不活动,则此语句没有可观察到的效果。

多行字符串字面值

在§7.8.4字符串字面量中描述

var str = "This is a \
really, really \
long line!";

您必须小心,因为\旁边的字符必须是行结束符,例如,如果在\后面有空格,代码将看起来完全相同,但它将引发SyntaxError。

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

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

obj.prop2 = undefined;

for (var key in obj) {
    ...

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

delete obj.prop2;

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

JavaScript没有块作用域(但它有闭包,所以让我们称它为偶数?)

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2