180203 類型、值和變量

數據類型

JavaScript 數據類型分爲:原始類型 和 對象類型。

原始類型 對象類型
數字 (6.02e23 ; Infinity):均用浮點數值表示 普通對象
字符串 (‘ name = ” myform ” ’) 數組
布爾值 函數
null (空值)
undefined(未定義的值,表示更深層次的空值)

操作數極限:小數點前後17位


1.數字[Date | Math]

非數字值(not-a-number): NaN 和任何值都不相等,包括自身

因此無法通過 x == NaN 來判斷變量 x 是否是 NaN
應當使用 x !== x 來判斷,當且僅當 x 爲 NaN 時返回 true

isNaN() : 判斷是否是非數字,參數是NaN,字符串或者對象時返回 true
(會隱式類型轉換)

var a = isNaN('10');  //  false : isNaN(Number('10'));發生隱示類型轉換

isFinite() : 檢測無窮數,參數不是NaN,Infinity,-Infinity的時候返回 true

# isNaN() isFinity()
number false true
Infinity false false
string true false
‘’ false true
boolean false true
null false true
undefined true false
{} true false
[1] false true
[‘a’] true false
function true false
  • 數字,布爾值,null,“ ”,[純數字數組] 都是數字值。
  • 數字,布爾值,null,“ ”,[純數字數組] 都是有窮數值。

2.字符串 [String | RegExp]

可讀性上:可以使用 ’ \ ’ 來讓字符串折行,不算做字符串直接量的內容

顯示上:可以使用 ’ \n ’ 來讓字符串折行顯示

當字符串有單引號包裹時,裏面想顯示單撇號需要轉義” \ ’ “

console.log('O\'Reilly\'s');
---- O'Reilly's

2.1 字符串拼接

’ + ’ 用於字符串拼接

msg = "Hello," + "world";   
---- "Hello, world"

可以使用索引來查看字符串中的單個字符

var a = 'hello' ; console.log(a[0]);
---- "h"

2.2 模式匹配-正則表達式


3.布爾值

  • 任意JavaScript值都可以轉化爲布爾值
  • 會轉化成 ‘false’ 的值是:undefined、null、0、NaN、”空”

4.undefined

  • 查詢對象屬性或數組元素的值時返回undefined 說明這個屬性或元素不存在。
  • 若函數沒有返回值,則返回undefined
  • 引用沒有提供實參的函數形參的值,返回undefined
  • undefined是預定義的全局變量
  • undefined是系統級的,出乎意料的或類似錯誤的值的空缺
  • null是程序級的,正常的或在意料之中的空缺

全局對象(待深入)

全局對象的屬性是全局定義的符號,程序可以直接使用。

當JS解釋器啓動時(或者瀏覽器加載新頁面時),它將創建一個全局對象,並定義一組初始屬性:

  • 全局屬性
  • 全局函數
  • 構造函數
  • 全局對象

包裝對象

var obj = new String(a)
var obj = new Number(b)
var obj = new Boolean(c)

對象可以通過 ‘.’ ‘[]’ 來調用屬性,字符串不是對象,爲什麼可以調用屬性呢?

  • 引用了字符串的屬性後,JavaScript就會將字符串值通過調用 new String(s)的方式轉換成對象,這個對象繼承了字符串的方法,並被用來處理屬性的引用。一旦屬性引用結束,這個新創建的對象就會銷燬。
  • 數字和布爾值也有對應的方法:Number() , Boolean() 構造函數創建一個臨時對象。
  • null和undefined沒有包裝對象,訪問它們的屬性會造成一個類型錯誤。
var s = 'test'; //創建一個字符串
s.len = 4;    //設置屬性
var t = s.len; //查詢這個屬性

