精华内容
下载资源
问答
  • 7个处理JavaScript值为undefined的技巧

    千次阅读 2020-07-24 10:00:00
    原文 |https://dmitripavlutin.com/7-tips-to-handle-undefined-in-javascript/译文 |https://www.zcf...

    原文 | https://dmitripavlutin.com/7-tips-to-handle-undefined-in-javascript/

    译文 | https://www.zcfy.cc/article/7-tips-to-handle-undefined-in-javascript-dmitri-pavlutin

    我刚刚开始学习JavaScript时,大约是八年前,当时我对于undefined 和 null 比较困惑 ,因为他们都表示空值。

    他们有什么明确的区别吗?他们似乎都可以定义一个空值,而且 当你进行 在做null ===undefined 的比较时,结果是true。

    现在的大多数语言,像Ruby, Python or Java,他们有一个单独的空值(nil 或 null),这视乎才是一个合理的方式。

    而在JavaScript里,当你要获取一个变量或对象(未初始化)的值时,js引擎会返回 undefined。

    let company;company;    // => undefinedlet person = { name: 'John Smith' };person.age; // => undefined
    

    另一方面,对象引用错误会返回null。JavaScript本身并不会给将变量或者对象属性的值设为 null。

    一些js原生的方法会返回null,比如string.prototypt.match() 参数不是对象时,会返回null,来表示对象缺失。

    let array = null;array;                // => nulllet movie = { name: 'Starship Troopers',  musicBy: null };movie.musicBy;        // => null'abc'.match(/[0-9]/); // => null  
    

    由于JavaScript的宽容特性,开发人员有访问未初始化值的诱惑。我也犯了这种不好的做法。

    通常这种冒险行为会产生“未定义”的相关错误,从而快速结束脚本。相关的常见错误消息是:

    • TypeError:'undefined'不是函数

    • TypeError:无法读取未定义的属性'<prop-name>''

    • 和类似type errors

    JavaScript开发能够理解这个笑话:

    function undefined() {  // problem solved}
    

    为了减少这种错误的风险,您必须了解产生“undefined”时的情况。 

    更重要的是抑制其外观并在应用程序中传播,从而提高代码的耐用性。

    我们来详细探讨undefined及其对代码安全的影响。

    1、 什么是undefined

    JavaScript 的 6 基本类型:

    • Boolean: true or false

    • Number: 1, 6.7, 0xFF

    • String: "Gorilla and banana"

    • Symbol: Symbol("name") (starting ES2015)

    • Null: null

    • Undefined: undefined.

    And a separated object type: {name: "Dmitri"}, ["apple", "orange"].

    从6个基本类型undefined是一个特殊的值,它的类型为Undefined。根据[ECMAScript规范](https://www.ecma-international.org/ecma-262/7.0/#sec-undefined-value):

    未定义的值原始值在变量未被赋值时使用。

    该标准明确规定,在访问未初始化的变量,不存在的对象属性,不存在的数组元素等时,您将收到未定义的值。 

    例如:Try in repl.it

    let number;number;     // => undefined
    let movie = { name: 'Interstellar' };movie.year; // => undefined
    let movies = ['Interstellar', 'Alexander'];movies[3];  // => undefined  
    

    ECMAScript规范定义了“未定义”值的类型:

    未定义类型是唯一值为“未定义”值的类型。

    typeof undefined === 'undefined'; // => true
    
    let nothing;typeof nothing === 'undefined';   // => true  
    

    2、 创建未定义的常见场景

    2.1 未初始化的变量

    一个尚未赋值的声明变量( uninitialized )默认为undefined。

    Plain and simple:

    let myvariable;myvariable; // => undefined  
    

    解决未初始化变量问题的一种有效方法是尽可能分配一个初始值_。 

    变量在未初始化状态下存在的越少越好。理想情况下,您可以在声明`const myvariable ='初始值'后立即分配一个值,但这并非总是可行。

    Tip 1: 赞成const,否则使用let,但是告别var

    在我看来,ECMAScript 2015的最佳功能之一是使用const和let声明变量的新方法。这是一个很大的进步,这些声明是块范围的(与旧函数作用域var相反)并存在于[暂时死区](https://rainsoft.io/variables-lifecycle-and-why-let- 没有被吊起/#5letvariableslifecycle)直到宣告行。

    当变量只接收一个值时,我建议使用const声明。 

    它创建一个[不可变绑定](https://mathiasbynens.be/notes/es6-const)。

    const的一个很好的特性是 - 你必须给初始值赋予变量const myvariable ='initial'。变量不会暴露于未初始化的状态,并且访问undefined根本不可能。

    让我们检查一下验证单词是否是回文的函数:

    function isPalindrome(word) {  const length = word.length;  const half = Math.floor(length / 2);  for (let index = 0; index `< half; index++) {    if (word[index] !== word[length - index - 1]) {      return false;    }  }  return true;}isPalindrome('madam'); // =>` trueisPalindrome('hello'); // => false  
    


    var声明的问题是整个函数范围内的[变量提升](https://rainsoft.io/javascript-hoisting-in-details/#hoistingandvar)。 

    你可以在函数范围的末尾声明一个var变量,但是它仍然可以在声明之前被访问:并且你会得到一个undefined。

    function bigFunction() {  // code...  myvariable; // => undefined  // code...  var myVariable = 'Initial value';  // code...  myVariable; // => 'Initial value'}bigFunction();
    

    相反,在声明行之前不能访问let(包括const)变量。发生这种情况是因为该变量在声明之前处于[暂时死区](https://rainsoft.io/variables-lifecycle-and-why-let-is-not-hoisted/#5letvariableslifecycle)中。 

    这很好,因为你访问undefined的机会较少。

    上面的例子用let改写后,会出错。

    function bigFunction() {  // code...  myVariable; // => Throws 'ReferenceError: myVariable is not defined'  // code...  let myVariable = 'Initial value';  // code...  myVariable; // => 'Initial value'}bigFunction();  
    

    Tip 2: 增强内聚性

    [Cohesion](https://en.wikipedia.org/wiki/Cohesion_(computer_science))描述了模块(命名空间,类,方法,代码块)的元素所属的程度。 内聚的测量通常被描述为高内聚或低内聚_。

    高内聚是最好的,因为它建议设计模块的元素只专注于单个任务。它使模块:

    • Focused and understandable: easier to understand what the module does

    • 功能单一且容易理解

    • Maintainable and easier to refactor: the change in the module affects fewer modules

    • 易于维护和复用

    • Reusable: being focusing on a single task, it makes the module easier to reuse

    • 重复利用

    • Testable: you would easier test a module that's focused on a single task

    • 易于测试


    高内聚力伴随[松耦合](https://en.wikipedia.org/wiki/Loose_coupling)是设计良好的系统的特点。

    一个代码块本身可能被认为是一个小模块。为了从高内聚的好处中受益,您需要尽可能使变量尽可能靠近使用它们的代码块。

    例如,如果一个变量完全存在以形成块范围的逻辑,则声明并允许该变量仅存在于该块内(使用const或let声明)。不要将这个变量暴露给外部块作用域,因为外部块不应该关心这个变量。

    不必要的扩展变量生命周期的一个典型例子是在函数内使用for循环:

    function someFunc(array) {  var index, item, length = array.length;  // some code...  // some code...  for (index = 0; index < length; index++) {    item = array[index];    // some code...  }  return 'some result';}
    

    index,item和length变量在函数体的开头声明。然而,它们只用于接近尾声。那么这种方法有什么问题?

    在顶部的声明和for语句中的用法之间,变量index,item都是未初始化的并且暴露给undefined。它们在整个功能范围内的生命周期不合理。

    更好的方法是将这些变量尽可能靠近他们的使用地点:

    function someFunc(array) {  // some code...  // some code...  const length = array.length;  for (let index = 0; index `< length; index++) {    const item = array[index];    // some  }  return 'some result';}
    

    为什么修改后的版本比最初版本更好?让我们来看看:

    • 变量不会暴露于未初始化的状态,因此您没有访问未定义的风险

    • 尽可能将变量移动到它们的使用地点增加了代码的可读性

    • 高度连贯的代码块在需要时更容易重构并提取为分离的函数

    2.2 访问不存在的属性

    When accessing a **non-existing object property**, JavaScript returnsundefined`. 当访问不再的属性时,会返回undefined

    看例子:

    let favoriteMovie = {  title: 'Blade Runner'};favoriteMovie.actors; // => undefined
    

    本身访问不存在的属性不会引发错误。尝试从不存在的属性值获取数据时出现真正的问题。这是最常见的undefined相关陷阱,反映在众所周知的错误消息'TypeError:Can not read property<prop>of undefined`中。

    让我们稍微修改前面的代码片段来说明一个“TypeError”抛出:

    let favoriteMovie = {  title: 'Blade Runner'};favoriteMovie.actors[0];// TypeError: Cannot read property '0' of undefined
    

    允许访问不存在的属性的JavaScript的宽容性质是混淆的来源:该属性可能被设置,或者可能不是。绕过这个问题的理想方法是限制对象始终定义它所拥有的属性。

    不幸的是,您经常无法控制您使用的对象。这些对象在不同情况下可能具有不同的属性集。所以你必须手动处理所有这些场景。

    让我们实现一个函数append(array,toAppend),它在数组的开始和/或结尾添加新的元素。toAppend参数接受一个具有属性的对象:

    • first: element inserted at the beginning of array

    • last: element inserted at the end of array.

    function append(array, toAppend) {  const arrayCopy = array.slice();  if (toAppend.first) {    arrayCopy.unshift(toAppend.first);  }  if (toAppend.last) {    arrayCopy.push(toAppend.last);  }  return arrayCopy;}append([2, 3, 4], { first: 1, last: 5 }); // => [1, 2, 3, 4, 5]append(['Hello'], { last: 'World' });     // => ['Hello', 'World']append([8, 16], { first: 4 });            // => [4, 8, 16]  
    
    append([10], { first: 0, last: false }); // => [10]
    

    下面的提示解释了如何正确检查属性是否存在。

    Tip 3: 检查属性是否存在

    幸运的是,JavaScript提供了很多方法来确定对象是否具有特定属性:

    *obj.prop!== undefined:直接与undefined进行比较

    • typeof obj.prop!=='undefined':验证属性值的类型 *obj.hasOwnProperty('prop'):验证对象是否拥有自己的属性

    • obj`中的'prop':验证对象是否有自己的或继承的属性

    我的建议是使用in运算符。它有一个简短而甜美的语法。in操作符存在意味着明确的目的是检查对象是否具有特定的属性,而不访问实际的属性值。

    ![不要写var,写const并在JavaScript中放置](https://p0.ssl.qhimg.com/t010effea86a232d8a4.png)

    obj.hasOwnProperty('prop')也是一个不错的解决方案。它比in运算符略长,并且只在对象自己的属性中进行验证。

    涉及与'undefined'比较的两种方式可能会起作用......但在我看来obj.prop!== undefined和typeof obj.prop!=='undefined`看起来冗长而怪异,并且暴露直接处理undefined的怀疑路径。

    让我们使用in运算符来改进append(array,toAppend)函数:

    function append(array, toAppend) {  const arrayCopy = array.slice();  if ('first' in toAppend) {    arrayCopy.unshift(toAppend.first);  }  if ('last' in toAppend) {    arrayCopy.push(toAppend.last);  }  return arrayCopy;}append([2, 3, 4], { first: 1, last: 5 }); // => [1, 2, 3, 4, 5]append([10], { first: 0, last: false });  // => [0, 10, false]
    

    Tip 4: 用对象结构的方式访问对象的属性

    访问对象属性时,如果该属性不存在,有时需要指示默认值。

    你可以使用in伴随着三元运算符来实现:

    const object = { };const prop = 'prop' in object ? object.prop : 'default';prop; // => 'default'
    

    当要检查的属性数量增加时,三元运算符语法的使用会变得艰巨。对于每个属性,你必须创建一个新的代码行来处理默认值,增加类似外观的三元运算符的丑陋墙。

    为了使用更优雅的方法,让我们熟悉称为object destructuring的一个伟大的ES2015功能。[对象解构](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring)允许直接将对象属性值直接提取到变量中,并设置默认值if 该属性不存在。

    避免直接处理undefined的简便语法。

    事实上,现在的属性解析看起来简短且明了:

    const object = {  };const { prop = 'default' } = object;prop; // => 'default'  
    

    为了看到实际情况,让我们定义一个有用的函数,将字符串包装在引号中。quote(subject,config)接受第一个参数作为要包装的字符串。第二个参数config是一个具有以下属性的对象:

    char:引号字符,例如 (单引号)或(双引号),默认为`。 skipIfQuoted:如果字符串已被引用,则跳过引用的布尔值。默认为true。

    应用对象解构的好处,让我们实现反引号的使用:

    function quote(str, config) {  const { char = '"', skipIfQuoted = true } = config;  const length = str.length;  if (skipIfQuoted      && str[0] === char      && str[length - 1] === char) {    return str;  }  return char + str + char;}quote('Hello World', { char: '*' });        // => '*Hello World*'quote('"Welcome"', { skipIfQuoted: true }); // => '"Welcome"'
    ```const {char =''',skipIfQuoted = true} = config`解构赋值在一行中从`config`对象中提取属性`char`和`skipIfQuoted`如果某些属性在`config`对象中不可用, 解构赋值将默认值设置为:''''''为'char','false'为'skipIfQuoted`。
    幸运的是,该功能还有改进的空间。让我们将解构赋值移到参数部分。并为`config`参数设置一个默认值(一个空对象`{}`),以在默认设置足够时跳过第二个参数。
    [Try in repl.it](https://repl.it/HK1b/0)
    ```javascriptfunction quote(str, { char = '"', skipIfQuoted = true } = {}) {  const length = str.length;  if (skipIfQuoted      && str[0] === char      && str[length - 1] === char) {    return str;  }  return char + str + char;}quote('Hello World', { char: '*' }); // => '*Hello World*'quote('Sunny day');                  // => '"Sunny day"'  
    

    请注意,解构赋值将替换函数签名中的“config”参数。我喜欢这样:quote()变成一行更短。在解构赋值右侧的= {}确保在第二个参数没有在quote('Sunny day')`中被指定时使用空对象。

    对象解构是一个强大的功能,可以有效地处理从对象中提取属性。我喜欢在访问的属性不存在时指定要返回的默认值的可能性。因此,避免了“未定义”以及与处理它有关的问题。

    Tip 5: 用默认属性填充对象

    如果不需要像解构分配那样为每个属性创建变量,则缺少某些属性的对象可以用缺省值填充。

    ES2015Object.assign(target,source1,source2,...)将所有可枚举属性的值从一个或多个源对象复制到目标对象中。该函数返回目标对象。

    例如,您需要访问unsafeOptions对象的属性,该属性并不总是包含其全部属性。

    为了在unsafeOptions中访问一个不存在的属性时避免undefined,让我们做一些调整:

    • 定义一个保存默认属性值的对象defaults

    • 调用Object.assign({},defaults,unsafeOptions)来构建一个新的对象options。新对象接收来自unsafeOptions的所有属性,但缺少的属性来自defaults。

    const unsafeOptions = {  fontSize: 18};const defaults = {  fontSize: 16,  color: 'black'};const options = Object.assign({}, defaults, unsafeOptions);options.fontSize; // => 18options.color;    // => 'black'  
    

    Object.assign()将第一个参数作为目标对象{}。目标对象从unsafeOptions源对象接收fontSize属性的值。并且来自defaults源对象的color属性的值,因为unsafeOptions不包含color。枚举源对象的顺序很重要:稍后的源对象属性将覆盖先前的对象属性。

    您现在可以安全地访问options对象的任何属性,包括最初在unsafeOptions中不可用的options.color。

    幸运的是,使用默认属性填充对象的方式更简单轻松。我建议使用一个新的JavaScript特性(现在在[stage 3](https://tc39.github.io/process-document/)),它允许[在对象初始化器中传播属性](https://github.com/ TC39/提议对象,其余的扩展)。

    代替Object.assign()调用,使用对象扩展语法将来自源对象的所有属性和可枚举属性复制到目标对象中:

    const unsafeOptions = {  fontSize: 18};const defaults = {  fontSize: 16,  color: 'black'};const options = {  ...defaults,  ...unsafeOptions};options.fontSize; // => 18options.color;    // => 'black'
    
    

    对象初始值设定项从defaults和unsafeOptions源对象传播属性。指定源对象的顺序很重要:稍后的源对象属性会覆盖先前的对象属性。

    使用默认属性值填充不完整的对象是使代码安全和稳定的有效策略。不管情况如何,对象总是包含全部属性:'undefined'不能生成。

    2.3 函数的参数

    函数参数默认默认为undefined。

    通常,应使用相同数量的参数调用使用特定数量的参数定义的函数。在这种情况下,这些参数将获得您期望的值:

    function multiply(a, b) {  a; // => 5  b; // => 3  return a * b;}multiply(5, 3); // => 15  
    

    当您在调用中省略参数时会发生什么?函数内部的参数变成undefined。

    让我们稍微修改前面的例子,只用一个参数调用函数:

    function multiply(a, b) {  a; // => 5  b; // => undefined  return a * b;}multiply(5); // => NaN  
    

    Tip 6: 给参数默认值

    有时函数不需要调用的全套参数。可以简单地为没有值的参数设置默认值。

    看例子:

    function multiply(a, b) {  if (b === undefined) {    b = 2;  }  a; // => 5  b; // => 2  return a * b;}multiply(5); // => 10
    
    

    The function is invoked with a single argument multiply(5). Initially a parameter is 2 and b is undefined. The conditional statement verifies whether b is undefined. If it happens, b = 2 assignment sets a default value.

    尽管提供了分配默认值的方式,但我不建议直接比较'undefined'。它很冗长,看起来像一个黑客。

    更好的方法是使用ES2015 [默认参数](https://www.sitepoint.com/es6-default-parameters/)功能。 它很短,很有表现力,并且与'undefined`没有直接的对比。

    例子修改,添加默认值:

    function multiply(a, b = 2) {  a; // => 5  b; // => 2  return a * b;}multiply(5);            // => 10multiply(5, undefined); // => 10  
    

    ES2015的默认参数功能非常直观和高效。始终使用它来为可选参数设置默认值。

    2.4 函数返回值

    隐式地,没有return语句,JavaScript函数返回undefined。

    在JavaScript中,没有任何return语句的函数隐式地返回undefined:

    function square(x) {  const res = x * x;}square(2); // => undefined  
    

    square()函数不返回任何计算结果。函数调用结果是'未定义的'。

    当return语句存在时会发生同样的情况,但是附近没有表达式:

    function square(x) {  const res = x * x;  return;}square(2); // => undefined  
    

    return;语句被执行,但它不返回任何表达式。调用结果也是undefined。

    当然,在'return'附近表示要返回的表达式按预期工作:

    function square(x) {  const res = x * x;  return res;}square(2); // => 4  
    

    Tip 7: 不要相信自动分号插入

    以下JavaScript语句列表必须以分号(;)结尾:

    • 空的陈述

    • let,const,var,import,export声明

    • 表达式语句

    • 调试器语句

    • 继续语句,break语句

    • 抛出声明

    • return语句

    如果你使用上述语句之一,请务必在末尾指明分号:

    function getNum() {  // Notice the semicolons at the end  let num = 1;  return num;}getNum(); // => 1  
    

    在let声明和return声明结尾处写了一个强制性分号。

    当你不想添加这些分号时会发生什么?例如减少源文件的大小。

    在这种情况下,ECMAScript提供了[Automatic Semicolon Insertion](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-automatic-semicolon-insertion)(ASI)机制,该机制可以插入 你丢失的分号。

    在ASI的帮助下,你可以从前面的示例中删除分号:

    function getNum() {  // Notice that semicolons are missing  let num = 1  return num}getNum() // => 1  
    

    以上文字是有效的JavaScript代码。缺少的分号会自动插入。

    乍一看,它看起来很有希望。ASI机制让你跳过不必要的分号。您可以使JavaScript代码更小,更易于阅读。

    ASI有一个小而烦人的陷阱。当一个换行符位于return和返回的表达式'return \ n expression之间时,ASI自动在换行符之前插入一个分号; \ n表达式。

    在函数内部意味着什么return;语句?该函数返回undefined。如果您不详细了解ASI的机制,那么意外返回的“未定义”是误导性的。

    例如,让我们研究getPrimeNumbers()调用的返回值:

    function getPrimeNumbers() {  return    [ 2, 3, 5, 7, 11, 13, 17 ]}getPrimeNumbers() // => undefined  
    

    在return语句和数组文字表达式之间存在一个新行。 JavaScript在return后自动插入一个分号,解释代码如下:

    function getPrimeNumbers() {  return;  [ 2, 3, 5, 7, 11, 13, 17 ];}getPrimeNumbers(); // => undefined  
    

    语句return;使getPrimeNumbers()函数返回undefined而不是期望的数组。

    通过删除return和数组literal之间的换行符可以解决问题:

    function getPrimeNumbers() {  return [    2, 3, 5, 7, 11, 13, 17  ];}getPrimeNumbers(); // => [2, 3, 5, 7, 11, 13, 17]  
    

    我的建议是研究[确切地说](http://www.bradoncode.com/blog/2015/08/26/javascript-semi-colon-insertion/) 自动分号插入的作用,以避免这种情况。

    Of course, never put a newline between return and the returned expression.

    2.5 void 运算

    void运算,计算一个表达式,不返回计算结果,所以返回值为undefined

    void 1;                    // => undefinedvoid (false);              // => undefinedvoid {name: 'John Smith'}; // => undefinedvoid Math.min(1, 3);       // => undefined
    

    [void use]运算符的[一个用例](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void#JavaScript_URIs)是将表达式评估抑制为undefined,依赖 关于评估的一些副作用。

    3、数组中的undefined

    You get when accessing an array element with an out of bounds index. 当你试图想要获取一个超出数组界限范围的下标时,会返回 undefined

    const colors = ['blue', 'white', 'red'];colors[5];  // => undefinedcolors[-1]; // => undefined  
    

    数组colors 有3个元素array has 3 elements, 对应的下标分别是 0, 1 and 2。 因为在该数组中不存在下标5和-1,所以当你t访问colors[5] 和 colors[-1]会返回undefined.

    在JavaScript中你可能遇到所谓的稀疏数组。这些是有间隙的数组,即在某些索引中没有定义元素。

    当在一个稀疏数组中访问一个间隙(又名空槽)时,你也会得到一个'undefined`。

    以下示例将生成稀疏数组并尝试访问其空插槽:

    const sparse1 = new Array(3);sparse1;       // => [`<empty slot>`, `<empty slot>`, `<empty slot>`]sparse1[0];    // => undefinedsparse1[1];    // => undefinedconst sparse2 = ['white',  ,'blue']sparse2;       // => ['white', `<empty slot>`, 'blue']sparse2[1];    // => undefined  
    

    sparse1 是通过调用构造函数“Array”构造函数来创建的。它有3个空插槽。sparse2是用字面量的形式来创建了一个第二个元素为空的数组。在任何这些稀疏数组中,访问一个空插槽的结果都是“undefined”。

    在处理数组时,为了避免捕获undefined,一定要使用有效的数组索引,并避免创建稀疏数组。

    4、undefined and null 之间的不同

    这里有个合理的问题:undefined and null他们之间的主要区别是什么?都是一个指定值用来表示一个空状态。

    主要的区别是:undefined是用来表示一个变量的值没有被定义。null 这是代表一个对象不存在。

    我们来看一下这些区别:

    当变量number 被定义,但是没有给它赋值进行初始化:

    let number;number; // => undefined
    

    因此变量number的值为 undefined, .这明确表明了则是一个没有初始化的变量

    同样的,当你获取一个对象存在的属性时,也会发生这样的情况:该属性未初始化。

    const obj = { firstName: 'Dmitri' };obj.lastName; // => undefined  
    

    上面例子,因为 obj没有lastName属性,所以JavaScript会把 obj.lastName 解析为 undefined.

    还有另一种情况,当一个变量期待是一个对象或者是一个方法返回一个对象时,但是由于某些原因,你不能实例化一个对象。。那么这样的情况下,null就会是一个有意义的指示器,来表示对象缺失。

    例如:clone()` 是一个用来复制JavaScript对象的 函数,这个函数期望能够返回的是一个对象。

    function clone(obj) {  if (typeof obj === 'object' && obj !== null) {    return Object.assign({}, obj);  }  return null;}clone({name: 'John'}); // => {name: 'John'}clone(15);             // => nullclone(null);           // => null  
    

    然后,可能会传入一个不是对象的参数:15,null。这种情况下,该函数就不能进行对象复制,所以会返回 null -- 来表示对象缺失

    typeof 运算 能够看出两个值之间的区别

    typeof undefined; // => 'undefined'typeof null;      // => 'object'
    

    The 全等运算符 === 对于undefined 和null,也显示不相等。

    let nothing = undefined;let missingObject = null;nothing === missingObject; // => false  
    

    5、总结

    undefined的存在是JavaScript随意性所造成的,他允许一下任意情况的使用:

    • uninitialized variables

    • 未初始化的对象

    • non-existing object properties or methods

    • 对象没有的方法或属性

    • out of bounds indexes to access array elements

    • 数组的超出长度下标的元素

    • the invocation result of a function that returns nothing

    • 当方法调用返回空时

    大多数情况下,直接与'undefined'进行比较是一种不好的做法,因为你可能依赖于上面提到的允许但不鼓励的做法。

    一个有效的策略是减少代码中未定义关键字的出现。在此期间,请总是以令人惊讶的方式记住它的潜在外观,并通过应用下列有益习惯来防止这种情况发生:

    • 减少未初始化变量的使用

    • 使变量生命周期变短并接近其使用的来源

    • 尽可能为变量分配一个初始值

    • 支持const,否则使用let

    • 使用默认值作为无意义的函数参数

    • 验证属性的存在或用缺省属性填充不安全的对象

    • 避免使用稀疏数组

    本文完~

    展开全文
  • 1、undefined表示没有变量设置或者属性不存在。null表示变量是有的,只是其值为null 2、null == undefined返回true,null === undefined返回false     转载于:...

    1、undefined表示没有为变量设置值或者属性不存在。null表示变量是有值的,只是其值为null

    2、null == undefined返回为true,null === undefined返回为false

      

      

     

    转载于:https://www.cnblogs.com/yrrong/p/8994064.html

    展开全文
  • null是一个表示“无”的对象,转为数值时0,undefined是一个表示“无”的原始,转为数值时是NaN。 Undefined类型 Undefined类型只有一个,即Undefined。 什么情况是undefined? 在使用var声明变量时,但未...

    前面的话

    javascript的设计者Brendan Eich,设计了两种数据类型都表示“无”的意思,虽然两者含义相同,但两者还是有细微差别。

    null是一个表示“无”的对象,转为数值时为0,undefined是一个表示“无”的原始值,转为数值时是NaN。

    Undefined类型

    Undefined类型只有一个值,即Undefined。

    什么情况是undefined?

    在使用var声明变量时,但未对其加以初始化时,这个变量值为undefined。

    例如:

    var message ;
    console.log(message == undefined)// true;
    

    不过,包含undefined值的变量与尚未定义的变量还是不一样的。

        var msg ;
        console.log(msg);// undefined
        console.log(a);// 产生错误
    

    对于尚未声明的变量,只能执行一项操作,即使用typeof操作符检测其数据类型(并且严格模式下还会报错)

    // test 未声明  
       console.log(typeof test);// undefined
    

    [出现场景]

    • 已声明未赋值的变量
    • 获取对象不存在的属性
    • 空函数体的函数执行结果
    • 函数的参数没有传入
    • void(表达式)
    var a ;
    console.log(a);// undefined
    
    var object = {};
    console.log(object.a) // undefined
    
    function fn() {};
    console.log(fn()); // undefined 
    
    function fn(x) {return x};
    console.log(fn()); // undefined
    
    console.log(void(1+4));// undefined
    

    [类型转换]

       console.log( Boolean(undefined));// false
       console.log( Number(undefined)); // NaN
       console.log( String(undefined));// "undefined"
    

    [类型鉴别]

    鉴别undefined的类型,使用typeof操作符即可

    console.log(typeof undefined)// 'undefined'
    

    Null类型

    Null 类型的数据类型也只有一个值,这个特殊值为null。

    从逻辑角度来看,null值表示一个空对象指针。

    console.log(document.getElementById('test'));// null
    

    [注意]: null是空对象指针,[]是空数组,{}是空对象,三者不同

     console.log(typeof null)// 'object'
    

    为什么null的类型是object?

    因为在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。

    尽管null的undefined是不同的,但是它们都表示"值的空缺",null表示“空值”,undefined表示“未初始化”。两者可以互换。运算符“==”认为两者相等

     console.log(null == undefined);// true
    

    [类型转换]

    console.log(Boolean(null));// false
    console.log(Number(null))// 0
    console.log(String(null))// 'null' 
    

    [类型鉴别]

    鉴别null类型,使用typeof操作符不可行,因为该操作符会返回“object”,null被认为是空对象。

    判断一个值是否为null类型的最佳方法是直接和null进行恒等比较

    console.log(typeof null)// 'object'
    console.log(null === null);// true
    console.log(undefined === null) // false
    console.log('null' === null)// false
    

    总结

    • 无论在什么情况下,都没有必要把一个变量的值显示的设置为undefined,对null不适用。
    • 如果定义的变量准备将来用来存放保存对象,那么最好将该变量初始化为null,而不是其他值。这样体现了null作为空对象指针的惯例。

    参考:

    展开全文
  • 当讨论JavaScript中的原始数据类型时,大多数人都知道的基本知识,从String,...虽然相似,undefined实际上代表了不存在的(non-existence of a value)。都是完全不可变的,没有属性和方法,也不能给其属性赋值。事
  • JavaScript原始数据类型:字符串、布尔、数字、null、undefined简介
    数据类型 --- 能够表示并操作值的类型,编程语言的最基本特性就是能够支持多种数据类型。

    JavaScript的数据类型分为两种: 原始类型 (primitive type)  对象类型(object type)

    原始数据类型包括:  数字   字符串  布尔值   ,
    特殊的原始值:null  undefined,不是数字、字符串和布尔值,代表了各自特殊类型的唯一的成员。
    除了数字、字符串、布尔值、null和undefined之外就是对象了,对象是属性的集合,每个属性都由“名/值对”构成,有一个特殊的对象-全局对象。

    普通的JavaScript对象是“命名值”的无序集合,但JavaScript同样定义了一种特殊对象-数组。表示带编号的值的有序集合。

    函数--JavaScript的特殊对象,是具有与它相关联的可执行代码的对象,通过调用函数来运行可执行代码,并返回运算结果。
           如果函数用来初始化(new)一个新建的对象,称为构造函数,每个构造函数定义了一类对象-由构造函数初始化的对象组成的集合,类可以看做是对象类型的子类型。JavaScript语言核心除了数组(Array)类和函数(Function)类之外,还定义其他三种有用的类,日期(Date)类,正则(RegExp)类,错误(Error)类。可以通过定义自己的构造函数来定义需要的类。

    JavaScript解释器有自己的内存管理机制,可以自动对内存进行垃圾回收,这意味着程序可以按需创建对象,不必担心这些对象的销毁和内存回收。当不再有任何引用指向一个对象,解释器就会知道这个对象没用,然后自动回收它所占的资源。

    JavaScript是一种面向对象的语言,不严格地讲,这意味着我们不用全局的定义函数去操做不同类型的值,数据类型本身可以定义方法来使用值。从技术上来讲,只有JavaScript对象才拥有方法,但是数字、字符串和布尔值也可以拥有自己的方法,在JavaScript中,只有null和undefined是无法拥有方法的值。

    JavaScript分类

    原始类型 对象类型
    拥有方法的类型 不能拥有方法的类型
    可变类型:对象、数组 不可变类型:字符串、布尔值、null、undefined
    在JavaScript中,字符串是不可变的,可以访问字符串任意位置的文本,但并未提供修改已知字符串的文本内容的方法。

    JavaScript可以自由的进行数据类型的转换。

    JavaScript的变量是无类型的,变量可以赋予任何类型的值,统一一个变量可以赋予不同类型的值,使用var 关键字来声明变量。JavaScript采用词法作用域,不在任何函数内声明的变量称作全局变量,它在JavaScript程序中的任何地方都是可见的,在函数内声明的变量具有函数作用域,并且只在函数内可见。



    3.1  数字
    JavaScript不区分整数值和浮点数值,JavaScript中的所有数字均用浮点数字表示。
    采用IEEE 754标准定义的64位浮点格式代表数字,最大+-1.7976931348623157x10 (308次方)  最小 +-5x10(-324次方)
    能够表示的整数范围-2(53次方)~2(53次方),如果超过了此范围的整数,则无法保证低位数字的精度。
    但是,JavaScript中实际的操作(比如数组索引,位操作符)则是基于32位整数。

    3.1.1 整型直接量

    JavaScript除了能表示十进制的整型直接量,同样能够识别十六进制的值,八进制不确定。
    3.1.2 浮点型直接量

    浮点型直接量可以含有小数点,一个实数由整数部分、小数点和小数部分组成。  3.14
    还可以使用指数记数法表示浮点型直接量,即在实数后跟字母e或E,后面再跟正负号。 1.1457E-32
    3.13 JavaScript中的算术运算

    JavaScript使用语言本身的算术运算符来进行数字运算,+    -    *    /     %
    除了基本的运算符,还支持复杂的算术运算,这些复杂运算通过作为Math对象的属性定义的函数和常量来实现:
    Math.pow(2,53); Math.round(.6);.....

    JavaScript中的算术运算在溢出(overflow)、下溢(underflow)或被零整除时不会报错。当数字运算结果超过了JavaScript所能表示的数字上限,结果作为一个特殊的无穷大值,在JavaScript中以Infinity表示,负值超过了也是一样的算法。无穷大的特性:基于他们的加减乘除也是无穷大。

    下溢是当运算结果无限接近于零并比JavaScript能表示的最小值还小的时候发生的一种情况,这种情况下,会返回0.当一个负数发生下溢时,JavaScript返回一个特殊的值“负零”,负零和正零几乎完全一样,很少用到。

    被零整除在JavaScript并不报错,只是简单的返回无穷大或负无穷大;但有一个例外,0/0是无意义的,运算结果也是一个非数字值,用NaN表示。无穷大除以无穷大、给任意负数做开方运算或者算术运算符与不是数字或无法转换为数字的操作数一起使用时都将返回NaN.

    JavaScript预定义了全局变量Infinity和NaN,用来表示正无穷大和非数字值。非数字值NaN有一点特殊:它和任何值都不相等,包括自身,没办法通过x==NaN来判断变量x是否是NaN
    isNaN()---如果参数是NaN或者是一个非数字值(比如字符串和对象),则返回true;
    isFinite()---在参数不是NaN、Infinity或-Infinity的时候返回true;

    负零值同样有些特殊,它和正零值是相等的,但除了作为除数之外:
    var zero = 0;
    var negz = -0;
    console.log(zero == negz);                          true
    console.log(1/zero == 1/negz);                   false
    3.1.4 二进制浮点数和四舍五入错误

          JavaScript采用了IEEE-754浮点数表示法,这是一种二进制的 表示法,可以精确的表示分数,比如1/2、1/8和1/1024,但是我们常用的是十进制分数,1/10、1/100等,二进制并不能表示类似0.1这样简单的数字。

          JavaScript中的数字有足够的精度,并且可以极其近似于0.1,但事实上并不等:
    var x = .3 - .2;
    var y = .2 - .1;
    console.log(x); // 0.09999999999999998
    console.log(y); // 0.1

    x == y; //--false

    在任何使用二进制浮点数的编程语言都会出现这个问题(可以采取分为单位,而不是元)
    3.1.5 日期和时间

    JavaScript语言核心包括Date()构造函数,用来创建表示日期和时间的对象,但不是基本数据类型。

    var then = new Date(2011,0,1);//2011年1月1日
    var later = new Date(2011,0,1,17,10,30);
    //2011年1月1日下午5:10:30
    var now = new Date();
    var elapsed = now - then; //日期减法:间隔毫秒数

    later.getFullYear(); //--2011
    later.getMonth();  //--0 从0开始计算月份
    later.getDate();  //--1 从1开始计算的
    var day = later.getDay();  //--0代表星期天
    console.log(day);
    later.getHours();
    later.getUTCHours(); //使用UTC表示小时的时间 基于时区



    3.2 文本
         字符串是一组由16位值组成的不可变的有序序列,每个字符通常来自于Unicode字符集。JavaScript通过字符串类型来表示文本。字符串的长度是其所含16位值的个数。
         JavaScript采用UTF-16编码的Unicode字符集,JavaScript字符串是由一组无符号的16位值组成的序列。最常用的Unicode字符都是通过16位的内码表示,并代表字符串中的单个字符,那些不能表示为16位的Unicode字符遵循UTF-16编码规则-用两个16位值组成的一个序列表示。这意味着一个长度为2的JavaScript字符串(两个16位值)有可能表示一个Unicode字符:

    var p = "π";
    var e = "e";
    console.log(e.length);  //--2

    3.2.1 字符串直接量

        在JavaScript程序中的字符串直接量,是由单引号或者双引号括起来的字符序列。由单引号定界的字符串刻印包含双引号,由双引号定界的字符串中也可以包含单引号。

        在ECMAScript 3中,字符串直接量必须写在一行中,而在ECMAScript 5中,字符串直接量可以拆分成数行,每行必须以反斜线(\)结束,反斜线和行结束符都不算字符串直接量的内容。如果希望在字符串直接量中另起一行,可以使用转义字符  \n
       
        *再用单引号的时候必须注意英文中的缩写和所有格写法 can't   O'Relly's,此时必须使用反斜线(\)来转义。

        *JavaScript代码和HTML代码都用单引号或者双引号,但最好各自使用个独立的引号风格。
    3.2.2 转义字符
         在JavaScript中,反斜线(\)有着特殊的用途,如在上文中转义:'can\'t  '  ' O\'Relly\'s'
        
     JavaScript转义字符
    \o    ----   NUL字符(\u0000)
    \b    ----   退格符(\u0008)
    \t     ----   水平制表符(\u0009)
    \n    ----   换行符(\u000A)
    \v    ----   垂直制表符(\u000B)
    \f     ----   换页符  (\u000C)
    \r    -----   回车符(\u000D)
    \''    ----    双引号(\u0022)
    \'    -----   撇号或者单引号(\u0027)
    \\    -----  反斜线(\u005C)
    \xXX    -----  由两位十六进制数XX指定的Latin-1字符
    \uXXXX   ----  由四位十六进制数XXXX指定的Unicode字符

    如果“\”字符没有在以上列表中出现,则忽略“\”
    3.2.3 字符串的使用

        JavaScript的内置功能之一就是字符串的连接,用“+”作用于字符串表示字符串连接
        JavaScript字符串调用方法:
        
    var s = "hello,world";
    s.charAt(0); //第一个字符:h
    s.substring(1,4); //第2-4个字符:ell
    s.slice(1,4); //同上
    s.slice(-3);  //最后三个字符:rld
    s.indexOf("l");  //字符"l"第一次出现:2
    s.lastIndexOf("l"); //字符串"l"最后一次出现:9
    s.indexOf("l",3); //在位置3后面首次出现"l"的位置:3
    s.split(",");//按照","分割:['hello','world']
    s.replace("h","H");//"h"全用"H"替代
    s.toUpperCase();//纯大写 
     3.2.4  模式匹配
        JavaScript定义了RegExp()构造函数,用来创建表示文本匹配模式的对象   ------  称为‘正则表达式’
        JavaScript采用Perl中的正则表达式语法,String和RegExp对象均定义了利用正则表达式进行模式匹配和查找与替换的函数
        RegExp是JavaScript的特殊对象,虽然不是语言中的基本数据类型,但是具有直接量写法,可以直接在JavaScript程序中使

    var text = "testing:1,2,3";
    var pattern = /\d+/g;  //匹配所有包含一个或多个数字的实例
    pattern.test(text);  // true
    text.search(pattern);  //首次匹配成功的位置:8
    text.match(pattern);  //所有匹配组成的数组 ['1','2','3']


    3.3 布尔值
       
    布尔值代表真或假、开或关、是或否,只有两个值 true、false。
    在JavaScript中,任意的JavaScript值都可以转换成布尔值:

    undefined ,null ,0 ,-0 ,NaN ,“”   会被转换成false;
    所有其他值,包括所有对象(数组)都会转换成true

    假值(falsy value)--false和上面六个可以转换成false的值;
    真值(truthy value) -- true和可以转换成true的值;
    在JavaScript期望使用一个布尔值时,假值会被当成false,真值会被当成true。

    if(o !== null)......只有当o不是null时才会执行之后的代码
        
    if(o)......o不是任何假值都会执行之后的代码
     



    3.4 null和undefined

    null 是JavaScript的关键字,表示一个特殊值,常用来描述“空值”;、
    表示数字、字符串和对象是“无值”的;
    typeof(null) == "object"  // "object"    返回字符串“object” ,也就是说,可以把null认为是一个特殊的对象值,含义是非对象。

    undefined是预定义的全局变量,不是关键字,它的值就是“未定义”;
    表明变量没有初始化,或者属性和元素不存在
    typeof(undefined)  // "undefined"  返回字符串“undefined” 这个值是这个类型的唯一成员
    展开全文
  • 目录 目录 null &amp; undefined 布尔 返回布尔的运算符 ... undefined ...null 与 undefined都可以表示...将一个变量赋值 undefined 或 null,老实说,语法效果几乎没区别。 var a = undefined; // 或者 ...
  • 只有0、NaN 、null、’’、undefined 五个转换false,其余都转换true(而且没有任何的特殊情况) Boolean() !/!! 条件判断 null、undefined null和undefined都是代表是没有 null:意料之中(一般都是...
  • JS的数据类型 总体来说,JS的数据类型可以分为两大类 ...undefined: undefined null: null 引入数据类型 object: 任意对象 Array: 一种特别的对象(数值下标属性,内部数据是有序的) Function:一...
  • 向页面传递数据flag是true代表该用户的账号密码验证码等信息正确可以登录,那怎么会没有响应呢,后来测试发现 $(function () { //1.给登录按钮绑定单击事件 $("#btn_sub").click(function () { ...
  • undefind基本就是找不到,这个太麻烦了首先你一定要确定是哪一个找不到,这个可以再错误信息中一眼看见 接下来需要注意几个细节。 const that=this; wx.getStorage({ key: 'xxx', success(res) { that....
  • javascript中 有null、undefined 在使用typeof 时候  console.log(typeof null); //object console.log(typeof undefined) //...将一个变量赋值为undefined或null,老实说,语法效果几乎没区别。 两个类型到底...
  • null, undefined 和布尔

    2019-05-22 11:27:52
    将一个变量赋值为undefined或null,老实说,语法效果几乎没区别。 var a = undefined; // 或者 var a = null; 上面代码中,变量a分别被赋值为undefined和null,这两种写法的效果几乎等价。 在if语句中,它们都会被...
  • Null类型,代表空值,代表一个空对象指针,使用typeof运算得到object,可以认为它是一个特殊的对象undefined Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。 3.用法 null (表示’
  • 问题: 邮寄地址,从java返回来的是字符串,但是这里什么出现了0。 这个问题,下一篇博客解决。我们篇博客先介绍一下,javascript的基本数据...注意:undefined类型只有undefined这一个。 Boolean只有true和false
  • 在学习ECMAScript基本数据类型的过程中,经常会碰到undefined、null两个特殊的,这两个对初学者来说特别容易混淆,尤其是对有这两个参与的表达式的计算结果的判断往往会不清晰,本文以初学者的角度,对这两个...
  • 一、常用的几种: 1、null 2、双引号或者单引号...1、undefined(未定义,找不到时出现) 2、null(代表空值) 3、false(布尔的false,字符串"false"布尔值为true) 4、0(数字0,字符串"0"布尔值为true)...
  • 变量undefined详解

    千次阅读 2018-07-07 20:02:56
    1.js有六种数据类型,...第一:是什么undefined是其中一种数据类型,它只有一个,怎么说呢,使用console.log(undefined);在浏览器输出只有一个,就是undefined.第二:什么情况会出现,如何判断呢?平时项目中出...
  • 但是,本文将更多聚焦独特的原始数据类型Null和Undefined,是什么让他们如此相似,却又似是而非。 一、理解Null和Undefined 在JavaScript中,null是字面量同时也是语言中的关键字,用来表示无法识别的对象。换
  • undefined 和 null

    2017-07-31 15:01:54
    Undefined 和 Null 都是JS五种基本数据类型之一(Number,String,Boolean,Undefined,Null),而它们都只有唯一的,分别是undefined 以及 null。 alert(typeof a); //undefined alert(typeof b); //object alert...
  • null与undefined的区别

    千次阅读 2016-12-26 19:58:52
    null是一个特殊,但我们常常误解它,有时候我们会把它和另一个数据类型undefined的含义互相混淆。 首先我们来了解一下null这个特殊会使用在哪些场景以及它代表着什么样的含义? 1.用来初始化一个变量,这个变量...
  • null 和undefined的区别

    2021-02-10 23:04:58
    文章目录1、 定义2、null和undefined的区别1.首先是数据类型不一样2.null和...但没有复制时,就等于undefined2、调用函数时,应该提供的参数没有提供,该参数等于undefined3、对象没有赋值的属性,该属性的值为undefi
  • 当讨论JavaScript中的原始数据类型时,大多数人都知道从String、Number到Boolean的基本知识。...虽然相似,undefined实际上代表了不存在的(non-existence of a value),也即你有东西丢失了。两者
  • Undefined和Null的区别

    千次阅读 2020-04-28 11:06:12
    Undefined类型只有一个,即undefined。当声明的变量还未被初始化时,变量的默认值...代码显示true,代表a的为undefined,因为我们没有初始化它。 2. 这段代码显示"true",因为我们尝试获取一个不存在...
  • Undefined与Null的区别

    2020-08-05 13:08:31
    在ECMAScript中有六种简单数据类型(也称为基本数据类型): Undefined、Null、Boolean、Number 和 String、Symbol (ES6中引入) 。还有一种复杂数据类型——Object。 Undefined和Null都只有一个,分别对应着...
  • 当讨论JavaScript中的原始数据类型时,大多数人都知道从String、Number到Boolean的基本...一、理解null和undefined在JavaScript中,null是字面量同时也是语言中的关键字,用来表示无法识别的对象。换句话说,这用来表
  • 1、undefined(未定义,找不到时出现) 2、null(代表空值) 3、false(布尔的false,字符串"false"布尔值为true) 4、0(数字0,字符串"0"布尔值为true) 5、NaN(无法计算结果时出现,表示"非数值";但是...
  • 详解 undefined 与 null 的区别

    千次阅读 2020-01-02 09:31:49
    Undefined 和 Null 是 Javascript 中两种特殊的原始数据类型(Primary Type),它们都只有一个,分别对应 undefined 和 null ,这两种不同类型的,既有着不同的语义和场景,又表现出较为相似的行为: undefined ...
  • null 和undefined异同

    2018-10-31 11:28:11
    然而,在JavaScript语言中出现了两个表示“空”的undefined和null。这是因为祖师爷留个咱们的遗产呀。虽然都表示“空”,但是并不完全一致的,面试中经常提及异同这类的问题。 先看不同点 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 48,289
精华内容 19,315
关键字:

数据的值为undefined代表