处理 JS中 undefined 的7个技巧

今天跟大家分享下处理JS中undefined的7个技巧的知识。

前言

大约8年前,开始学习JS时,遇到了一个奇怪的情况,既存在undefined 的值,也存在表示空值的null。它们之间的明显区别是什么?它们似乎都定义了空值,而且,比较null == undefined的计算结果为true。

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

对于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
TypeError: Cannot read property '<prop-name>' of undefined
type errors

JS 开发人员可以理解这个笑话的讽刺:

functionundefined(){
   
// problem solved
}

为了降低此类错误的风险,必须理解生成undefined的情况。更重要的是抑制它的出现并阻止在应用程序中传播,从而提高代码的持久性。

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

1 undefined是什么鬼

JS 有6种基本类型

Boolean: true 或 false
Number: 1, 6.7, 0xFF
String: “Gorilla and banana”
Symbol: Symbol(“name”) (starting ES2015)
Null: null
Undefined: undefined.

和一个单独的Object 类型:{name: “Dmitri”}, [“apple”, “orange”]。

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

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

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

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

上述代码大致流程:

未初始化的变量number

一个不存在的对象属性movie.year

或者不存在数组元素movies[3]

都会被定义为undefined。

ECMAScript规范定义了undefined 值的类型

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

在这个意义上,typeof undefined返回“undefined”字符串

typeofundefined==='undefined';// => true

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

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

2 创建未定义的常见场景

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

let myVariable;
myVariable;// => undefined

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

解决未初始化变量问题的有效方法是尽可能分配初始值。变量在未初始化状态中越少越好。理想情况下,你可以在声明const myVariable ='Initial value’之后立即指定一个值,但这并不总是可行的。

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

当变量一次性且永久地接收到一个值时,建议使用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'); // => true
isPalindrome('hello'); // => false

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

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

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

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

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

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

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

技巧2:增加内聚性
内聚描述模块的元素(命名空间、类、方法、代码块)内聚在一起的程度。凝聚力的测量通常被称为高凝聚力或低内聚。
高内聚是优选的,因为它建议设计模块的元素以仅关注单个任务,它构成了一个模块。
专注且易懂:更容易理解模块的功能
可维护且更容易重构:模块中的更改会影响更少的模块
可重用:专注于单个任务,使模块更易于重用
可测试:可以更轻松地测试专注于单个任务的模块
在这里插入图片描述
高内聚和低耦合是一个设计良好的系统的特征。

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

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

不必要地延长变量生命周期的一个典型例子是函数中for循环的使用:

function someFunc(array) {
   
  var index, item, length = array.length;
  // some code...
  //
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祁娥安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值