[译]Understanding javascript's 'undefined'

和其他言语比拟,javascript中的关于undefined的明白照样有点让人疑心的。迥殊是试着明白ReferenceErrors毛病(“x is not defined”)以及在编码过程当中怎样去防止这些毛病总让人以为比较疑心。

这篇文章是我整顿的关于这个知识点的内容。假如你关于javascript中的变量以及属性还不是很熟悉的话,你能够看看我之前写的[文章]()

undefined是什么?

Javascript中,存在着Undefined(基本范例),undefined(值),以及defedined(变量)

Undefined(基本范例)是js内置的基本范例之一(String, Number, Boolean, Null, Object)

undefined(值)是一个原始值,是未定义范例的基本值。任何未被赋值的属性值都能够假设为undefined。无返回值或许返回值为空的函数末了实行获得的值都未undefined。未设定的函数参数值也为undefined.

    var a;
    typeof a; // undefined
    
    window.b;
    typeof window.b; // undefined
    
    var c = (function() {})();
    typeof c; // undefined
    
    var d = (function(e) {return e})();
    typeof d; // undefined

undefined(变量)是初始值为undefined的全局属性,既然它是个全局属性,那末我们也能够经由过程变量来猎取它。比方我在这篇文章内里像如许将它作为一个变量来猎取它。

    typeof undefined; // undefined
    
    var f = 2;
    f = undefined;  //从新将变量f赋值为变量undefined
    typeof f; // undefined

在ECMA3当中,它的值能够从新被赋值:

    undefined = 'washing machine';
    typeof undefined;  // string
    
    f = undefined;
    typeof f; // string
    f; // 'washing machine'

不用说,将undefined从新赋值是一个比较蹩脚的用法。事实上再ECMA5当中这类做法也是不被许可的。

And then there’s null?

大致上我们相识这两者之间的区分,然则照样须要从新复述一遍:undefinednull比拟,undefined是一个原始值,它示意一个缺省值。undefinednull之间唯一相似的处所就是它们都能被经由过程范例转换成false

So what’s a RefernceError?

一个ReferenceError示意编译器检测到一个无效的援用值。

在实际状况中,ReferenceError往往是在Javascript猎取一个未被赋值的援用时被抛出。
注重下在差别浏览器中,ReferenceError如今的差别的语法毛病提醒信息。正如我们看到的,在差别浏览器中,毛病信息并不是迥殊的清晰清楚明了。

    alert(foo);
    
    //FF/Chrome: foo is not defined
    //IE: foo is undefined
    //Safari: can't find variable foo

Still not clear …”unresolvable reference”?

在ECMA规范中,一个援用值包括一个援用称号及一个基本值。

假如这个援用是一个属性,那末基本值及这个援用离别位于点号的两侧:

    window.foo; // base value = window, reference name = foo;
    a.b; //base value = a, reference name = b;
    myObj['create']; //base value = myObj, reference name = create;
    //Safari, Chrome, IE8+ only
    Object.defineProperty(window, 'foo', {value: 'hello'});
    //base value = window. reference name = foo;

关于援用变量来讲,基本值是当前实行上下文的变量对象。全局上线文的变量对象就是全局对象本身(浏览器当中是window)。任何一个函数上下文都有一个被称为运动对象的变量对象。(这个运动对象取决于挪用这个函数的实行context)

    var foo;    //base value = window, reference name = foo;
    function a() {
        var b;  // base value = <code>ActivationObject</code>, reference name = b;
    }

假如一个援用的基本值是undefined的话,那末这个援用就被以为unresolvable

因而,假如点号前面的值为undefined,那末这个属性援用就是unresolved。下面的这个例子就会抛出一个ReferenceError的毛病,然则这并不是是由于TypeError在此之前就被抛出。这是由于一个属性的基本值是属于CheckObjectCoercible,当试着将一个Undefined范例的转化为一个Object,那末这类状况下会抛出TypeError;

    var foo;    
    foo.bar;    //TypeError (base value, foo, is undefined)
    bar.baz;    //ReferenceError (bar is unresolvable)
    undefined.foo   //TypeError (base value is undefined)

假如运用var关键字,那末将会确保变量对象一直有基本值,那末就不会涌现援用变量unresolvable的状况。

当援用被定义的时刻既不是属性值也不是变量的时刻将会抛出一个ReferenceError:

    foo;   //ReferenceError

Javascript检测到援用名foo没有明白的基本值,因而就会去寻觅属性名为foo的变量对象。没有找到的话,就会以为援用名foo没有基本值并抛出ReferenceError的毛病。

But isn’t foo just a undeclared variable?

技术上来讲不是。只管有时刻我们以为undeclared variable是有应用我们去排查bug。然则事实上假如一个变量未被声明的话也就不是一个变量。

What about implicit globals?

未经由过程var关键字声明的标识符将会默许当作全局变量而被建立,但这只会在这些标识符被赋值的状况下才会见效。

    function a() {
        alert(foo);     // ReferenceError
        bar = [1, 2, 3]; // no error, bar is global
    }
    a();
    bar;    // [1, 2, 3]

这确切让人有点疑心。假如Javascript检测到unresolvable的援用就直接抛出ReferenceErrors就更好了。(事实上在严厉形式下javascript确切是如许做的)

When do I need to code against ReferenceErrors?

假如你的代码写的很合理。我们发如今典范的用法中只要一种体式格局会碰到unresolvable reference: 当运用属性或许变量的句法不正确的时刻。在大多数状况下,假如你能确保声明变量的时刻运用var关键字时即可防止这类状况。在代码运转过程当中唯一可能会碰到的状况就是援用的变量仅仅存在于部份浏览器或许第三方的代码当中。

一个比较好的例子就是console.在webkit浏览器中,console是内置的,console这个属性能够在任何处所猎取到。Firefoxconsole属性取决于Firebug是不是被装置以及被翻开运用。IE7下没有console,IE8下的console属性仅存在于IE Developer Tools被启动的状况下。Opera显著是有console属性的,然则我历来没用运用过。

末了的效果就是,下面的代码在浏览器中运转时照样有可能会抛出ReferenceError的毛病。

    console.log(new Date());

How do I code against variables that may not exist?

一种体式格局就是去经由过程运用typeof关键字去嗅探一个unresolvable reference,防止抛出ReferenceError毛病:

    if (typeof console != 'undefined') {
        console.log(new Date());
    }

但是这类要领对我来讲太烦琐了,更不用说合理了。我是比较阻挡运用typeof去举行范例检测的。

荣幸的是另有别的一种体式格局:我们已晓得基本值被定义了,然则属性未被定义是不会抛出ReferenceErrorconsole是全局对象的属性值,因而我们能够如许做:

    window.console && console.log(new Date());

事实上在全局环境下仅仅只须要检测变量是不是存在(函数中也存在着实行上下文,你能够决议哪些变量能够存在于你的函数当中)。因而理论上最少你能够防止运用typeof来消弭ReferenceError的状况。

原文链接

    原文作者:苹果小萝卜
    原文地址: https://segmentfault.com/a/1190000008032892
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