> 웹 프론트엔드 > JS 튜토리얼 > JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

青灯夜游
풀어 주다: 2020-10-14 15:45:02
앞으로
4183명이 탐색했습니다.

JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

원작가가 JS를 배우기 시작했을 때 이상한 상황에 직면했습니다. undefined 的值,也存在表示空值的null。它们之间的明显区别是什么?它们似乎都定义了空值,而且,比较null == undefined的计算结果为true

大多数现代语言,如Ruby、Python或Java都有一个空值(nilnull),这似乎是一种合理的方式。

对于JavaScript,解释器在访问尚未初始化的变量或对象属性时返回undefined。例如:

let company;
company;    // => undefined
let person = { name: 'John Smith' };
person.age; // => undefined
로그인 후 복사

另一方面,null表示缺少的对象引用,JS本身不会将变量或对象属性设置为null

一些原生方法,比如String.prototype.match(),可以返回null来表示丢失的对象。看看下面的示例:

let array = null;
array; // => null
let movie = { name: "Starship Troopers", musicBy: null };
movie.musicBy; // => null
"abc".match(/[0-9]/); // => null
로그인 후 복사

由于 JS 的宽容特性,开发人员很容易访问未初始化的值,我也犯了这样的错误。

通常,这种危险的操作会生成 undefined 的相关错误,从而快速地结束脚本。相关的常见错误消息有:

  • TypeError: 'undefined' is not a function 값과 null 값을 나타내는 null이 둘 다 있었습니다. 둘 사이의 명백한 차이점은 무엇입니까? 둘 다 null 값을 정의하는 것으로 보이며 null == undefine 비교가 true로 평가됩니다.

  • Ruby, Python 또는 Java와 같은 대부분의 최신 언어에는 null 값(nil 또는 null)이 있는데 이는 합리적인 접근 방식처럼 보입니다.
  • JavaScript의 경우 아직 초기화되지 않은 변수나 객체 속성에 액세스하면 인터프리터가 TypeError: Cannot read property &#39;<prop-name>&#39; of undefined를 반환합니다. 예:

    function undefined() {
        // problem solved
    }
    로그인 후 복사
  • 반면, null은 누락된 개체 참조를 나타내며 JS 자체는 변수나 개체 속성을 null로 설정하지 않습니다.
  • String.prototype.match()와 같은 일부 기본 메서드는 null을 반환하여 누락된 개체를 나타낼 수 있습니다. 아래 예를 살펴보세요. type errors

    let number;
    number; // => undefined
    
    let movie = { name: "Interstellar" };
    movie.year; // => undefined
    
    let movies = ["Interstellar", "Alexander"];
    movies[3]; // => undefined
    로그인 후 복사

    JS의 허용적 특성으로 인해 개발자가 초기화되지 않은 값에 액세스하기 쉽고, 저도 이런 실수를 했습니다.
일반적으로 이 위험한 작업은

