iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
0
自我挑戰組

寇丁人妻的前端書蟲日誌系列 第 7

Day07:YDKJS 第三次讀書會

大家的三個重點:

Tomas:

  1. 每一個利用 Symbol 產生的值都是獨特的,他的屬性無法用 for in Object.getOwnPropertyNames 取得。
    (可用 getOwnPropertySymbols)
  2. 補充 Map , Set, WeakMap, WeakSet

Lai:

  1. 建構器形式的值建立動作(new String(“abc”))的結果是一個包裹了基型值的物件包裹器,而非只是建立基型值本身。
  2. 如果想要取用物件包裹器中底層的基本型別值,可以使用valueOf()方法。
  3. 基本型別值沒有特性或方法,會需要包裹基型值的物件包裹器,JS會自動封裝,以利存取。

日安:

  1. 顯示封裝器的方法:Object.prototype.toString(..)方法
  2. 建立一個包在 false 值的物件包裹器,但物件本質還是 truthly。
  3. 取出其底層的基本型別值,可以使用 valueof() 方法。

mango:

  1. String(), Number(), Boolean()這三個natives,不用new就會自動封裝
  2. 在new Array()時要避免有empty
  3. Object()這個native本身就是物件,再用new的方式太多餘

chris:

  1. Object.prototype.toString() ≠ xxx.toString()
    XXX.constructor.name 也可以看型別
  2. 基本型別建構式 與 Object 型別建構式 用途不一樣
  3. 不要修改 prototype 的本意

kai:

  1. 稀疏陣列 ≠ 陣列裡面放 undefined (empty ≠ undefinde)
  2. JS 會自動封裝
  3. 不要去修改原生原型的東西

Andy:

  1. 這些對象包裝器服務於一個非常重要的目的。基本類型值沒有屬性或方法,所以為了訪問.length或.toString()你需要這個值的對象包裝器。值得慶幸的是,JS將會自動地封箱(也就是包裝)基本類型值來滿足這樣的訪問。
  2. Array構造器有一種特殊形式,如果它僅僅被傳入一個number參數,與將這個值作為數組的內容不同,它會被認為是用來“預定數組大小”(嗯,某種意義上)用的長度。

Henry

  1. 可以透過 Object.prototype.toString.call 得知[[Class]] 屬性
  2. JS 預設會自動封裝,所以 primitive 也可以取用 methods
  3. (忘了)

