Data Types

ECMAScript 標準定義了七種資料型別:

除了物件以外的所有值,都是原始定義的值(值意味著不能被改變)。我們引用這些類型的值為 primitive values(原始值)

  • Boolean
  • Number
  • String
  • Null
  • Undefined
  • Symbol(於 ECMAScript 6 新定義)

  • Object

Boolean, Number, String, …

定義是….你認真的???

Undefined vs Null

空(null)就是空值,代表的是沒有值的意思。

In JavaScript null is not a “reference to a non-existing object” or a “null pointer” like in some other languages.

It’s just a special value which has the sense of “nothing”, “empty” or “value unknown”.

未定義(undefined)即是尚未被定義(not been assigned)類型,或也有可能是根本不存在,完全不知道是什麼。

A variable that has not been assigned a value is of type undefined. 

A method or statement also returns undefined if the variable that is being evaluated does not have an assigned value. 

A function returns undefined if a value was not returned.

** undefined is not a reserved word

適用情境

雖然JavaScript並沒有明確規範這兩個資料類型的用途,但對JavaScript程式設計師而言,應儘量: - 使用空值(null)來進行運算後判斷或當特殊情況回傳值

- 未定義(undefined)就留給JavaScript系統用,常用typeof運算符的判斷方式。

Symbol

ES6新增的Data type.

初始化

Symbol(); // symbol
Symbol('foo'); // description: foo
console.log(Symbol()); // prints "Symbol()" to the console
assert(typeof Symbol() === 'symbol')
new Symbol(); // TypeError: Symbol is not a constructor 

特色

  • Symbols 絕對不會與 Object 的 string keys衝突
  • Symbols 不能用既有的Reflection取得, 且不是private的
  • Symbols 不能與其他primitives運算
  • Symbols 不總是唯一值

Symbols 絕對不會與 Object 的 string keys衝突

var myObj = {};
var fooSym = Symbol('foo');
var otherSym = Symbol('bar');
myObj['foo'] = 'bar';
myObj[fooSym] = 'baz';
myObj[otherSym] = 'bing';
assert(myObj.foo === 'bar');
assert(myObj[fooSym] === 'baz');
assert(myObj[otherSym] === 'bing'); 

Symbols 不能用既有的Reflection取得, 且不是private的

Symbols 不會顯示在使用 for in、 for of 或者 Object.getOwnPropertyNames的Object上,在Object中獲取Symbol的唯一方法是Object.getOwnPropertySymbols

var fooSym = Symbol('foo');
var myObj = {};
myObj['foo'] = 'bar';
myObj[fooSym] = 'baz';
Object.keys(myObj); // -> [ 'foo' ]
Object.getOwnPropertyNames(myObj); // -> [ 'foo' ]
Object.getOwnPropertySymbols(myObj); // -> [ Symbol(foo) ]
assert(Object.getOwnPropertySymbols(myObj)[0] === fooSym); 

Symbols 不能與其他primitives運算

如果用(+Symbol(), “+Symbol(), Symbol() + ‘foo’) 會出錯…

Symbols 不總是唯一值

完全唯一的狀況

建立一個 symbol,它會在 JavaScript引擎建立一個全新的值。如果没有reference Symbol,你就不能使用它。這代表兩個symbols永遠不會等於相同的值, 即使description一樣.

除非出現下列狀況

除非是使用Symbol.for(), 這表示在global Symbol registry建立一個Symbols。此 registry 是跨域的,代表同一個iframe 或 service worker 的symbol會跟目前frame的symbol會完全一樣

assert.notEqual(Symbol('foo'), Symbol('foo'));
assert.equal(Symbol.for('foo'), Symbol.for('foo'));

// Not unique:
var myObj = {};
var fooSym = Symbol.for('foo');
var otherSym = Symbol.for('foo');
myObj[fooSym] = 'baz';
myObj[otherSym] = 'bing';
assert(fooSym === otherSym);
assert(myObj[fooSym] === 'bing');
assert(myObj[otherSym] === 'bing');

// Cross-Realm
iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

assert(iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo')); // true! 

好像還是不太懂… 看看有些適合的使用情境

可以用在String 或Integer的作為唯一值使用的地方

比如logger.levels.DEBUG, logger.levels.INFO, logger.levels.WARN 等等。

過去使用要用String(logger.levels.DEBUG ===‘debug’)或Integer(logger.levels.DEBUG === 10)。這兩個有可能不是唯一值, 會有衝突風險. 但Symbols 的特性是!所以logger.levels 很容易改成这样:

log.levels = {
    DEBUG: Symbol('debug'),
    INFO: Symbol('info'),
    WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message'); 

** In some programming languages, Symbols are called atoms. You can also compare them to named enumerations (enum) in C.

A place to put metadata values in an Object

You could also use them to store custom metadata properties that are secondary to the actual Object.

var size = Symbol('size');
class Collection {
    constructor() {
        this[size] = 0;
    }

    add(item) {
        this[this[size]] = item;
        this[size]++;
    }

    static sizeOf(instance) {
        return instance[size];
    }

}

var x = new Collection();
assert(Collection.sizeOf(x) === 0);
x.add('foo');
assert(Collection.sizeOf(x) === 1);
assert.deepEqual(Object.keys(x), ['0']);
assert.deepEqual(Object.getOwnPropertyNames(x), ['0']);
assert.deepEqual(Object.getOwnPropertySymbols(x), [size]); 

Reference

JavaScript 的資料型別與資料結構.

What data types are supported in Javascript?

Data types

深入解析 ES6:Symbol

  • 欲知更多詳情, 請參閱: Symbols 為什麼令人驚嘆 中文 英文

Object

請準時參加下周課程