new String(str).len = 4
vat t = new String(str).len
  • 執行代碼,輸出t值是undefined。第二行代碼創建一個臨時字符串對象,並給其len屬性賦值爲4,隨即銷燬這個對象。第三行通過原始字符串值創建一個新字符串包裝對象,嘗試讀取其len屬性,這個屬性自然不存在。
  • 字符串、數字、布爾值的屬性都是隻讀的,不能給他們定義新屬性。(給其屬性賦值會被忽略這個操作)
  • 可以通過構造方法顯示創建包裝對象。
var s = 'test', n = 1 , b = true;
var S = new String(s);
var N = new Number(n);
var B = new Boolean(b);
  • JavaScript會在必要時將包裝對象轉換成原始值。
  • 因此 S B N 常常(但不總是)表現的和值 s b n一樣。
  • S == s –> true
  • S === s –> false

原始值和引用值

原始值

  • 原始值不可更改,字符串中的方法看上去返回了一個修改後的字符串,實際上返回的是一個新的字符串值,原始字符串的值並未改變。
  • 原始值的比較是值的比較。

引用值

  • 常將對象稱爲引用類型。對象值都是引用,對象比較均是引用的比較。

  • 對象的值可以修改。

  • 對象的比較:及時兩個對象包含同樣的屬性及相同的值,它們也不是相等的。各個索引元素完全相同的數組也不相等。當且僅當它們引用同一個基對象時,它們才相等。
var o = {x:1}, p = {x:1};
// o === p -> false:兩個單獨的對象永不相等
var a = [], b=[];
// a === b -> false:兩個單獨的數組永不相等

這裏寫圖片描述

引用同一個地址,兩個變量棧數據相同,指向同一個堆數據。

var a = [];// 定義一個引用空數組的變量a
var b = a; // 變量b引用同一個數組
b[0] = 1; // 通過變量b修改引用的數組
// a[0] -> 1:變量a也會改變
// a === b -> true:a和b引用同一個數組
  • 以上僅僅是賦值的引用值:對象本身沒有複製。
var a = ['a','b','c'];
var b = [];
for(var i = 0; i< a.length; i++){
    b[i] = a[i];
}
// 顯式複製對象

如果想 單獨 比較兩個對象或數組:

function equalArrays(a,b){
    if(a.length != b.length) return false; 
    for(var i = 0; i < a.length; i++)
    if(a[i] !== b[i]) return false;
    return true;
}

類型轉換

1 原始值 -> 原始值 [顯式,隱式,方法]
2 原始值 -> 對象 [調用 構造函數 轉化爲 包裝對象]
3 對象 -> 原始值


數字 -> 字符串

  • 顯式類型轉換
    Boolean() Number() String() Object()
    當不通過new運算符調用這些函數時,它們會作爲類型轉換函數使用。
Number('3')  //3    !!要求嚴格數字格式!!
String(false)  // 'false' 相當於 false.toString()
Boolean([])  // true
Object(3)  // new Number(3)

除了null或undefined之外的任何值都具有toString()方法,執行結果通常和String()方法返回的結果一致。如果試圖把null和undefined轉換爲對象,Object()函數會返回一個新的空對象。

  • 隱式類型轉換
//如果'+'運算符的一個操作數是字符串,它將會把另外一個操作數轉換爲字符串。
//加號 一個字符 結果必定是字符串 
var a0 = 1 + '';        // '1' 也是字符
var a1 = 1 + 'a';       // '1a'
var a2 = 1 + '1';       // '11'
var a3 = 1 + '1.2';     // '11.2'

//正常情況下,一元運算符 '+' '-' '*' '/' 將其操作數轉換爲數字。
//加號 沒有字符 按照轉換表相應轉換 其他類型結果NaN 

var a4 = 1 + true;         // 2
var a5 = 1 + false;        // 1
var a6 = 1 + null;         // 1
var a7 = 1 + undefined;    // NaN
var a8 = 1 + Infinity;     // Infinity
var a9 = 1 + -Infinity;    // -Infinity
var a10 = true + true;     // 2
var a11 = null + null;     // 0
var a12 = Infinity + Infinity; // Infinity


