BACK
Featured image of post TypeScript 裡 string 和 String,還真不僅僅是大小寫的區別!

TypeScript 裡 string 和 String,還真不僅僅是大小寫的區別!

TypeScript 是 JavaScript 的超集(superset),TypeScript 需要編譯(語法轉換)生成 JavaScript 才能被瀏覽器執行,它也區分了 string 和 String 這兩個資料型別。通常來說,string 表示原生型別,而 String 表示物件。

參考網站
參考網站
參考網站
參考網站


背景

與 JavaScript 語言不同的是,TypeScript 使用的是靜態型別(強型別),比如說它指定了變數可以儲存的資料型別。

如下圖所示,如果在 JS 中,指定變數可以儲存的資料型別,會報錯:“型別註釋只可以在TS檔案中被使用”:

TypeScript 是 JavaScript 的超集(superset),TypeScript 需要編譯(語法轉換)生成 JavaScript 才能被瀏覽器執行,它也區分了 string 和 String 這兩個資料型別。通常來說,string 表示原生型別,而 String 表示物件。


原生 string

JavaScript 在 ES6 標準裡支援6種原生型別,string 是其中之一。

1
2
3
4
5
6
let testVar1: number = 19;
let testVar2: boolean = true;
let testVar3: string ="Hi Wayne!";
let testVar4: null = null;
let testVar5: undefined = undefined;
let testVar6: object = new String("Wayne Cloud!");

原生的 string 是不包含屬性的值(即沒有properties),包括字面上沒有定義型別、字面上定義了 string、字面上定義了 String和一些從 string 函式呼叫返回的 strings 也都可以被歸為原生型別:

1
2
3
let msg1: string = "Hello world!";
let msg2: string = "Hello world!";
let msg22 = returnStr();

以上三個變數的型別(typeof())是 string


物件 String

物件是不同屬性的累積,一個物件可以呼叫許多相應的方法。

1
let msg3: String = new String('Hello world!');

這個變數 msg3 的型別就是 object

1
console.log(typeof(msg3)); // object

String 物件支援的方法:

No.MethodDescription
1.charAt()charAt() 方法從一個字符串中返回指定的字符
2.charCodeAt()charCodeAt() 方法返回 0 到 65535 之間的整數,表示給定索引處的 UTF-16 代碼單元
3.concat()concat() 方法將一個或多個字符串與原字符串連接合併,形成一個新的字符串並返回
4.indexOf()indexOf() 方法,給定一個參數:要搜索的子字符串,搜索整個調用字符串,並返回指定子字符串第一次出現的索引。給定第二個參數:一個數字,該方法將返回指定子字符串在大於或等於指定數字的索引處的第一次出現
5.lastIndexOf()lastIndexOf() 方法返回調用 String 對象的指定值最後一次出現的索引,在一個字符串中的指定位置 fromIndex 處從後向前搜索。如果沒找到這個特定值則返回 -1。

該方法將從尾到頭地檢索字符串 str,看它是否含有子串 searchValue。開始檢索的位置在字符串的 fromIndex 處或字符串的結尾(沒有指定 fromIndex 時)。如果找到一個 searchValue,則返回 searchValue 的第一個字符在 str 中的位置。 str 中的字符位置是從 0 開始的
6.localeCompare()localeCompare() 方法返回一個數字來指示一個參考字符串是否在排序順序前面或之後或與給定字符串相同。

