Javascript编码实践:对象中的空值

Javascript编码实践:对象中的空值,javascript,coding-style,Javascript,Coding Style,只需阅读,然后思考我在自己的工作项目代码库中使用了什么 我编写了一个简单的函数来演示这个问题(使用Google Apps脚本,从而调用Logger.log()): 在过去的几个月里,我一直在用数千行代码构建一个系统,当我看到一个特定的值时,我经常会回溯到它,以记住它在一个特定的条件表达式之前的状态 因为我是编写代码的人,所以我不太难理解它,因为我知道数据的结构,应该存在的值,等等 然而,在我大学毕业后,这个系统将被另一个开发人员接管,因此我想知道,表示一个房产没有数据的最佳实践是什么 例如,我的

只需阅读,然后思考我在自己的工作项目代码库中使用了什么

我编写了一个简单的函数来演示这个问题(使用Google Apps脚本,从而调用
Logger.log()
):

在过去的几个月里,我一直在用数千行代码构建一个系统,当我看到一个特定的值时,我经常会回溯到它,以记住它在一个特定的条件表达式之前的状态

因为我是编写代码的人,所以我不太难理解它,因为我知道数据的结构,应该存在的值,等等

然而,在我大学毕业后,这个系统将被另一个开发人员接管,因此我想知道,表示一个房产没有数据的最佳实践是什么

例如,我的用例是我有
event
对象,这些对象用空数据初始化,并且在一个学期的生命周期内,最终用真实数据填充。就我个人而言,我使用
undefined
,因为读
if(typeof data==“undefined”)
对我来说更有意义,它的语义与“if this data is undefined”(即还没有值)类似

但我想知道,在工业界、图书馆和个人项目中,有哪些常用方法可以使代码更可读、更易懂?虽然前三个条件句的长度比后三个条件句长,但我发现后三个条件句很模糊

例如,
prop2
可以有一个非空的字符串,如
“data”
,或者值
true
,这将导致后一个条件
if(object.prop2)
两种情况下都计算为
true
,因为JavaScript中的所有内容都是真实的,除了以下内容:

  • 空的
  • 未定义
  • 空字符串(“”)
  • 0
  • 假的
数据完全可能有
0
false
作为有效值,而
null
未定义的
和(特别是)
NaN
可能不是真实数据的典型值

显然,我知道数据的结构,然后我们可能会实施更严格的检查来消除非空字符串与真字符串之间的歧义。但是在一个有数千行代码的项目中,我觉得这很快就会失控,尤其是当数据结构随着时间的推移而改变时


那么我的问题是:是否有一种首选的方法可以在Javascript中表示空值?这种偏好(性能、可读性、可伸缩性等)有什么特别的原因吗?

Javascript在
NaN
常量中尤其阴险:

alert(NaN==NaN?"isNaN":"isNotNaN"); // isNotNaN !
表示空对象最常用的方法是
null
常量。但是,使用它时可能会遇到问题:

var coords = null;
if(coords===null) alert("empty object");
if(coords.x==0 && coords.y==0) alert("[0,0]");
// Uncaught TypeError: Cannot read property 'x' of null
有一种设计模式称为:要创建一个表示
null
值并具有正确属性的对象:

var nullcoords = {x:-1,y:-1}; // null object
var coords = nullcoords;
if(coords===nullcoords) alert("empty coords");
if(coords.x==0 && coords.y==0) alert("[0,0]");
// no TypeError
正如罗布在评论中指出的那样,你可以接受这种态度

  • nullobject默认属性不是有效值
  • 默认值不会破坏您的操作
  • 但是,
    null
    对于coords属性不是一个好主意,因为它不是一个数字类型,并且可能会弄乱一些算术运算(但在JS中不是)。下面的代码是使用自定义空对象处理程序的更合适(更复杂)的解决方案:

    function nullCoordsHandler(obj) {
      // any error handling you want
      alert("setting default values...");
      obj.x = obj.y = 0;
    }
    
    function coords() {
      var _x, _y;
      var defined = false;
      Object.defineProperty(this,"x",{
        enumerable: true,
        get:function() { if(!defined) nullCoordsHandler(this); return _x; },
        set:function(value) { defined = true; _x = value; }
      });
      Object.defineProperty(this,"y",{
        enumerable: true,
        get:function() { if(!defined) nullCoordsHandler(this); return _y; },
        set:function(value) { defined = true; _y = value; }
      });
    };
    
    var c = new coords();
    if(c.x==0 && c.y==0) alert("[0,0]");
    // nullCoordsHandler was called to handle the null object situation
    

    这可能是一个意见问题,但就我个人而言,我会使用
    null
    ,轻松区分尚未定义的属性与尚未使用或设置的属性
    NaN
    可能是由于某些错误的数学计算失败而导致的,并且很难判断它来自何处(因为它会被视为空的)。另外,一个额外的好处是
    null
    只能在为已为null的属性分配变量或直接分配null时产生。你不能以任何其他方式获得null(除了可能通过
    eval('null')
    ,但这太不可能了)。我同意,这可能是一个意见问题——例如,我已经表达了我自己的观点!然而,我认为还有其他一些事情需要考虑。例如,如果某些操作失败/找不到数据,则返回空值:
    var split=“some,”.split(“,”)
    split[1]
    处的值为
    null
    ,根据系统的不同,该值可能是有效值。这就是为什么我倾向于
    未定义的
    ,因为它在语义上更有意义,而且像我刚才给出的示例中那样,随机冲突的可能性更小。我想知道这是否是共识…@ChrisCirefice实际上,
    split[1]===未定义的
    。另外,我也会使用
    null
    <代码>未定义
    用于未定义的属性。但是这些属性确实被定义了。。。没有价值。然后您应该使用
    null
    ,因为这是它的确切含义。@chrisciredice:您的观点是有效的,
    match()
    和一些DOM方法确实返回null,我已经忘记了。但其他几点仍然站得住脚。我认为你对这个问题考虑得太多了。您试图从特定值推断状态,但使用
    undefined
    时,您不知道这是因为它没有被分配值还是被分配了
    undefined
    值。只要将值设置为适合的值,并在阅读时处理它们。不要把国家当作一个问题。有趣的是。。。我不知道这种设计模式,在我的例子中,这正是我需要的方法。看起来我将不得不修改一些东西,但看起来这将清除我执行的许多荒谬的类型检查。虽然我应该补充一点,但这个对象并不意味着function nullCoordsHandler(obj) { // any error handling you want alert("setting default values..."); obj.x = obj.y = 0; } function coords() { var _x, _y; var defined = false; Object.defineProperty(this,"x",{ enumerable: true, get:function() { if(!defined) nullCoordsHandler(this); return _x; }, set:function(value) { defined = true; _x = value; } }); Object.defineProperty(this,"y",{ enumerable: true, get:function() { if(!defined) nullCoordsHandler(this); return _y; }, set:function(value) { defined = true; _y = value; } }); }; var c = new coords(); if(c.x==0 && c.y==0) alert("[0,0]"); // nullCoordsHandler was called to handle the null object situation