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

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

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

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


当前回答

如果你盲目地eval()一个JSON字符串来反序列化它,你可能会遇到问题:

这并不安全。该字符串可能包含恶意函数调用! 如果你没有将JSON字符串括在括号中,属性名可能会被误认为是标签,导致意外的行为或语法错误: Eval ("{\"foo\": 42}");//语法错误:无效标签 Eval ("({\"foo\": 42})");/ /好吧

其他回答

我提交的第一个特性与其说是一个隐藏特性,不如说是一个很少使用的属性重定义特性应用程序。因为可以重新定义对象的方法,所以可以缓存方法调用的结果,这在计算开销很大且希望延迟求值的情况下非常有用。这是记忆的最简单形式。

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.area=function() {
            area = this.r * this.r * Math.PI;
            this.area = function() {return area;}
            return area;
        }
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

重构将结果缓存到方法中的代码,你会得到:

Object.prototype.cacheResult = function(name, _get) {
  this[name] = function() {
    var result = _get.apply(this, arguments);
    this[name] = function() {
      return result;
    }
    return result;
  };
};

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.cacheResult('area', function() { return this.r * this.r * Math.PI; });
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

如果你想要一个记忆函数,你可以用那个代替。不涉及属性重定义。

Object.prototype.memoize = function(name, implementation) {
    this[name] = function() {
        var argStr = Array.toString.call(arguments);
        if (typeof(this[name].memo[argStr]) == 'undefined') {
            this[name].memo[argStr] = implementation.apply(this, arguments);
        }
        return this[name].memo[argStr];
    }
};

注意,这依赖于标准数组toString转换,通常不能正常工作。解决这个问题留给读者练习。

第二个提交的是getter和setter。我很惊讶他们还没有被提及。因为官方标准不同于事实上的标准(defineProperty vs. define[GS]字母),而且Internet Explorer几乎不支持官方标准,所以它们通常没什么用。也许这就是他们没有被提及的原因。注意,你可以很好地结合getter和结果缓存:

Object.prototype.defineCacher = function(name, _get) {
    this.__defineGetter__(name, function() {
        var result = _get.call(this);
        this.__defineGetter__(name, function() { return result; });
        return result;
    })
};

function Circle(r) {
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  recalcArea: function() {
        this.defineCacher('area', function() {return this.r * this.r * Math.PI; });
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}

var unit = new Circle(1);
unit.area;

有效地组合getter, setter和结果缓存有点混乱,因为你必须防止在set上自动失效或不自动失效,这就是下面的例子所做的。如果改变一个属性会使其他多个属性失效,这是一个主要的问题(假设在这些示例中有一个“diameter”属性)。

Object.prototype.defineRecalcer = function(name, _get) {
  var recalcFunc;
  this[recalcFunc='recalc'+name.toCapitalized()] = function() {
    this.defineCacher(name, _get);
  };
  this[recalcFunc]();
  this.__defineSetter__(name, function(value) {
      _set.call(this, value);
      this.__defineGetter__(name, function() {return value; });
  });
};

function Circle(r) {
    this.defineRecalcer('area',
             function() {return this.r * this.r * Math.PI;},
             function(area) {this._r = Math.sqrt(area / Math.PI);},
    );
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}

函数在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]

你也可以声明一个“private”函数,它只存在于特定函数的作用域中:

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

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

我要说的是自执行函数。

(function() { alert("hi there");})();

因为Javascript没有块作用域,如果你想定义局部变量,你可以使用一个自执行函数:

(function() {
  var myvar = 2;
  alert(myvar);
})();

在这里,myvar不会干扰或污染全局作用域,并且在函数终止时消失。

Function.toString()(隐性):

function x() {
    alert("Hello World");
}
eval ("x = " + (x + "").replace(
    'Hello World',
    'STACK OVERFLOW BWAHAHA"); x("'));
x();