1.undefined如何出現express
對於JavaScript,解釋器在訪問還沒有初始化的變量或對象屬性時返回undefined;函數沒有返回值,是undefined
數組
2.null如何出現安全
null
表示缺乏的對象引用,JS自己不會將變量或對象屬性設置爲null;
函數
一些原生方法,好比String.prototype.match()
,能夠返回null
來表示丟失的對象。ui
3.常出現的錯誤:es5
TypeError: 'undefined' is not a function
spa
TypeError: Cannot read property 'xxx' of undefined
prototype
type errors
debug
4.undefinedcode
1.)未爲變量賦值時默認值爲undefined
該標準明肯定義,當訪問未初始化的變量、不存在的對象屬性、不存在的數組元素等時,將接收到一個undefined
的值
2.)Undefined type是其惟一值爲undefined 值的類型
typeof undefined
返回「undefined」字符串
console.log(typeof undefined) //字符串undefined
console.log(typeof undefined ==="undefined") //true
let a;
typeof a=== "undefined"; // => true
3.)致使undefined的常見場景
(1).未初始化變量
myVariable
已聲明,但還沒有賦值,默認值爲undefined
。
解決未初始化變量問題的有效方法是儘量分配初始值。 變量在未初始化狀態中越少越好。
技巧1:使用 let 和 const 來代替 var
技巧2:技巧2:增長內聚性
內聚描述模塊的元素(命名空間、類、方法、代碼塊)內聚在一塊兒的程度。凝聚力的測量一般被稱爲高凝聚力或低內聚。
(2). 訪問不存在的屬性
訪問不存在的對象屬性時,JS 返回undefined
。
let tuandui = {
title: 'bitt uit'
};
console.log(tuandui.alis) // => undefined
修改後:自己訪問不存在的屬性不會引起錯誤, 但嘗試從不存在的屬性值中獲取數據時就會出現問題。 常見的的錯誤是 TypeError: Cannot read property <prop> of undefined
。
eg:
let tuandui = {
title: 'bitt uit'
};
tuandui.alis[0]
console.log(tuandui.alis[0]) // => Uncaught TypeError: Cannot read property '0' of undefined
JS 容許訪問不存在的屬性,這種容許訪問的特性容易引發混淆:可能設置了屬性,也可能沒有設置屬性,繞過這個問題的理想方法是限制對象始終定義它所持有的屬性。
不幸的是,我們經常沒法控制對象
技巧3:檢查屬性是否存在
JS 提供了許多方法來肯定對象是否具備特定屬性:
obj.prop!== undefined
:直接與undefined
進行比較
typeof obj.prop!=='undefined'
:驗證屬性值類型
obj.hasOwnProperty('prop')
:驗證對象是否具備本身的屬性
'prop' in obj
:驗證對象是否具備本身的屬性或繼承屬性
建議使用 in
操做符。in
操做符的存在代表一個明確的意圖,即檢查對象是否具備特定的屬性,而不訪問實際的屬性值。
obj.hasOwnProperty('prop')
也是一個很好的解決方案,它比 in
操做符稍長,僅在對象本身的屬性中進行驗證。
涉及與undefined進行比較剩下的兩種方式可能有效,obj.prop!== undefined
和typeof obj.prop!=='undefined'
看起來冗長。
經過in的實例:
function addTo(array, toAppend) {
const arrayCopy = array.slice();
if ('first' in toAppend) {
arrayCopy.unshift(toAppend.first);
}
if ('last' in toAppend) {
arrayCopy.push(toAppend.last);
}
return arrayCopy;
}
addTo([1,2,3], {
last:4
});
console.log(addTo([1,2,3], {
last: 4
})) //[0, 1, 2, 3, 4]
addTo([10], {
first: 0,
last: false
});
console.log(addTo([10], {
first: 0,
last: false
})) //[0, 10, false]
技巧4:解構訪問對象屬性
在訪問對象屬性時,若是屬性不存在,有時須要指示默認值。可使用in
和三元運算符來實現這一點。
eg:
const thatobj = {};
const prop = 'prop' in thatobj ? thatobj.prop : 'default';
prop; // => 'default'
console.log(prop)
對象解構:對象解構容許將對象屬性值直接提取到變量中,並在屬性不存在時設置默認值,避免直接處理undefined
const thatobj = {};
const {
ab = 'defaults'
} = thatobj;
ab; //
console.log(ab) //=> 'defaults'
eg:
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: '*'
});
console.log(quote('Hello World', {
char: '*'
}))// => '*Hello World*'
quote('Goods day');
console.log(quote('Goods day'))// => "Goods day"
技巧5: 用默認屬性填充對象
若是不須要像解構賦值那樣爲每一個屬性建立變量,那麼丟失某些屬性的對象能夠用默認值填充。
ES6 Object.assign(target,source1,source2,...)
將全部可枚舉的自有屬性的值從一個或多個源對象複製到目標對象中,該函數返回目標對象。
例如,須要訪問unsafes
對象的屬性,該對象並不老是包含其完整的屬性集。
爲了不從unsafes訪問不存在的屬性,讓咱們作一些調整:
定義包含默認屬性值的defaults
對象
調用Object.assign({},defaults,unsafes)
來構建新的對象options
。 新對象從unsafes接收全部屬性,但缺乏的屬性從defaults
對象獲取。
eg:
const unsafe = {
fontSize:60
};
const defaults = {
fontSize: 100,
color: 'white'
};
const options = Object.assign({}, defaults, unsafe);
options.fontSize;
console.log(options.fontSize)// => 60
options.color;
console.log(options.color)// => 'white'
枚舉源對象的順序很重要:後面的源對象屬性會覆蓋前面的源對象屬性。
還有一種簡單的方法就是使用ES6中展開運算符:
const unsafeOptions = {
fontSize: 18
};
const defaults = {
fontSize: 16,
color: 'black'
};
const options = {
...defaults,
...unsafeOptions
};
options.fontSize; // => 18
options.color; // => 'black'
對象初始值設定項從defaults
和unsafeOptions
源對象擴展屬性。 指定源對象的順序很重要,後面的源對象屬性會覆蓋前面的源對象。
使用默認屬性值填充不完整的對象是使代碼安全且持久的有效策略。不管哪一種狀況,對象老是包含完整的屬性集:而且沒法生成undefined的屬性。
(3). 函數參數
函數參數隱式默認爲undefined
一般,用特定數量的參數定義的函數應該用相同數量的參數調用。在這種狀況下,參數獲得指望的值
function multip(a, b) {
a; // => 5
b; // => 3
return a * b;
}
multip(2, 3); // => 6
調用multip(5,3)
使參數a
和b
接收相應的5
和3
值,返回結果:5 * 3 = 15
。
在調用時省略參數會發生什麼?
function multip(a, b) {
a; // => 2
b; // => undefined
return a * b;
}
multiply(2); // => NaN
函數multip(a, b){}
由兩個參數a
和b
定義。調用multip(5)
用一個參數執行:結果一個參數是2
,可是b
參數是undefined
。
技巧6: 使用默認參數值
//技巧6: 使用默認參數值
//es5
function mult(a1, b1) {
if (b1 === undefined) {
b1 = 100;
}
return a1 * b1;
}
mult(5);
console.log(mult(10)) // => 50
function mult(a1, b1) {
if (b1 === undefined) {
b1 = 100;
}
return a1 * b1;
}
mult(5);
console.log(mult(10)) // => 50
//雖然所提供的分配默認值的方法有效,但不建議直接與undefined值進行比較。它很冗長
//這裏可使用 ES6 的默認值:
function mults(a, b = 100) {
return a * b;
}
mults(50);
console.log(mults(50))// => 5000
mults(50, undefined);
console.log(mults(50, undefined))// => 5000
(4).函數返回值
沒有return
語句,JS 函數返回undefined
。
在JS中,沒有任何return
語句的函數隱式返回undefined
:
function square(x) {
const res = x * x;
}
square(2);
console.log(square(2))// => undefined
square()
函數沒有返回計算結果,函數調用時的結果undefined
。
當return
語句後面沒有表達式時,默認返回 undefined
。
function squares(x) {
const res = x * x;
return;
}
squares(10);
console.log(squares(2))// => undefined
return;
語句被執行,但它不返回任何表達式,調用結果也是undefined
。
function square(x) {
const res = x * x;
return res;
}
square(2); // => 4
技巧7: 不要相信自動插入分號
JS 中的如下語句列表必須以分號(;)
結尾:
空語句
let
,const
,var
,import
,export
聲明
表達語句
debugger
語句
continue
語句,break
語句
throw
語句
return
語句
若是使用上述聲明之一,請儘可能務必在結尾處指明分號
let
聲明和 return
語句結束時,強制性寫分號。
固然,不要在return
和返回的表達式之間放置換行符。
(5).void 操做符
void <expression>
計算表達式不管計算結果如何都返回undefined
。
void 1; // => undefined
void (false); // => undefined
void {name: 'John Smith'}; // => undefined
void Math.min(1, 3); // => undefined
void
操做符的一個用例是將表達式求值限制爲undefined
,這依賴於求值的一些反作用。
(6).未定義數組
訪問越界索引的數組元素時,會獲得undefined
。
const colors = ['blue', 'white', 'red'];
colors[5]; // => undefined
colors[-1]; // => undefined
colors
數組有3個元素,所以有效索引爲0
,1
和2
。
由於索引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 = ['white', ,'blue']
sparse2; // => ['white', <empty slot>, 'blue']
sparse2[1]; // => undefined
使用數組時,爲了不獲取undefined
,請確保使用有效的數組索引並避免建立稀疏數組。
4).undefined和null之間的區別
undefined
和null
之間的主要區別是什麼?這兩個特殊值都表示爲空狀態。
主要區別在於undefined
表示還沒有初始化的變量的值,null
表示故意不存在對象。
number 定義了但沒有賦值。
let number;
number; // => undefined
number
變量未定義,這清楚地代表未初始化的變量。
當訪問不存在的對象屬性時,也會發生相同的未初始化概念
const obj = { firstName: 'Dmitri' };
obj.lastName; // => undefined
由於obj
中不存在lastName
屬性,因此JS正確地將obj.lastName
計算爲undefined
。
在其餘狀況下,你知道變量指望保存一個對象或一個函數來返回一個對象。可是因爲某些緣由,你不能實例化該對象。在這種狀況下,null是丟失對象的有意義的指示器。
例如,clone()
是一個克隆普通JS對象的函數,函數將返回一個對象
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操做符區分了這兩個值
typeof undefined; // => 'undefined'
typeof null; // => 'object'
嚴格相等運算符===
能夠正確區分undefined
和null
:
let nothing = undefined;let missingObject = null;nothing === missingObject; // => false