【JS】671- 7个处理undefined的技巧
let company;
company; // => undefined
let person = { name: 'John Smith' };
person.age; // => undefined
let array = null;
array; // => null
let movie = { name: 'Starship Troopers', musicBy: null };
movie.musicBy; // => null
'abc'.match(/[0-9]/); // => null
TypeError:'undefined'不是函数
TypeError:无法读取未定义的属性'
'' 和类似type errors。
function undefined() {
// problem solved
}
1、 什么是undefined
Boolean: true or false Number: 1, 6.7, 0xFF String: "Gorilla and banana" Symbol: Symbol("name") (starting ES2015) Null: null Undefined: undefined.
未定义的值原始值在变量未被赋值时使用。
let number;
number; // => undefined
let movie = { name: 'Interstellar' };
movie.year; // => undefined
let movies = ['Interstellar', 'Alexander'];
movies[3]; // => undefined
未定义类型是唯一值为“未定义”值的类型。
typeof undefined === 'undefined'; // => true
let nothing;
typeof nothing === 'undefined'; // => true
2、 创建未定义的常见场景
2.1 未初始化的变量
一个尚未赋值的声明变量( uninitialized )默认为undefined。
let myvariable;
myvariable; // => 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
function bigFunction() {
// code...
myvariable; // => undefined
// code...
var myVariable = 'Initial value';
// code...
myVariable; // => 'Initial value'
}
bigFunction();
function bigFunction() {
// code...
myVariable; // => Throws 'ReferenceError: myVariable is not defined'
// code...
let myVariable = 'Initial value';
// code...
myVariable; // => 'Initial value'
}
bigFunction();
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
易于测试
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';
}
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
let favoriteMovie = {
title: 'Blade Runner'
};
favoriteMovie.actors[0];
// TypeError: Cannot read property '0' of undefined
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]
typeof obj.prop!=='undefined':验证属性值的类型 *obj.hasOwnProperty('prop'):验证对象是否拥有自己的属性
obj`中的'prop':验证对象是否有自己的或继承的属性
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]
const object = { };
const prop = 'prop' in object ? object.prop : 'default';
prop; // => 'default'
const object = { };
const { prop = 'default' } = object;
prop; // => 'default'
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)
```javascript
function 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"'
定义一个保存默认属性值的对象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; // => 18
options.color; // => 'black'
const unsafeOptions = {
fontSize: 18
};
const defaults = {
fontSize: 16,
color: 'black'
};
const options = {
...defaults,
...unsafeOptions
};
options.fontSize; // => 18
options.color; // => 'black'
2.3 函数的参数
函数参数默认默认为undefined。
function multiply(a, b) {
a; // => 5
b; // => 3
return a * b;
}
multiply(5, 3); // => 15
function multiply(a, b) {
a; // => 5
b; // => undefined
return a * b;
}
multiply(5); // => NaN
function multiply(a, b) {
if (b === undefined) {
b = 2;
}
a; // => 5
b; // => 2
return a * b;
}
multiply(5); // => 10
function multiply(a, b = 2) {
a; // => 5
b; // => 2
return a * b;
}
multiply(5); // => 10
multiply(5, undefined); // => 10
2.4 函数返回值
隐式地,没有return语句,JavaScript函数返回undefined。
function square(x) {
const res = x * x;
}
square(2); // => undefined
function square(x) {
const res = x * x;
return;
}
square(2); // => undefined
function square(x) {
const res = x * x;
return res;
}
square(2); // => 4
空的陈述
let,const,var,import,export声明
表达式语句
调试器语句
继续语句,break语句
抛出声明
return语句
function getNum() {
// Notice the semicolons at the end
let num = 1;
return num;
}
getNum(); // => 1
function getNum() {
// Notice that semicolons are missing
let num = 1
return num
}
getNum() // => 1
function getPrimeNumbers() {
return
[ 2, 3, 5, 7, 11, 13, 17 ]
}
getPrimeNumbers() // => undefined
function getPrimeNumbers() {
return;
[ 2, 3, 5, 7, 11, 13, 17 ];
}
getPrimeNumbers(); // => undefined
function getPrimeNumbers() {
return [
2, 3, 5, 7, 11, 13, 17
];
}
getPrimeNumbers(); // => [2, 3, 5, 7, 11, 13, 17]
2.5 void 运算
void 1; // => undefined
void (false); // => undefined
void {name: 'John Smith'}; // => undefined
void Math.min(1, 3); // => undefined
3、数组中的undefined
const colors = ['blue', 'white', 'red'];
colors[5]; // => undefined
colors[-1]; // => undefined
const sparse1 = new Array(3);
sparse1; // => [`
`, ` `, ` `] sparse1[0]; // => undefined
sparse1[1]; // => undefined
const sparse2 = ['white', ,'blue']
sparse2; // => ['white', `
`, 'blue'] sparse2[1]; // => undefined
4、undefined and null 之间的不同
let number;
number; // => undefined
const obj = { firstName: 'Dmitri' };
obj.lastName; // => undefined
function clone(obj) {
if (typeof obj === 'object' && obj !== null) {
return Object.assign({}, obj);
}
return null;
}
clone({name: 'John'}); // => {name: 'John'}
clone(15); // => null
clone(null); // => null
typeof undefined; // => 'undefined'
typeof null; // => 'object'
let nothing = undefined;
let missingObject = null;
nothing === missingObject; // => false
5、总结
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 当方法调用返回空时
减少未初始化变量的使用
使变量生命周期变短并接近其使用的来源
尽可能为变量分配一个初始值
支持const,否则使用let
使用默认值作为无意义的函数参数
验证属性的存在或用缺省属性填充不安全的对象
避免使用稀疏数组
回复“加群”与大佬们一起交流学习~
点击“阅读原文”查看70+篇原创文章