var b1 = 1 - 'a';          // NaN
var b2 = 2 - '1';          // 1
var b3 = 1 - true;         // 0
var b4 = 1 - Infinity;     // -Infinity
var b5 = Infinity - 1;     // Infinity
var b6 = 1 * 'a';          // NaN
var b7 = 1 * '3';          // 3
var b8 = 1 * true;         // 1
var b9 = 1 / '1';          // 1
var b10 = 1 / '2';         // 0.5
var b11 = 1 / true;        // 1
var b12 = 1 / Infinity;    // 0
var b13 = 1 / -Infinity;   // -0

-----------------------------------
隱示類型轉換
isNaN('10');  // false
if(10 && 'a') console.log('hello');
// if(Boolean(10) && Boolean('a'))   
  • Number.toString(radix) [10進制轉其它進制]

作用:將一個數字轉換爲字符串。
參數:表示進制,默認十進制。
返回:當前數字在指定進制下的字符串形式。
注意:Number對象使用。

var n = 17;
console.log(n.toString(2));
console.log('0' + n.toString(8));
console.log('0x' + n.toString(16));

這裏寫圖片描述

  • Number.toFixed(digits)

作用:小數求有效數字。
參數:小數點後要顯示的數字數量。省略相當於0。

  • Number.toExponential(digits)

作用:科學計數法。
參數:小數點之後出現數字的數目。

  • Number.toPrecision()

字符串 -> 數字

  • parseInt(‘string’ , num) [其它進制轉換10進制]

作用:從字符中解析整數。
參數:可以接收第二個可選參數,參數指定數字轉換的基數,合法的取值範圍是2~36。
特點:直解析整數。如果字符串前綴是 ’ 0x ’ , 可以將其識別成十六進制數。

console.log(parseInt('11', 2));   // 3 (1*2+1)
console.log(parseInt('ff', 16));  // 255 (15*16+15)
console.log(parseInt('zz', 36));  // 1295 (35*36+35)
console.log(parseInt('077', 8));  // 63 (7*8+7)
console.log(parseInt('077', 10)); // 77 (7*10+7)
  • parseFloat()

作用:從字符中解析數值。
特點:可以解析整數和浮點數。

  • 這兩個方法是全局函數,不屬於任何類的方法,更加靈活。
  • 它們會跳過任意數量的前導空格,儘可能解析更多數值字符。
  • 如果第一個非空格字符是非法的數字直接量,返回NaN。
console.log(parseInt('3 black boys'));
console.log(parseFloat('3.14 meters'));
console.log(parseInt('-12.34'));
console.log(parseInt('0xff'));
console.log(parseInt('0xFF'));
console.log(parseInt('-0xff'));
console.log(parseFloat('.1'));
console.log(parseInt('0.1'));
console.log(parseInt('.1'));
console.log(parseFloat('$72.98'));

這裏寫圖片描述


對象 –> 布爾值

  • 所有對象都轉換爲true。
  • 包裝對象也是。
var x = new Boolean(false); //這是一個對象
console.log(x);
console.log(Boolean(x)); //Boolean(對象) 

這裏寫圖片描述


對象 -> 數字,字符串

轉換規則只適用於本地對象。宿主對象根據各自的算法可以轉化成字符串和數字。

所有對象都繼承了兩個轉換方法。

  • object.toString()

    作用:定義一個對象的字符串表示形式。可以用於判斷未知對象的類型。
    返回:一個表示這個對象的字符串。[ object class ]
    注意:大多數對象都有自定義版本的toString(),需要在對象上顯式的調用:

Object.prototype.toString.apply(o);
  • object.valueOf()

變量作用域

一個變量的作用域是程序源代碼中定義這個變量的區域。

  • 全局變量擁有全局作用域,在代碼任何地方都有定義。
  • 函數內聲明的變量只在函數體內有定義。
  • 它們是局部變量,作用域是局部性的。
  • 函數參數也是局部變量,它們只在函數體內有定義。

