原生JS(3)嚴格模式、變數宣告、型別
(七)嚴格模式
①ECMAScript5 引入了嚴格模式(strict mode)的概念。
嚴格模式是為JavaScript定義了一種不同的解析與執行模型,在這種模式下,ECMA3Script中的一些不確定的行為將得到處理,對不安全的操作也會丟擲錯誤。
②啟用方法:
整個指令碼:
頂部新增 “use strict”
某個函式:
函式內部的第一行(花括號之後的第一行)新增 “use strict”
③相容嚴格模式的瀏覽器:IE10+、FireFox 4+、Safari 5.1+、 Opcra 12+和Chrome
④在嚴格模式下,很多原本可以正常跑的程式碼,都不可以了,會丟擲異常,或者結果有所區別。典型的就是:
function test(value) {
"use strict"
value = 7;
console.log(value, arguments[0]);
}
function test2(value) {
value = 7;
console.log(value, arguments[0]);
}
test(10);
test2(10);
嚴格模式的結果是7,10;
非嚴格模式的結果是7,7;
原因在於,非嚴格模式對引數的操縱會影響arguments中的值,而嚴格模式是不影響的。
參考連結:
(八)變數的宣告
應避免以下這種宣告方式:
function test() { var a = b = 1; } test(); console.log(b);
原因在於,這種情況下,變數a的作用域是程式碼塊,脫離函式後被成功銷燬;
但變數b變成了全域性變數,在console.log(b)中可以正確的顯示其結果。
但以下這種宣告方式是可以的:
function test() {
var a = 1,
b = 1;
}
(九)變數,型別
①typeof
注:輸出結果都是字串,因此可以在if語句裡用===某個字串來匹配是否是某個型別
typeof以下型別變數 | 輸出結果 |
宣告未賦值/未宣告變數 | undefined |
布林值 | boolean |
數值 | number |
物件或者null | object |
函式 | function |
②null和undefined
null == undefined 返回值為true;
null === undefined 返回值為false
原因在於,undefined是null派生而來的。
③boolean
true == 1 返回值true
true == ‘1’ 返回值true
true === 1 返回值false
false同理
Boolean('')和Boolean(' ')的值,分別是false和true
Boolean是一個布林型別的強制轉換函式
轉換後為false 的:(1)空字串;(2)數字0;(3)null;(4)NaN;(5)undefined;(6)false本身
放在if等判斷語句裡,會自動轉換;
④number
(1)八進位制:賦值時,0開頭,且符合要求(例如每位數字都在0~7之間),如果數字超出,忽略開頭的0,當做10進位制解釋(不使用數字除外,會出錯);
八進位制嚴格模式下(“use strict”)無效
十六進位制:賦值時,0x開頭(或0X),如果使用非範圍內數字字母,會出錯,字母可大寫可小寫;
十進位制:其他正常賦值時。
計算時,會轉為十進位制來計算。
(2)浮點數:即小數;
l 存在精度問題(17位);
l 末尾0很多時(var a = 0.000000000000000000001或var a = 10000000000000000000000)會被轉化為1e然後後面跟一個整數或者負數;
l 不要計算兩個浮點數相加後和另外一個浮點數他們之間的結果是否相等(0.1+0.2 == 0.3的結果是false,其值為0.30000000000000004),除此之外還有0.1+0.7結果是0.7999999999999999等
l 最小值大概是5e-324,最大值是1.7xxxx e+308。假如某次計算超出這個數值,會轉換為Infinity(正無窮)或 -Infinity(負無窮);Infinity減去或除以Infinity的結果是NaN,乘以或者加上依然是Infinity;Infinity - 1結果還是Infinity;Infinity*0結果是NaN,/0結果是Infinity;1/0結果也是Infinity(火狐和chrome,其他未驗證),而不是書上說的NaN,但0/0是結果是NaN
(3)NaN 非數值,是一種特殊的數值
0/0結果是NaN,其他數值除以0則不是;
NaN == NaN 的結果是false,包括三個等號的結果
isNaN()可以用於測試一個數值是否是NaN,能被轉化為數值的為false(比如字串),不能轉化為數值的為true,比如字串為true,true/false為false,undefined為true等;
可以檢測物件,但並非必然是true。檢測方式是呼叫物件的valueOf()方法,之後是toString(),根據其值決定是true還是false(有一個為false即為false,都是true才是true),;空物件返回true,但例如以下情況則返回false:
var a = {}; //true
var a = { valueOf: 1}; //true
var a = { valueOf: function(){return 1}}; //false
var a = { toString: function(){return 1;}} //false
var a = { toString: function(){return "a";}} //true
(4)數值轉換
三個轉換函式:Number(), parseInt(), parseFloat()
Number()
源 |
目標 |
true/false |
1或0 |
數字 |
返回數字 |
null |
0 |
undefined |
NaN |
字串:純數字 |
作為十進位制數字轉換,忽略開頭0,因此不存在八進位制識別 |
字串:浮點數(無其他干擾) |
浮點數 |
字串:十六進位制格式 |
十六進位制數識別,然後轉換為十進位制 |
字串:空 |
0 |
字串其他:例如在以上情況下有其他字元干擾 |
NaN |
parseInt()
源 |
結果 |
字串開頭有非0~9非空格字元 |
NaN |
空格開頭的字串 |
忽略空格後看上一行,不符合的話看下一行 |
0x開頭後面跟數字比如0x1 |
當十六進位制數字識別,剩下的看第六行 |
失效 |
實際測試失效,例如parseInt("070") 返回70而不是56 |
普通數字開頭 |
當做十進位制數字識別 |
數字後跟字母或空格 (重要) |
如果是十六進位制數,遇見非a~f字母后,從該位置開始忽略後面的; 如果是十進位制數字,遇見字母后,從第一個字母開始忽略後面的 |
小數 |
識別為整數 |
當parseInt()當存在第二個引數時,第二個引數用於作為轉換時的基制,即多少進位制;假如以下是
例如parseInt("11",2)的結果是3,parseInt("11",11)的結果是12。前者是作為二進位制識別,後者是作為十一進位制識別。
第二個引數為1時NaN,0則使用預設,當第一個引數不是十進位制數字時,返回值為0,例如parseInt("0x11",2)作為二進位制解析時,其值為0(x不能作為二進位制識別);
0x開頭的,第二個引數只能使用16(轉換為十六進位制),否則無法識別(正常識別,識別結果為0)。
當使用第二個引數時,則不會將其設法轉換為十六進位制,而是作為普通字串來處理。
按照教程所說:
如果我們要預設其以某個進位制來轉換,應該顯式的在第二個引數宣告他,例如第二個引數寫10,預設其為10進位制,這樣的話,當其看起來像16進位制數字,可以避免用十六進位制來解釋
parseFloat()
和parseInt()類似的識別方式,只不過他會忽視開頭的0或者空格,識別到非浮點數為止。也就是說,他不認十六進位制或者其他。
例如:parseFloat("0x1.1")返回0(不識別十六進位制);
parseFloat("0000.11")返回0.11(前面加若干空格結果也一樣)
parseFloat(" 0 000.11")返回0,因為從開始識別的位置之後,他不會忽視空白字元。
⑤string型別
【1】轉義字元:
字元 |
表示 |
\n |
換行 |
\t |
製表符 |
\b |
空格 |
\r |
回車 |
\f |
走紙換頁 (然而並不明白所以給個搜尋連結https://www.google.com/#newwindow=1&q=%E8%B5%B0%E7%BA%B8%E6%8D%A2%E9%A1%B5) |
\xnn |
nn是十六進位制字元,x需要小寫。需要2位n。 用於表示字元,其是ASCII字符集,比如41轉換為十進位制為65,ASCII中65表示A |
\unnnn |
類似上面,x小寫,n十六進位制,四位n都要有,表示Unicode字符集。 |
物件無toString方法 |
"[object Object]" |
物件有toString方法 |
toString方法的返回值 |
【2】.length屬性
字串都有;
不能正確識別漢字是兩個字元的長度;
轉義字元是轉義後的長度。例如”\x41”表示字母A,他的長度則為1
【3】其他型別轉為字串:
(1)呼叫toString()方法;
l .toString()方法在加上引數後,可以將一個數字轉換為2~36進制中的任何一個;例如:(113).toString(30)的返回值是"3n"
l true轉為”true”;
l 普通數字轉為數字;
l 十六進位制數字轉為10進位制數字後輸出。例如:(0x1a).toString()返回26
l null和undefined沒有這個方法,會出錯。
l 字串本身也有這個方法。但這個方法不能被覆寫。例如var a=”a”;a.toString = function(){return "b"}; 這個時候再呼叫a.toString(),則返回值依然為”a”,而不是”b”
(2)使用String()方法,被轉換的變數作為引數
假如一個方法有toString()方法,則呼叫之;
假如沒有(只剩null和undefined),則null變為”null”,undefined變為”undefined”
(3)通過+號連線符,隱式呼叫toString方法
比如說拼接;
var a={};
a.toString = function(){return "bb"}
a+”aa”的返回值是”bbaa”
⑥object物件
【1】每個object物件都具有的方法:
(1)constructor:顯示一個物件建構函式的方法;
用例一:檢視某個物件的建構函式。
假如有一個我們自定義的函式
function test(a, b) {
this.a = a;
this.b = b;
}
我們new一個他的例項
var m = new test();
這個時候m的constructor是什麼呢,就是上面那個函式;
用例二:
我們如何判斷一個物件是否是某個類的例項,很簡單,就像在上面那樣,呼叫constructor屬性和原類進行比值(可以用三個等號)。
例如:
function test(a, b) {
this.a = a;
this.b = b;
}
var m = new test();
console.log(m.constructor === test);
其返回子是true
類似,陣列的constructor的值是Array(沒有引號),字串是String,數字是Number,布林值是Boolean
var test = new Array;
console.log(test.constructor === Array);
【2】hasOwnPrototype(“某屬性”)
(1)用於檢測某個物件的例項是否具有某個屬性;
(2)只檢測當前例項有沒有,跟原型有沒有無關;
(3)原型鏈上繼承來的屬性無法檢測到。
示例:
function test(a) {
this.a = a;
}
var m = new test(1);
console.log(m.hasOwnProperty("a")); //檢測有沒有a屬性,原型有,所以有
console.log(m.hasOwnProperty("b")); //檢測有沒有b屬性,原型沒有,目前沒有
m.b = function(){};
console.log(m.hasOwnProperty("b")); //檢測有沒有b屬性,原型沒有,但後來賦值了,所以有
返回值依次是:true, false, true
證明了(1)和(2)
function test(a) {
this.a = 1;
}
var a = new test();
test.prototype.test2 = function () {
return "1";
}
console.log(a.test2());
console.log(a.hasOwnProperty("test2"));
返回值依次為1和false
說明例項的原型繼承到的方法,是被例項所繼承的,但是無法通過hasOwnPrototype來檢測。
擴充套件:
之前的情況,可以通過in來檢測,例如;
console.log("test2" in a);
返回值為true
for in方法也是可以檢測到的
for (var i in a) {
console.log(i)
}
輸出:a和test2
但據說老版本的瀏覽器上是不可以的,參照《for in的缺陷》:
【3】obj1.prototype.isPrototypeOf(obj2)
(1)用於檢測呼叫這個方法的物件obj1,是否是引數obj2的原型;
例如:
function test(a) {
this.a = 1;
}
var b = new test();
console.log(test.prototype.isPrototypeOf(b));
返回值為true;
說明test是b的原型。
(2)************* 問題 *************:
按照說明,他會檢查原型鏈上的繼承,但我自己測試後,假如是繼承,那麼返回值依然為false,如下:
function test() {
}
function test2() {
}
test2.prototype.test = test;
var m = new test2();
console.log(test2.prototype.isPrototypeOf(m));
console.log(test.prototype.isPrototypeOf(m));
返回值依次為true和false
test的確在test2的原型鏈上,但是返回值為false。搞不懂。
也許是我搞錯了原型鏈上的繼承。
【4】.propertyIsEnumerable(屬性名)
(1)檢測某個屬效能否使用for in語句來列舉,引數需要是字串型別
(2)無視原型鏈上的內容(即無法檢測原型鏈上的)
例如:
function test() { //原型
this.a = 1;
}
test.prototype.b = "test"; //test2方法是test的一個屬性
var m = new test();
console.log(m.propertyIsEnumerable("b"));
console.log(m.propertyIsEnumerable("a"));
var n = {a: 1, b: 2};
console.log(n.propertyIsEnumerable("a"));
返回值依次為false,true,true
在這裡,m是test的例項;b是test繼承的一個屬性;
因此,這兩個都可以通過for in來顯示,但由於a是test的屬性,而b是通過繼承來的,因此propertyIsEnumberable是無法檢測到b的。故一個返回false,一個返回true
n有屬性a,因此其返回值為true
【5】toLocaleString()
(1)返回物件的字串表示;
(2)該字串與執行環境的地區對應。
具體不太清楚,先放置吧,也許和下面的有關係?
【6】toString()
(1)返回物件的字串表示。可以通過手動覆寫的方法,使其可以用於物件可以和字串相加,然後返回字串。例如:
var m = {a: 1, b: 2};
m.toString = function () {
return "m";
}
console.log(m + "n");
返回值是字串mn
此時:
console.log(m.toLocaleString());
輸出的值也是字串m
【7】valueOf()
(1)按照說明:返回物件的字串、數值、或布林值表示。通常與toString()的返回值相同。但並不是這樣,個人覺得是和物件本身的值是一樣的
例如:
var m = {a: 1, b: 2};
console.log(m.toString());
console.log(m.valueOf());
輸出值是:字串[object Object]和物件Object {a: 1, b: 2}
即使覆寫m的toString()方法,valueOf()輸出的值依然是Object {a: 1, b: 2}