JavaScript未定义变量检测undefined null detection

HTML5自十多年前(2010年前后)被推举以来,逐渐大放异彩,尽管过去十年是属于Native APP的高光时刻,但HTML5的一些新特性和功能还是带来了大量的新网络/网页应用,尤其是在JavaScript的加持下,网页应用有极其令人着迷的便利与强大。

JavaScipt是网页应用默认编程语言,让人又爱又恨。

笔者曾经在《中国计算机学会通讯》上刊发了一篇看法文章《JavaScript或成主导的编程语言》( https://dl.ccf.org.cn/institude/institudeDetail?id=3738875941521408&_ack=1 ),其后两个开源项目 GTAjax ( https://ufqi.com/dev/gtajax )和 Hanjst ( https://ufqi.com/dev/hanjst/Hanjst.demo.html )又分别是使用JavaScript做了实现,甚至 Base62x( https://ufqi.com/dev/base62x/ ) 的编解码方法,都有JavaScript语言版本,可谓是JavaScript的重度用户、开发者。

即便如此“资深”,仍常常觉得JavaScript用起来让人不那么放心,为了写出更可靠的代码,我们甚至在JavaScript中显示地声明用严格检查模式: use strict.

即便如此“谨慎”,我们也会遇到 object/variable is null or undefined 的异常抛出,使得程序异常终止,为用户带来了很不好的体验。随着我们在 UfqiWork/有福工坊( https://ufqi.com/work ) 的开发推进,我们尝试寻找一种检测 JavaScript 变量或者对象是否null 或 undefined方法的努力,有了新收获,兹分享如下。

从JavaScript本身来说,要检测某个对象或变量是否为null/undefined,主要有两个工具可用: typeof 操作符 和 window.hasOwnProperty 方法。我们所创制的方法, 代码1,也是基于这两个基本操作。


//- _isDefined
//- @param: $var, to be tested;
//- @param: global_or_local: ‘global|local’, optional
//- return true | false
//- usage: test whether a global variable($var): _isDefined(“$var”) , _isDefined($var)
//- test a variable($var) declared nearby/locally: _isDefined($var) , _isDefined(“$var”, “local”)
function _isDefined($var, global_or_local){
var isDef = false;
if($var != null){
var myTp = typeof $var;
if(myTp == ‘string’){
if(window.hasOwnProperty($var)){
isDef = true;
}
else if(global_or_local != null && global_or_local == ‘local’){
isDef = true;
}
else{
//- @todo
}
}
else if(myTp != ‘undefined’){
isDef = true;
}
}
return isDef;
}


这些代码已经部署在 Hanjst/汉吉斯特, UfqiWork/有福工坊 相关模块中,经实测,运行良好,符合预期。

在编制这些代码之前,我们也曾经在多个应用中写了大量的检测某个JavaScript是否为null/undefined,无一例外地都是使用 typeof 或者 window.hasOwnProperty方法,甚至再带着对 null和 empty的判断。代码显得异常繁琐和臃肿。相信此后,这些代码将陆续得到简化和修正,新写的代码也将引入该功能 _isDefined .

在编制这些代码之前,我们也在网络上进行了 code review,翻阅了大量针对此问题的解决思路和办法,可能面对不同运行时环境,给出的解决方法也各个不同,实际上并没有一种方法可以通用到“放之四海而皆准”。

比如最接近本方法的一个尝试是定义一个 isDefined2, 代码2,然后在方法体内使用 typeof 操作符判断传入的 $var 是否 null/undefined , 以此来进行判断变量或者对象 $var 是否为 null/undefined .


//- _isDefined2,  WRONG!
//- @param: $var, to be tested
//- return true | false
function _isDefined2($var){
var isDef = false;
if(typeof $var != ‘undefined’){
isDef = true;
}
return isDef;
}


这段代码通常情况下,能够进行运行,并对一些变量实现null/undefined的探测。然而这个情况只局限在本地变量或者当前已经声明的变量,如果待探测的变量 $var 没有在 _isDefined2 调用之前被声明,则调用探测语句 _isDedined2($var) 本身就会报错说 $var is null/undefined .

问题进一步地被延申到 JavaScript的函数方法调用的参数传递是pass-by-value传值,还是 pass-by-reference传引用。通常情况下,JavaScript的方法调用都是 pass-by-value, 所以在执行语句  _isDefined($var) 时,先要对 $var 进行取值操作,而 $var 如果本身 undefined 时,悲剧错误就产生了,检测是否为 null/undefined 之前已经发生了 undefined .

当我们判断了 $var 为String类型的数据对象时,同时引发了另外一个问题,就是当某一个数据变量或对象其本身就是字符串时,如果其本身是一个本地变量,而String类型会被视为检测全局变量,这里就会发生异常错误,把本该返回本地变量为 true的结果,错误地解释为全局变量为 false。因此需要进一步地对方法本身做修正,使之能够兼容本地变量、String类型,改进的做法是针对 _isDefined 引入第二个参数,显示地告诉程序,当前虽然引入了 String类型的变量,但不是默认检测全局变量,而是要检测本地变量。

进一步地修正这个问题,我们创制了样例代码1. 可以兼容全局变量和本地变量,不管$var 是否被什么,都能够进行检测。只是,在调用的时候需要区分,待检测的变量或者对象是全局变量或者是局部变量:
如果是全局变量,调用方式是: _isDefined(“$var”) , _isDefined($var)
如果是局部变量,调用方法是: _isDefined($var, ‘local’) , _isDefined(“$var”, ‘local’) 

变量 $var 在被检测之前,我们能够知道它是全局变量或者局部变量吗?
答案应该是明确的。

测试样例:

var a;
console.log(“UfqiWork/Hanjst: a:”+_isDefined(a));
var b = null;
console.log(“UfqiWork/Hanjst: b:”+_isDefined(b));
var c = 0;
console.log(“UfqiWork/Hanjst: c:”+_isDefined(c));
console.log(“UfqiWork/Hanjst: global-c:”+_isDefined(“c”));
var dd = “d_string”;
console.log(“UfqiWork/Hanjst: local-dd:”+_isDefined(dd, ‘local’));
console.log(“UfqiWork/Hanjst: global-dd:”+_isDefined(dd));
console.log(“UfqiWork/Hanjst: global-dd:”+_isDefined(“dd”));
console.log(“UfqiWork/Hanjst: local-dd:”+_isDefined(“dd”, ‘local’));

预期输出:

UfqiWork/Hanjst: a:false
UfqiWork/Hanjst: b:false
UfqiWork/Hanjst: c:true
UfqiWork/Hanjst: global-c:false
UfqiWork/Hanjst: local-dd:true
UfqiWork/Hanjst: global-dd:false
UfqiWork/Hanjst: global-dd:false
UfqiWork/Hanjst: local-dd:true


Hanjst
Hanjst 汉吉斯特 Logo

🙋Hanjst汉吉斯特 是一种基于JavaScript的模板语言及模版解析引擎,她运行在客户端或服务器端。

🙋Hanjst汉吉斯特 能够表述逻辑控制,能够实现与服务器端模版语言相同的强大功能。

  • Hanjst当完全在客户端解析时,节省服务器端计算资源;

  • Hanjst模板语言独立,不与服务器端资源做任何绑定;

  • 纯粹的MVC,层间数据用JSON格式传递;

  • 常见模板语言功能全支持,附带复杂而强大的JavaScript编程能力;

  • 无学习成本,直接使用JavaScript书写模板语言;

  • ….

Hanjst is a JavaScript-based templating language and parsing engine that runs on both the client-side and/or server-side.

Hanjst can express logical controls and achieve the same functionalities as the server-side templating languages.

  • Hanjst’s Run-time in client-side, reduce computing render in server-side;

  • Hanjst is Language-independent, not-bound with back-end scripts or languages;

  • Totally-isolated between MVC, data transfer with JSON;

  • Full-support template tags with built-in logic and customized JavaScript functions;

  • No more tags languages to be learned, just JavaScript;

  • ….

此条目发表在-GTAjax, -Hanjst/-汉吉斯特, 编程技术, 计算机技术分类目录,贴了, , , , 标签。将固定链接加入收藏夹。

JavaScript未定义变量检测undefined null detection》有4条回应

  1. Wadelau说:

    改进版本:
    function _isDefined($var, global_or_local){
    var isDef = false;
    if($var != null && $var != undefined){
    var myTp = typeof $var;
    if(myTp == ‘string’){
    if(window.hasOwnProperty($var)){
    isDef = true;
    }
    else if(global_or_local != null && global_or_local == ‘local’){
    isDef = true;
    }
    else{
    if(myTp != ‘undefined’ && myTp != ‘null’){
    isDef = true;
    }
    else{
    console.log(“isDef: trapped? var:”+$var+” isDef:”+isDef);
    }
    }
    }
    else if(myTp != undefined && myTp != null){
    isDef = true;
    }
    }
    //console.log(“isDef: var:”+$var+” isDef:”+isDef);
    return isDef;
    }

  2. admin说:

    15.?.运算符
    ?.运算符这在有时候处理对象时非常有用,看下面案例,person.name返回undefined然后在调用toString这时肯定会报错,这时使用?.运算符就不会产生错误,?.运算符是只有在当值不是undefined时才会调用toString方法。

  3. admin说:

    14.??运算符
    ??运算符只有前面的值是undefined or null才会执行,工作中有的情况下使用,我们来看一下。
    let status = undefined;
    let text = status ?? “暂无”
    console.log(text) // 暂无

  4. Pingback引用通告: JavaScript未定义变量检测undefined null detection | -wordpress-wadelau

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code