Jason

  1. Object.prototype.toString().call()``來抓到[[class]]`是哪個型別
  2. JS會自動封裝,所以在宣告變數的時候,不需再宣告 data type
  3. Array的不要亂建構(new),會大事不好

Tony:

  1. 知道 Native 是否能夠作為建構器
  2. 成為建構器有哪些注意事項
  3. 純值 使用方法時,用建構器與 Native 的差異。

Jimmy

  1. Natives是由JS提供包覆基本型別值用的物件包裹器
  2. JS會自動封裝基本型別值

共筆

最常用的幾個 natives:

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol()

這些 natives 實際上是內建函式,確實可以被當作一個原生建構器,但建構出來的東西可能與你想像的不同:

var a = new String("abc");
typeof a; //Object
a instanceof String //true
Object.prototype.toString.call(a); // [object String]

建構式形式所創建的結果,是一個包裹了基型值的物件包裹器。typeof 顯示出這些物件,並非他們自己的特殊型別,他們是 object 的子型別。

重點是 new String("abc") 建立了一個字串包裹器物件,包裹了abc,而非基型值本身。

Internal [[Class]]

typeof 為"object"的那些值,會額外標示有一個內部的[[Class]]特性。這個特性無法直接被取用,但可借取Object.prototype.toString(..)方法,來間接揭露此特性。

Object.prototype.toString.call(null);
// "[Object Null]"
Object.prototype.toString.call(undefined);
// "[Object Undefined]"

多數情況,內部的 Class 值,會對應到該值關聯的原生建構式中,但也有例外狀況,像是建構式 Null() 和 Undefined() 都不存在,但儘管如此,顯露的還是 "Null" 和 "Undefined"。
相對於其他簡單基型值,像是 string、number、boolean,實際上會有其他行為的涉入。

封裝後的包裹器

物件包裹器具有非常重要的用途,基本型別值沒有特性或方法,所以要存取lengthtoString,會需要包裹基型值的物件包裹器。

在跑 for 迴圈的時候,最好的方法可能是讓值有物件的形式,但實際上程式會執行得更慢,最好是讓自動封裝的動作隱含的發生,換句話說就是永遠不要使用原生建構式,而使用字面形式的基本型別值。

物件包裹器的陷阱

假設真的要使用原生建構式,有幾個陷阱:

var a = new Boolean(false);
if(!a) {
	console.log("Oops!"); //永遠都不會執行
}
  • 建立一個包在 false 值的物件包裹器,但物件本質還是 truthly。

  • 如果要手動封裝一個 Object,可以使用 Object(...)函式(不帶new)。

解封裝

想要取出其底層的基本型別值,可以使用valueof()方法。

var myName = new String('Jason');
var weight = new Number(96);
var isHenry = new Boolean(true);

myName.valueOf();//"Jason"
weight.valueOf();//96
isHenry.valueOf();//true

typeof myName.valueOf(); //"string"
typeof weight.valueOf(); //"number"
typeof isHenry.valueOf(); //"boolean"

解封裝的動作也可能隱含的發生,會造成強制轉型:

var myName = new String('Jason');
var sumEmpty = myName + "";
//sumEmpty擁有解封後的基本型別值 "Jason"
// 「myName +」 就是 「myName.valueOf() +」

typeof myName;//"object"
typeof sumEmpty;//"string"

作為建構式的 Natives

最偏好的方式是使用字面表示來建立基本型別值,這些字面形式的值會與建構式形式所創建的物件相同。

Array

  • Array 建構式,如果只有一個 number 引數被傳入,那麼建構式不會把該值當作陣列的內容,而是將他當成一個長度來預先設定陣列的大小。但實際上並沒有「預先設定陣列大小」這種事存在,取而代之建立出來的是一個空陣列,不過該陣列length被設定為所指定的那個數值。插槽中沒有明確的值,意味著陣列中的插槽會是undefined

Object()、Function()、RegExp()

  • 幾乎沒有什麼情況會用到 new Object()。
  • 你得動態定義一個函式的參數或其函式主體的時候才會用得到 Function()。
  • 應該優先選用字面值形式定義正規表示式,JS 引擎會在程式碼執行前預先編譯,並快取。

Date(..)、Error(..)

  • Date() 和 Error()兩者沒有字面表示式的形式可用。
  • 要建立一個日期物件,除了增加參數,還可以使用Date().getTime()方法。
  • 使用 Error 物件的主要狀況,通常是用於執行堆疊情境,錯誤物件的實體通常會有一個message特性,通常最好是做錯誤物件上呼叫toString方法,已取得格式化方便閱讀的錯誤訊息。

Symbol

  • ES6中加入一個額外的基本型別值型別,叫做「Symbol」。主要是為了建構器特殊的內建行為設計。
  • Symbols 主要用於私有或特殊屬性。
const test1 = Symbol("hello");
const test2 = Symbol("hello");
console.log(test1 === test2); //false
//Tomas

Symbol 取值

相同 key 值
// Tomas 的範例
 
const obj = {};
const a = Symbol("a");
const b = Symbol("b");  //key 值相同
const c = Symbol("b");  //key 值相同

obj[a] = 'Hello';
obj[b] = 'World';
obj[c] = 'yo!';

const objectSymbols = Object.getOwnPropertySymbols(obj);

console.log(obj[objectSymbols[1]]); // "World"
console.log(obj[objectSymbols[2]]); // "yo!"
// Turtle 的範例

var info = {
    name:'Jason',
    [Symbol('description')]:'CSS很強',
};
var otherInfo = {
    [Symbol('description')]:'很愛性騷擾同事'
};

var Person = Object.assign({},info,otherInfo);
//{name: "Jason", 
//Symbol(description): "CSS很強", 
//Symbol(description): "很愛性騷擾同事"}

Person[Object.getOwnPropertySymbols(Person)[0]]
es6-feature 上面的範例
// Tomas 的範例
// 
Symbol("foo") !== Symbol("foo")
const foo = Symbol()
const bar = Symbol()
typeof foo === "symbol"
typeof bar === "symbol"
let obj = {}
obj[foo] = "foo"
obj[bar] = "bar"
JSON.stringify(obj) // {}
Object.keys(obj) // []
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [ foo, bar ]

原生的原型

每個原生建構式都有自己的prototype,而這些方法不會直接修改字串,修改動作會從現有的值建立出一個新的值。

做為預設值的原型

Function.prototype是空的函式,RegExp.prototype是空的正規表達式,Array.prototype是空的陣列,這使得他們適合拿來做預設值,可以給尚未擁有適當型別值的變數。

副作用:當設預設值重新創建,會耗費記憶體和 CPU。

const test1 = Symbol("hello");
const test2 = Symbol("hello");
console.log(test1 === test2); //false

Array.from({length: 10}).map((_,index) => index);
//創建某個長度的陣列
var range = Array.from({length: 10})
for (x of range) {
  console.log('here')
}

range es-6

var configObject = {}
Array.prototype.push.call(configObject, "new element")
configObject  // {0: "new element", length: 1}
Array.from(configObject)  // ["new element"]

Object 的 Subtype 的原生建構式使用

字面形式 不用 new new 參數 注意事項

|Array|[]|沒差|沒差|1.Array.legnth 2.元素
|Object|{}|封裝成 Object|幾乎用不到|要封裝的資料
|Function|function(){}, ()=>{} |要執行的程式碼|別用|要執行的 code|別用來當作 eval()|
|RegExp|/(?:)/|沒差|沒差|正規表達式
|Date|x|別用,不同的 browser 不同結果|常用|指定日期 空參數:回傳現在|ES5: Date.now()
|Error|x|沒差|沒差|變成 error.message
|Symbol|x|正常使用|Uncaught TypeError|要變 Symbol 的值

  • 沒差指的是「有用 new 和不用 new」的差別
  • 來源自 Chris

上一篇
Day06:圖解 HTTP Chapter01 了解 Web 及網路基礎 筆記精要
下一篇
Day08:圖解 HTTP Chapter05 與 HTTP 協作的網頁伺服器 筆記精要
系列文
寇丁人妻的前端書蟲日誌30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言