관련 오류를 생성하여 스크립트를 빠르게 종료합니다. 관련된 일반적인 오류 메시지는 다음과 같습니다:

    undefined的情况。更重要的是抑制它的出现并阻止在应用程序中传播,从而提高代码的持久性。

    让咱们详细讨论 undefined 及其对代码安全性的影响。

    1、undefined 是什么鬼

    JS 有6种基本类型

    • Boolean: truefalseTypeError: 'undefine'은 함수가 아닙니다 ~ ~ ​ ​

    • JS 개발자는 다음 농담의 아이러니를 이해할 수 있습니다. 1, 6.7, 0xFF

      typeof undefined === "undefined"; // => true
      로그인 후 복사

      이러한 오류의 위험을 줄이려면
    • 이 생성되는 상황을 이해하는 것이 필요합니다. 더 중요한 것은 발생을 억제하고 애플리케이션 내에서 전파를 방지하여 코드의 내구성을 높이는 것입니다.
    • 자세히 "Gorilla and banana"토론하고 이것이 코드 보안에 미치는 영향을 살펴보겠습니다.

    • 1. 정의되지 않은 것이 도대체 무엇인가요?
    • JS에는 6가지 기본 유형이 있습니다Symbol("name") (starting ES2015)

    • Null: null

        부울: true 또는 false ~ ~                             >                                           기호: Symbol("name") (ES2015부터)
      • undefined

        Null:  null ~           ​ ​

      Object 类型:{name: "Dmitri"} ["apple", "orange"]

      根据ECMAScript规范,从6种原始类型中,undefined是一个特殊的值,它有自己的Undefined类型。

      未为变量赋值时默认值为undefined

      该标准明确定义,当访问未初始化的变量、不存在的对象属性、不存在的数组元素等时,将接收到一个undefined 的值。例如:

      let nothing;
      typeof nothing === "undefined"; // => true
      로그인 후 복사

      上述代码大致流程:

      • 未初始化的变量number 및 별도의 Object 유형: {name: "Dmitri"}, ["apple", "orange"] .

      • ECMAScript 사양 , 6가지 기본 유형 중
      • 는 고유한 Undefine 유형을 갖는 특수 값입니다.

        movie.year변수에 값이 할당되지 않은 경우 기본값은

        입니다.
      • 표준에서는 초기화되지 않은 변수, 존재하지 않는 객체 속성, 존재하지 않는 배열 요소 등에 액세스할 때

        값을 수신한다고 명확하게 정의합니다. 예: movies[3]

        let myVariable;
        myVariable; // => undefined
        로그인 후 복사

        위 코드의 일반적인 흐름:
        • 초기화되지 않은 변수 number >                                            undefined

          ECMAScript规范定义了 undefined 值的类型

          Undefined type是其唯一值为undefined 值的类型。

          在这个意义上,typeof undefined返回“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"); // => true
          isPalindrome("hello"); // => false
          로그인 후 복사
          로그인 후 복사

          当然typeof可以很好地验证变量是否包含undefined的值

          function bigFunction() {
            // code...
            myVariable; // => Throws &#39;ReferenceError: myVariable is not defined&#39;
            // code...
            let myVariable = &#39;Initial value&#39;;
            // code...
            myVariable; // => &#39;Initial value&#39;
          }
          bigFunction();
          로그인 후 복사
          로그인 후 복사

          2、导致undefined的常见场景

          2.1 未初始化变量

          尚未赋值(未初始化)的声明变量默认为undefined

          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 &#39;some result&#39;;
          }
          로그인 후 복사
          로그인 후 복사

          myVariable已声明,但尚未赋值,默认值为undefined

          解决未初始化变量问题的有效方法是尽可能分配初始值。 变量在未初始化状态中越少越好。 理想情况下,你可以在声明const myVariable =&#39;Initial value&#39;

          존재하지 않는 개체 속성      

          🎜🎜또는 배열 요소가 없습니다 🎜        🎜🎜🎜🎜은 모두 🎜로 정의됩니다. 🎜🎜ECMAScript 사양은 🎜 값 유형을 정의합니다. 🎜
          🎜정의되지 않은 유형은 정의되지 않은 값만 값으로 갖는 유형입니다. 🎜
          🎜이러한 의미에서 typeof undefine은 "정의되지 않은" 문자열을 반환합니다. 🎜
          function someFunc(array) {
            // some code...
            // some code...
            const length = array.length;
            for (let index = 0; index < length; index++) {
              const item = array[index];
              // some 
            }
            return &#39;some result&#39;;
          }
          로그인 후 복사
          로그인 후 복사
          🎜물론 typeof는 변수에 다음이 포함되어 있는지 확인하는 좋은 방법이 될 수 있습니다. 🎜🎜
          let favoriteMovie = {
            title: &#39;Blade Runner&#39;
          };
          favoriteMovie.actors; // => undefined
          로그인 후 복사
          로그인 후 복사

          🎜2. 정의되지 않음🎜

          🎜🎜2.1 초기화되지 않은 변수 🎜🎜🎜아직 값이 할당되지 않은(초기화되지 않은) 선언된 변수의 기본값은 🎜입니다. 🎜
          let favoriteMovie = {
            title: &#39;Blade Runner&#39;
          };
          favoriteMovie.actors[0];
          // TypeError: Cannot read property &#39;0&#39; of undefined
          로그인 후 복사
          로그인 후 복사
          🎜myVariable이 선언되었지만 값이 할당되지 않았습니다. 기본값은 🎜입니다. 🎜🎜초기화되지 않은 변수 문제를 해결하는 효과적인 방법은 가능할 때마다 초기값을 할당하는 것입니다. 초기화되지 않은 상태에서는 변수가 적을수록 좋습니다. 이상적으로는 const myVariable ='초기값'을 선언한 직후에 값을 지정하는 것이 좋지만 이것이 항상 가능한 것은 아닙니다. 🎜🎜🎜🎜 팁 1: var🎜🎜 대신 let과 const를 사용하세요.

          在我看来,ES6 最好的特性之一是使用const和let声明变量的新方法。const和let具有块作用域(与旧的函数作用域var相反),在声明行之前都存在于暂时性死区

          当变量一次性且永久地接收到一个值时,建议使用const声明,它创建一个不可变的绑定。

          const的一个很好的特性是必须为变量const myVariable =&#39;initial&#39;分配一个初始值。 变量未暴露给未初始化状态,并且访问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"); // => true
          isPalindrome("hello"); // => false
          로그인 후 복사
          로그인 후 복사

          length 和 half 变量被赋值一次。将它们声明为const似乎是合理的,因为这些变量不会改变。

          如果需要重新绑定变量(即多次赋值),请应用let声明。只要可能,立即为它赋一个初值,例如,let index = 0。

          那么使用 var 声明呢,相对于ES6,建议是完全停止使用它。

          JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

          var 声明的变量提会被提升到整个函数作用域顶部。可以在函数作用域末尾的某个地方声明var变量,但是仍然可以在声明之前访问它:对应变量的值是 undefined。

          相反,用let 或者 const 声明的变量之前不能访问该变量。之所以会发生这种情况,是因为变量在声明之前处于暂时死区。这很好,因为这样就很少有机会访问到 undefined 值。

          使用let(而不是var)更新的上述示例会引发ReferenceError 错误,因为无法访问暂时死区中的变量。

          function bigFunction() {
            // code...
            myVariable; // => Throws &#39;ReferenceError: myVariable is not defined&#39;
            // code...
            let myVariable = &#39;Initial value&#39;;
            // code...
            myVariable; // => &#39;Initial value&#39;
          }
          bigFunction();
          로그인 후 복사
          로그인 후 복사

          技巧2:增加内聚性

          内聚描述模块的元素(命名空间、类、方法、代码块)内聚在一起的程度。凝聚力的测量通常被称为高凝聚力或低内聚。

          高内聚是优选的,因为它建议设计模块的元素以仅关注单个任务,它构成了一个模块。

          • 专注且易懂:更容易理解模块的功能

          • 可维护且更容易重构:模块中的更改会影响更少的模块

          • 可重用:专注于单个任务,使模块更易于重用

          • 可测试:可以更轻松地测试专注于单个任务的模块

          JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

          高内聚和低耦合是一个设计良好的系统的特征。

          代码块本身可能被视为一个小模块,为了尽可能实现高内聚,需要使变量尽可能接近使用它们代码块位置。

          例如,如果一个变量仅存在以形成块作用域内,不要将此变量公开给外部块作用域,因为外部块不应该关心此变量。

          不必要地延长变量生命周期的一个典型例子是函数中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 &#39;some result&#39;;
          }
          로그인 후 복사
          로그인 후 복사

          indexitemlength变量在函数体的开头声明,但是,它们仅在最后使用,那么这种方式有什么问题呢?

          从顶部的声明到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 &#39;some result&#39;;
          }
          로그인 후 복사
          로그인 후 복사

          indexitem变量仅存在于for语句的作用域内,for 之外没有任何意义。length变量也被声明为接近其使用它的位置。

          为什么修改后的版本优于初始版本? 主要有几点:

          • 变量未暴露undefined状态,因此没有访问undefined的风险

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

          • 高内聚的代码块在必要时更容易重构并提取到单独的函数中

          2.2 访问不存在的属性

          访问不存在的对象属性时,JS 返回undefined

          咱们用一个例子来说明这一点:

          let favoriteMovie = {
            title: &#39;Blade Runner&#39;
          };
          favoriteMovie.actors; // => undefined
          로그인 후 복사
          로그인 후 복사

          favoriteMovie是一个具有单个属性 title 的对象。 使用属性访问器favoriteMovie.actors访问不存在的属性actors将被计算为undefined

          本身访问不存在的属性不会引发错误, 但尝试从不存在的属性值中获取数据时就会出现问题。 常见的的错误是 TypeError: Cannot read property <prop> of undefined

          稍微修改前面的代码片段来说明TypeError throw

          let favoriteMovie = {
            title: &#39;Blade Runner&#39;
          };
          favoriteMovie.actors[0];
          // TypeError: Cannot read property &#39;0&#39; of undefined
          로그인 후 복사
          로그인 후 복사

          favoriteMovie没有属性actors,所以favoriteMovie.actors的值 undefined。因此,使用表达式favoriteMovie.actors[0]访问undefined值的第一项会引发TypeError

          JS 允许访问不存在的属性,这种允许访问的特性容易引起混淆:可能设置了属性,也可能没有设置属性,绕过这个问题的理想方法是限制对象始终定义它所持有的属性。

          不幸的是,咱们常常无法控制对象。在不同的场景中,这些对象可能具有不同的属性集,因此,必须手动处理所有这些场景:

          接着我们实现一个函数append(array, toAppend),它的主要功能在数组的开头和/或末尾添加新的元素。 toAppend参数接受具有属性的对象:

          • first:元素插入数组的开头

          • last:元素在数组末尾插入。

          函数返回一个新的数组实例,而不改变原始数组(即它是一个纯函数)。

          append()的第一个版本看起来比较简单,如下所示:

          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([&#39;Hello&#39;], { last: &#39;World&#39; });     // => [&#39;Hello&#39;, &#39;World&#39;]
          append([8, 16], { first: 4 });            // => [4, 8, 16]
          로그인 후 복사

          由于toAppend对象可以省略first或last属性,因此必须验证toAppend中是否存在这些属性。如果属性不存在,则属性访问器值为undefined

          检查firstlast属性是否是undefined,在条件为 if(toappendix .first){}if(toappendix .last){}中进行验证:

          这种方法有一个缺点, undefinedfalsenull0NaN&#39;&#39;是虚值。

          append() 的当前实现中,该函数不允许插入虚值元素:

          append([10], { first: 0, last: false }); // => [10]
          로그인 후 복사

          0false是虚值的。 因为 if(toAppend.first){}if(toAppend.last){}实际上与falsy进行比较,所以这些元素不会插入到数组中,该函数返回初始数组[10]而不会进行任何修改。

          以下技巧解释了如何正确检查属性的存在。

          技巧3: 检查属性是否存在

          JS 提供了许多方法来确定对象是否具有特定属性:

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

          • typeof obj.prop!==&#39;undefined&#39;:验证属性值类型

          • obj.hasOwnProperty(&#39;prop&#39;):验证对象是否具有自己的属性

          • &#39;prop&#39; in obj:验证对象是否具有自己的属性或继承属性

          我的建议是使用 in 操作符,它的语法短小精悍。in操作符的存在表明一个明确的意图,即检查对象是否具有特定的属性,而不访问实际的属性值。

          JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

          obj.hasOwnProperty(&#39;prop&#39;)也是一个很好的解决方案,它比 in 操作符稍长,仅在对象自己的属性中进行验证。

          涉及与undefined进行比较剩下的两种方式可能有效,但在我看来,obj.prop!== undefinedtypeof obj.prop!==&#39;undefined&#39;看起来冗长而怪异,并暴露出直接处理undefined的可疑路径。。

          让咱们使用in操作符改进append(array, toAppend) 函数:

          function append(array, toAppend) {
            const arrayCopy = array.slice();
            if (&#39;first&#39; in toAppend) {
              arrayCopy.unshift(toAppend.first);
            }
            if (&#39;last&#39; 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]
          로그인 후 복사

          &#39;first&#39; in toAppend (和&#39;last&#39; in toAppend)在对应属性存在时为true,否则为falsein操作符的使用解决了插入虚值元素0false的问题。现在,在[10]的开头和结尾添加这些元素将产生预期的结果[0,10,false]

          技巧4:解构访问对象属性

          在访问对象属性时,如果属性不存在,有时需要指示默认值。可以使用in和三元运算符来实现这一点。

          const object = { };
          const prop = &#39;prop&#39; in object ? object.prop : &#39;default&#39;;
          prop; // => &#39;default&#39;
          로그인 후 복사

          当要检查的属性数量增加时,三元运算符语法的使用变得令人生畏。对于每个属性,都必须创建新的代码行来处理默认值,这就增加了一堵难看的墙,里面都是外观相似的三元运算符。

          为了使用更优雅的方法,可以使用 ES6 对象的解构。

          对象解构允许将对象属性值直接提取到变量中,并在属性不存在时设置默认值,避免直接处理undefined的方便语法。

          实际上,属性提取现在看起来简短而有意义:

          const object = {  };
          const { prop = &#39;default&#39; } = object;
          prop; // => &#39;default&#39;
          로그인 후 복사

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

          • char:包装的字符,例如 &#39;(单引号)或(双引号),默认为

          • skipIfQuoted:如果字符串已被引用则跳过引用的布尔值,默认为true

          使用对象析构的优点,让咱们实现quote()

          function quote(str, config) {
            const { char = &#39;"&#39;, skipIfQuoted = true } = config;
            const length = str.length;
            if (skipIfQuoted
                && str[0] === char
                && str[length - 1] === char) {
              return str;
            }
            return char + str + char;
          }
          quote(&#39;Hello World&#39;, { char: &#39;*&#39; });        // => &#39;*Hello World*&#39;
          quote(&#39;"Welcome"&#39;, { skipIfQuoted: true }); // => &#39;"Welcome"&#39;
          로그인 후 복사

          const {char = &#39;", skipifquote = true} = config解构赋值在一行中从config对象中提取charskipifquote属性。如果config对象中有一些属性不可用,那么解构赋值将设置默认值:char&#39;"&#39;skipifquotefalse

          该功能仍有改进的空间。让我们将解构赋值直接移动到参数部分。并为config参数设置一个默认值(空对象{}),以便在默认设置足够时跳过第二个参数。

          function quote(str, { char = &#39;"&#39;, skipIfQuoted = true } = {}) {
            const length = str.length;
            if (skipIfQuoted
                && str[0] === char
                && str[length - 1] === char) {
              return str;
            }
            return char + str + char;
          }
          quote(&#39;Hello World&#39;, { char: &#39;*&#39; }); // => &#39;*Hello World*&#39;
          quote(&#39;Sunny day&#39;);                  // => &#39;"Sunny day"&#39;
          로그인 후 복사

          注意,解构赋值替换了函数 config 参数。我喜欢这样:quote()缩短了一行。

          ={}在解构赋值的右侧,确保在完全没有指定第二个参数的情况下使用空对象。

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

          技巧5: 用默认属性填充对象

          如果不需要像解构赋值那样为每个属性创建变量,那么丢失某些属性的对象可以用默认值填充。

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

          例如,需要访问unsafeOptions对象的属性,该对象并不总是包含其完整的属性集。

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

          定义包含默认属性值的defaults对象

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

          const unsafeOptions = {
            fontSize: 18
          };
          const defaults = {
            fontSize: 16,
            color: &#39;black&#39;
          };
          const options = Object.assign({}, defaults, unsafeOptions);
          options.fontSize; // => 18
          options.color;    // => &#39;black&#39;
          로그인 후 복사

          unsafeOptions仅包含fontSize属性。 defaults对象定义属性fontSizecolor的默认值。

          Object.assign() 将第一个参数作为目标对象{}。 目标对象从unsafeOptions源对象接收fontSize属性的值。 并且人defaults对象的获取color属性值,因为unsafeOptions不包含color属性。

          枚举源对象的顺序很重要:后面的源对象属性会覆盖前面的源对象属性。

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

          还有一种简单的方法就是使用ES6中展开运算符:

          const unsafeOptions = {
            fontSize: 18
          };
          const defaults = {
            fontSize: 16,
            color: &#39;black&#39;
          };
          const options = {
            ...defaults,
            ...unsafeOptions
          };
          options.fontSize; // => 18
          options.color;    // => &#39;black&#39;
          로그인 후 복사

          对象初始值设定项从defaultsunsafeOptions源对象扩展属性。 指定源对象的顺序很重要,后面的源对象属性会覆盖前面的源对象。

          使用默认属性值填充不完整的对象是使代码安全且持久的有效策略。无论哪种情况,对象总是包含完整的属性集:并且无法生成undefined的属性。

          2.3 函数参数

          函数参数隐式默认为undefined

          通常,用特定数量的参数定义的函数应该用相同数量的参数调用。在这种情况下,参数得到期望的值

          function multiply(a, b) {
            a; // => 5
            b; // => 3
            return a * b;
          }
          multiply(5, 3); // => 15
          로그인 후 복사

          调用multiply(5,3)使参数ab接收相应的53值,返回结果:5 * 3 = 15

          在调用时省略参数会发生什么?

          function multiply(a, b) {
            a; // => 5
            b; // => undefined
            return a * b;
          }
          multiply(5); // => NaN
          로그인 후 복사

          函数multiply(a, b){}由两个参数ab定义。调用multiply(5)用一个参数执行:结果一个参数是5,但是b参数是undefined

          技巧6: 使用默认参数值

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

          回顾前面的例子,让我们做一个改进,如果b参数未定义,则为其分配默认值2

          function multiply(a, b) {
            if (b === undefined) {
              b = 2;
            }
            a; // => 5
            b; // => 2
            return a * b;
          }
          multiply(5); // => 10
          로그인 후 복사

          虽然所提供的分配默认值的方法有效,但不建议直接与undefined值进行比较。它很冗长,看起来像一个hack .

          这里可以使用 ES6 的默认值:

          function multiply(a, b = 2) {
            a; // => 5
            b; // => 2
            return a * b;
          }
          multiply(5);            // => 10
          multiply(5, undefined); // => 10
          로그인 후 복사

          2.4 函数返回值

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

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

          function square(x) {
            const res = x * x;
          }
          square(2); // => undefined
          로그인 후 복사

          square() 函数没有返回计算结果,函数调用时的结果undefined

          return语句后面没有表达式时,默认返回 undefined

          function square(x) {
            const res = x * x;
            return;
          }
          square(2); // => undefined
          로그인 후 복사

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

          function square(x) {
            const res = x * x;
            return res;
          }
          square(2); // => 4
          로그인 후 복사

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

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

          • 空语句

          • letconstvarimportexport声明

          • 表达语句

          • debugger 语句

          • continue 语句,break 语句

          • throw 语句

          • return 语句

          如果使用上述声明之一,请尽量务必在结尾处指明分号:

          function getNum() {
            let num = 1; 
            return num;
          }
          getNum(); // => 1
          로그인 후 복사

          let 声明和 return 语句结束时,强制性写分号。

          当你不想写这些分号时会发生什么? 例如,咱们想要减小源文件的大小。

          在这种情况下,ECMAScript 提供自动分号插入(ASI)机制,为你插入缺少的分号

          ASI 的帮助下,可以从上一个示例中删除分号

          function getNum() {
            // Notice that semicolons are missing
            let num = 1
            return num
          }
          getNum() // => 1
          로그인 후 복사

          上面的代码是有效的JS代码,缺少的分号ASI会自动为我们插入。

          乍一看,它看起来很 nice。 ASI 机制允许你少写不必要的分号,可以使JS代码更小,更易于阅读。

          ASI 创建了一个小而烦人的陷阱。 当换行符位于returnreturn \n expression之间时,ASI 会在换行符之前自动插入分号(return; \n expression)。

          函数内部return; ? 即该函数返回undefined。 如果你不详细了解ASI的机制,则意外返回的undefined会产生意想不到的问题。

          getPrimeNumbers()调用返回的值:

          function getPrimeNumbers() {
            return 
              [ 2, 3, 5, 7, 11, 13, 17 ]
          }
          getPrimeNumbers() // => undefined
          로그인 후 복사

          return语句和数组之间存在一个换行,JS 在return后自动插入分号,解释代码如下:

          function getPrimeNumbers() {
            return; 
            [ 2, 3, 5, 7, 11, 13, 17 ];
          }
          getPrimeNumbers(); // => undefined
          로그인 후 복사

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

          这个问题通过删除return和数组文字之间的换行来解决:

          function getPrimeNumbers() {
            return [ 
              2, 3, 5, 7, 11, 13, 17 
            ];
          }
          getPrimeNumbers(); // => [2, 3, 5, 7, 11, 13, 17]
          로그인 후 복사

          我的建议是研究自动分号插入的确切方式,以避免这种情况。

          当然,永远不要在return和返回的表达式之间放置换行符。

          2.5 void 操作符

          void <expression>计算表达式无论计算结果如何都返回undefined

          void 1;                    // => undefined
          void (false);              // => undefined
          void {name: &#39;John Smith&#39;}; // => undefined
          void Math.min(1, 3);       // => undefined
          로그인 후 복사

          void操作符的一个用例是将表达式求值限制为undefined,这依赖于求值的一些副作用。

          3、 未定义的数组

          访问越界索引的数组元素时,会得到undefined

          const colors = [&#39;blue&#39;, &#39;white&#39;, &#39;red&#39;];
          colors[5];  // => undefined
          colors[-1]; // => undefined
          로그인 후 복사

          colors数组有3个元素,因此有效索引为012

          因为索引5-1没有数组元素,所以访问colors[5]colors[-1]值为undefined

          JS 中,可能会遇到所谓的稀疏数组。这些数组是有间隙的数组,也就是说,在某些索引中,没有定义元素。

          当在稀疏数组中访问间隙(也称为空槽)时,也会得到一个undefined

          下面的示例生成稀疏数组并尝试访问它们的空槽

          const sparse1 = new Array(3);
          sparse1;       // => [<empty slot>, <empty slot>, <empty slot>]
          sparse1[0];    // => undefined
          sparse1[1];    // => undefined
          const sparse2 = [&#39;white&#39;,  ,&#39;blue&#39;]
          sparse2;       // => [&#39;white&#39;, <empty slot>, &#39;blue&#39;]
          sparse2[1];    // => undefined
          로그인 후 복사

          使用数组时,为了避免获取undefined,请确保使用有效的数组索引并避免创建稀疏数组。

          4、 undefined和null之间的区别

          一个合理的问题出现了:undefinednull之间的主要区别是什么?这两个特殊值都表示为空状态。

          主要区别在于undefined表示尚未初始化的变量的值,null表示故意不存在对象。

          让咱们通过一些例子来探讨它们之间的区别。

          number 定义了但没有赋值。

          let number;
          number; // => undefined
          로그인 후 복사

          number 变量未定义,这清楚地表明未初始化的变量。

          当访问不存在的对象属性时,也会发生相同的未初始化概念

          const obj = { firstName: &#39;Dmitri&#39; };
          obj.lastName; // => undefined
          로그인 후 복사

          因为obj中不存在lastName属性,所以JS正确地将obj.lastName计算为undefined

          在其他情况下,你知道变量期望保存一个对象或一个函数来返回一个对象。但是由于某些原因,你不能实例化该对象。在这种情况下,null是丢失对象的有意义的指示器。

          例如,clone()是一个克隆普通JS对象的函数,函数将返回一个对象

          function clone(obj) {
            if (typeof obj === &#39;object&#39; && obj !== null) {
              return Object.assign({}, obj);
            }
            return null;
          }
          clone({name: &#39;John&#39;}); // => {name: &#39;John&#39;}
          clone(15);             // => null
          clone(null);           // => null
          로그인 후 복사

          但是,可以使用非对象参数调用clone(): 15null(或者通常是一个原始值,nullundefined)。在这种情况下,函数不能创建克隆,因此返回null—— 一个缺失对象的指示符。

          typeof操作符区分了这两个值

          typeof undefined; // => &#39;undefined&#39;
          typeof null;      // => &#39;object&#39;
          로그인 후 복사

          严格相等运算符===可以正确区分undefinednull

          let nothing = undefined;
          let missingObject = null;
          nothing === missingObject; // => false
          로그인 후 복사

          总结

          undefined的存在是JS的允许性质的结果,它允许使用:

          • 未初始化的变量

          • 不存在的对象属性或方法

          • 访问越界索引的数组元素

          • 不返回任何结果的函数的调用结果

          大多数情况下直接与undefined进行比较是一种不好的做法。一个有效的策略是减少代码中undefined关键字的出现:

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

          • 使变量生命周期变短并接近其使用的位置

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

          • 多敷衍 const 和 let

          • 使用默认值来表示无关紧要的函数参数

          • 验证属性是否存在或使用默认属性填充不安全对象

          • 避免使用稀疏数组

          更多编程相关知识,请访问:编程入门!!

          위 내용은 JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:dmitripavlutin.com
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