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

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

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

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


当前回答

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

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

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);

其他回答

我可以引用道格拉斯·克罗克福德这本好书的大部分内容 JavaScript:好的部分。

但我只给你一个,总是使用===和!==而不是==和!=

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

==是不可传递的。如果你使用===,它会给出false for 所有这些陈述都符合预期。

你可以使用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

我知道我迟到了,但我只是无法相信+运算符的有用性除了“将任何东西转换为数字”之外没有被提及。也许这就是隐藏得有多好?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

当然,你也可以用Number()来代替,但是+运算符要漂亮得多!

您还可以通过重写原型的valueOf()方法为对象定义一个数值返回值。在该对象上执行的任何数字转换都不会导致NaN,而是valueOf()方法的返回值:

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;

也许其中一个不太为人所知:

arguments. called .caller + Function#toString()

function called(){
    alert("Go called by:\n"+arguments.callee.caller.toString());
}

function iDoTheCall(){
    called();
}

iDoTheCall();

打印出idocall的源代码—— 已弃用,但有时在警报是您唯一的选择时可能有用....

也许对某些人来说有点明显…

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