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

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

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

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


当前回答

正如Marius已经指出的,可以在函数中使用公共静态变量。

我通常使用它们来创建只执行一次的函数,或者缓存一些复杂的计算结果。

下面是我以前的“单例”方法的例子:

var singleton = function(){ 

  if (typeof arguments.callee.__instance__ == 'undefined') { 

    arguments.callee.__instance__ = new function(){

      //this creates a random private variable.
      //this could be a complicated calculation or DOM traversing that takes long
      //or anything that needs to be "cached"
      var rnd = Math.random();

      //just a "public" function showing the private variable value
      this.smth = function(){ alert('it is an object with a rand num=' + rnd); };

   };

  }

  return arguments.callee.__instance__;

};


var a = new singleton;
var b = new singleton;

a.smth(); 
b.smth();

如您所见,在这两种情况下构造函数都只运行一次。

For example, I used this approach back in 2004 when I had to create a modal dialog box with a gray background that covered the whole page (something like Lightbox). Internet Explorer 5.5 and 6 have the highest stacking context for <select> or <iframe> elements due to their "windowed" nature; so if the page contained select elements, the only way to cover them was to create an iframe and position it "on top" of the page. So the whole script was quite complex and a little bit slow (it used filter: expressions to set opacity for the covering iframe). The "shim" script had only one ".show()" method, which created the shim only once and cached it in the static variable :)

其他回答

闭包:

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已经分配了一个新值之后!

JavaScript的通用性-覆盖默认功能

下面是覆盖窗口的代码。使用jQuery UI的对话框小部件的警报功能。我把它作为一个jQuery插件来实现。你可以在我的博客上读到;altAlert,一个用于个性化警报消息的jQuery插件。

jQuery.altAlert = function (options)  
{  
    var defaults = {  
        title: "Alert",  
        buttons: {  
            "Ok": function()  
            {  
                jQuery(this).dialog("close");  
            }  
        }  
    };  

    jQuery.extend(defaults, options);  

    delete defaults.autoOpen;  

    window.alert = function ()  
    {  
        jQuery("<div />", {
            html: arguments[0].replace(/\n/, "<br />")
        }).dialog(defaults);  
    };  
};

函数l (f, n) {n&&l (n - 1 f, f (n));} L(函数(循环){警报(循环);}, 5);

警报5、4、3、2、1

除了公共成员外,还可以使用闭包创建具有私有(在“类”定义之外不可访问)静态成员和非静态成员的“类”。

注意,下面的代码中有两种类型的公共成员。特定于实例的(在构造函数中定义),可以访问私有实例成员,共享成员(在原型对象中定义)只能访问私有静态成员。

var MyClass = (function () {
    // private static
    var nextId = 1;

    // constructor
    var cls = function () {
        // private
        var id = nextId++;
        var name = 'Unknown';

        // public (this instance only)
        this.get_id = function () { return id; };

        this.get_name = function () { return name; };
        this.set_name = function (value) {
            if (typeof value != 'string')
                throw 'Name must be a string';
            if (value.length < 2 || value.length > 20)
                throw 'Name must be 2-20 characters long.';
            name = value;
        };
    };

    // public static
    cls.get_nextId = function () {
        return nextId;
    };

    // public (shared across instances)
    cls.prototype = {
        announce: function () {
            alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                  'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
        }
    };

    return cls;
})();

测试这段代码:

var mc1 = new MyClass();
mc1.set_name('Bob');

var mc2 = new MyClass();
mc2.set_name('Anne');

mc1.announce();
mc2.announce();

如果您有Firebug,您会发现除了在定义私有成员的闭包中设置断点之外,没有其他方法可以访问私有成员。

当定义需要严格验证值和完全控制状态更改的类时,这种模式非常有用。

要扩展这个类,你可以把MyClass.call(this);在扩展类的构造函数的顶部。您还需要复制MyClass。prototype对象(不要重用它,因为你也会改变MyClass的成员。

如果要替换announce方法,则需要调用MyClass。MyClass.prototype.announce.call(this);

知道一个函数需要多少个参数

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

知道函数接收了多少参数

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6