在函數體內,局部變量的優先級高於同名的全局變量。

如果在函數內聲明的一個局部變量或者函數參數中帶有的變量和全局變量重名,那麼全局變量就被局部變量所遮蓋。

var scope = "global";    // 聲明一個全局變量

function checkscope() {  
    var scope = "local";   // 聲明一個同名的局部變量
    return scope;          // 返回局部變量
}
checkscope()

儘管在全局作用域編寫代碼時可以不寫var語句,但聲明局部變量時則必須使用var語句。

var  scope = " global scope";
 function checkscope(){
     var scope = "local scope";
     function nested(){
         var scope = "nested scope"
         return scope;
     }
     return nested();
 }
 checkscope()   // nested scope

函數作用域和聲明提前

函數作用域:變量在聲明它們的函數體以及這個函數體嵌套的任意函數體內都是有定義的
函數作用域是指在函數內聲明的所有變量在函數體內始終可見。
這意味着變量在聲明之前甚至已經可用。這個特性稱爲 聲明提前,即函數裏聲明的所有變量都被“提前”至函數體的頂部。

var scope = "global",
function f(){
    console.log(scope);  // 輸出undefined
    var scope = "local"; // 變量在這裏賦初始值,
    // 但變量本身在函數體內任何地方均是可見的。
    console.log(scope); // 輸出local
}

在函數體內局部變量遮蓋了同名全局變量。儘管如此,只有在程序執行到var語句的時候,局部變量纔會被真正賦值。上述過程等價於:將函數內的變量聲明“提前”至函數體頂部,同時變量初始化留在原來的位置。

function f(){
    var scope;            //在函數頂部聲明瞭局部變量
    console.log(scope);   //變量存在,但其值是“undefined”
    scope = "local";      //這裏將其初始化並賦值
    console.log(scope);   //這裏它具有了我們所期望的值
}

由於JS沒有塊級作用域,因此一些程序員特意將變量聲明放在函數體頂部,而不是將聲明靠近放在使用變量之處。這種做法使得他們的源代碼非常清晰地反映了真實的變量作用域。

作爲屬性的變量

當聲明瞭一個JS全局變量時,實際上定義了全局對象的一個屬性。當使用var聲明一個變量時,創建這個屬性是不可配置的。也就是說這個變量無法通過delete運算符刪除。
在沒有使用嚴格模式的並給一個未聲明的變量賦值的話,JS會自動創建一個全局變量。以這種方式創建的變量是全局對象的正常的可配置屬性,並可以刪除:

var truevar = 1;   //聲明一個不可刪除的全局變量
fakevar = 2;       //創建全局對象的一個可刪除的屬性
this.fakevar2 = 3; //
delete truevar     // false 變量沒被刪除
delete fakevar     // true  變量被刪除
delete this.fakevar2  // true 變量被刪除

JS全局變量時全局對象的屬性。局部變量當做跟函數調用相關的某個對象的屬性。ES3稱該對象爲“調用對象”,ES5規範稱“聲明上下文對象”。

作用域鏈

每一個JS代碼都有一個與之關聯的作用域鏈(scope chain)。
這個作用域鏈是一個對象列表或者鏈表,這組對象定義了這段代碼“作用域中”的變量。
當JS需要查找變量x的值的時候(這個過程叫做“變量解析”):它會從鏈中的第一個對象開始查找,直到查找到屬性。如果作用域鏈上沒有任何一個對象含有這個屬性,最後會拋出一個異常。

在JS最頂層代碼中(也就是不包含任何函數定義內的代碼),作用域鏈由一個全局對象組成。
在不包含嵌套的函數體內,作用域上有兩個對象,一個是定義函數參數和局部變量的對象,一個是全局對象。
在一個嵌套函數裏,至少含有三個對象。

發佈了44 篇原創文章 · 獲贊 2 · 訪問量 5028
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章