新的 locales 和 options 參數能讓應用程序定制函數的行為,即指定用來排序的語言。 locales 和 options 參數完全取決於實現,在舊的實現中忽略這兩個參數
7.match()match() 方法檢索返回一個字符串匹配正則表達式的結果
8.replace()replace() 方法返回一個由替換值(replacement)替換部分或所有的模式(pattern)匹配項後的新字符串。模式可以是一個字符串或者一個正則表達式,替換值可以是一個字符串或者一個每次匹配都要調用的回調函數。如果 pattern 是字符串,則僅替換第一個匹配項
9.search()search() 方法執行正則表達式和 String 對象之間的一個搜索匹配
10.slice()slice() 方法提取某個字符串的一部分,並返回一個新的字符串,且不會改動原字符串
11.split()split() 方法使用指定的分隔符字符串將一個 String 對象分割成子字符串數組,以一個指定的分割字串來決定每個拆分的位置
12.substr()substr() 方法返回一個字符串中從指定位置開始到指定字符數的字符
13.substring()substring() 方法返回一個字符串在開始索引到結束索引之間的一個子集,或從開始索引直到字符串的末尾的一個子集
14.toLocaleLowerCase()toLocaleLowerCase() 方法根據任何指定區域語言環境設置的大小寫映射,返回調用字符串被轉換為小寫的格式
15.toLocaleUpperCase()toLocaleUpperCase() 方法根據本地主機語言環境把字符串轉換為大寫格式,並返迴轉換後的字符串
16.toLowerCase()toLowerCase() 會將調用該方法的字符串值轉為小寫形式,並返回
17.toString()字符串對象的 toString() 方法返回一個字符串,表示指定的字符串
18.toUpperCase()toUpperCase() 方法將調用該方法的字符串轉為大寫形式並返回(如果調用該方法的值不是字符串類型會被強制轉換)
19.valueOf()valueOf() 方法返回 String 對象的原始值

程式碼對比

我們對下面4個變數進行型別的探索與比較:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let msg: string = 'Hello world!';
let msg2: String = 'Hello world!';
let msg22 = 'Hello world!'; // 字面上沒有定義型別
let msg3: String = new String('Hello world!');

console.log(typeof(msg)); // string
console.log(typeof(msg2)); // string
console.log(typeof(msg22)); // string
console.log(typeof(msg3)); // object
console.log(msg === msg2); // true
console.log(msg === msg3); // false
console.log(msg2 === msg3); // false

為什麼需要 String 物件

首先,當我們使用關鍵字 new 新建一個 String 物件的時候,Typescript 會建立一個新的物件

即我們用 new 新建了兩個 String 物件,即使內容相同,它們也是指向不同的記憶體。

舉下面兩個例子:

  1. 當用 a1、b1 代表相同值的兩個變數的時候,它們是相同的;而當用 new 新建兩個物件的時候,即使值相同,它們也是不同的:
1
2
3
4
5
6
7
let a1 = "Hello World";
let b2 = "Hello World";
console.log(a1 === b1); // true

let a2 = new String("Hello World");
let b2 = new String("Hello World");
console.log(a2 === b2); // false
  1. eval() 函式的作用:用來計算表示式的值。如果我們把 eval() 直接賦給 string,而 string 裡面是計算式的字串,那麼它會返回計算後的值;而如果我們把 eval() 賦給 String,因為它不是原生型別,它只會返回 String 這個物件:
1
2
3
4
5
6
let a3 = "3 * 9";
console.log(eval(a3)); // 27

let b3 = new String("8 + 20");
console.log(eval(b3)); // Warning:Argument of type 'String' is not assignable to parameter of type 'string'. 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.ts(2345)
console.log(eval(b3.toSTring())); // 28
  1. 其次,因為 String 物件可以有屬性。我們可以用 String 物件在屬性裡保留一個額外的值。即使這個用法並不常見,但是仍然是 TS 的一個特性:
1
2
3
4
5
6
let prim = 'hello Wayne';
let obj = new String('hello Wayne Cloud');

prim.property = 'PaaS'; // Invalid
obj.property = 'PaaS'; // Valid
console.log(obj.property); // 輸出為 PaaS

兩者區別總結

string 原生型別String 物件
廣泛被使用幾乎很少被使用
只會保留值有能力除了值之外,還可以保留屬性
值是不可變的,因此執行緒安全String物件是可變的
沒有任何方法String物件有各種方法
不能建立兩個獨立的字面上值相同的 string可以用 new 建立兩個物件
是原生的資料型別包裝原生資料型別來建立一個物件
傳遞的值是原生資料本身的拷貝傳遞的值是實際資料的引用
當使用 eval() 函式時,將直接作為原始碼進行處理當使用 eval() 函式時,將被轉換為字串

comments powered by Disqus