목차
1、undefined 是什么鬼" >1、undefined 是什么鬼
1. 정의되지 않은 것이 도대체 무엇인가요?
  • " >
  • 1. 정의되지 않은 것이 도대체 무엇인가요?
  • 2、导致undefined的常见场景" >2、导致undefined的常见场景
    🎜2. 정의되지 않음🎜" >🎜2. 정의되지 않음🎜
    3、 未定义的数组" >3、 未定义的数组
    4、 undefined和null之间的区别" >4、 undefined和null之间的区别
    总结" >总结
    웹 프론트엔드 JS 튜토리얼 JavaScript에서 정의되지 않은 문제를 처리하기 위한 7가지 팁

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

    Oct 13, 2020 pm 06:06 PM
    javascript

    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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

      본 웹사이트의 성명
      본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

      핫 AI 도구

      Undresser.AI Undress

      Undresser.AI Undress

      사실적인 누드 사진을 만들기 위한 AI 기반 앱

      AI Clothes Remover

      AI Clothes Remover

      사진에서 옷을 제거하는 온라인 AI 도구입니다.

      Undress AI Tool

      Undress AI Tool

      무료로 이미지를 벗다

      Clothoff.io

      Clothoff.io

      AI 옷 제거제

      Video Face Swap

      Video Face Swap

      완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

      뜨거운 도구

      메모장++7.3.1

      메모장++7.3.1

      사용하기 쉬운 무료 코드 편집기

      SublimeText3 중국어 버전

      SublimeText3 중국어 버전

      중국어 버전, 사용하기 매우 쉽습니다.

      스튜디오 13.0.1 보내기

      스튜디오 13.0.1 보내기

      강력한 PHP 통합 개발 환경

      드림위버 CS6

      드림위버 CS6

      시각적 웹 개발 도구

      SublimeText3 Mac 버전

      SublimeText3 Mac 버전

      신 수준의 코드 편집 소프트웨어(SublimeText3)

      WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 Dec 17, 2023 pm 02:54 PM

      WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

      WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 Dec 17, 2023 pm 05:30 PM

      WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

      JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 Dec 17, 2023 pm 12:09 PM

      JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

      WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 Dec 17, 2023 am 09:39 AM

      WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

      JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 Dec 17, 2023 pm 05:13 PM

      JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

      간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 Jan 05, 2024 pm 06:08 PM

      JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

      자바스크립트에서 insertBefore를 사용하는 방법 자바스크립트에서 insertBefore를 사용하는 방법 Nov 24, 2023 am 11:56 AM

      사용법: JavaScript에서 insertBefore() 메서드는 DOM 트리에 새 노드를 삽입하는 데 사용됩니다. 이 방법에는 삽입할 새 노드와 참조 노드(즉, 새 노드가 삽입될 노드)라는 두 가지 매개 변수가 필요합니다.

      JavaScript 및 WebSocket: 효율적인 실시간 이미지 처리 시스템 구축 JavaScript 및 WebSocket: 효율적인 실시간 이미지 처리 시스템 구축 Dec 17, 2023 am 08:41 AM

      JavaScript는 웹 개발에 널리 사용되는 프로그래밍 언어인 반면 WebSocket은 실시간 통신에 사용되는 네트워크 프로토콜입니다. 두 가지의 강력한 기능을 결합하면 효율적인 실시간 영상 처리 시스템을 만들 수 있습니다. 이 기사에서는 JavaScript와 WebSocket을 사용하여 이 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 첫째, 실시간 영상처리 시스템의 요구사항과 목표를 명확히 할 필요가 있다. 실시간 이미지 데이터를 수집할 수 있는 카메라 장치가 있다고 가정해 보겠습니다.

      See all articles