手记

趣说Javascript数据类型

一图胜千言,今天我们要学习的就是下面的这张图:

话说蹩脚的Javascript小镇坐落在一个不知名的山脚下。

镇长

镇长就是大名鼎鼎的object:

其实这家伙也就会那么几个蹩脚的技能,大部分时间就是悠闲地混日子,却安安稳稳的混了快一辈子。他声称:“整个小镇全是他的,Javascript就是彻底面向对象的”。其实他的狂妄也是有道理的,整个小镇里大部分人都是他的部下,除了那几个特殊的家伙。好了,镇长大人长得就是下面的样子:

var obj = {
    name : "镇长",
    age : 88
};
assert(obj.name === "镇长" && obj.age === 88, "Object");

女强人

小镇里最出名的就是女强人function了:

我实在不知道怎么来形容这个人,精明干练、诡计多端、冷若冰霜、风骚入骨等等。但是我不得不承认,正是因为她的存在才使得整个小镇充满到了生机,她的一颦一笑都会牵动整个小镇的神经:

function smile()
{
    return "笑";
}

var cry = function() {
    return "哭";
}

assert(smile() === "笑", "Function");
assert(cry() === "哭", "Function");

三个熊孩子

小镇里有三个调皮捣蛋的熊孩子:

  • 一个叫boolean,理想是长大了当一个法官,因为他对是非最感兴趣;

  • 一个叫number,理想是长大了当一个数学家,因为他对数字最感兴趣;

  • 一个叫string,理想是长大了当一个文学家,因为他对文字最感兴趣;

boolean最小,也最单纯,她最常用的口头禅就是,如果我扔的硬币是正面,我今天就和number玩;如果是反面,我今天就和string玩。

assert(true, "true");
assert(!false, "false");

number是个小小的数学家,他会用整数数数,会用浮点数测量,还有用一些特殊数解决一些稀奇古怪的问题:

test("整数字面量", function() {
    assert(12 === 12, "十进制");
    assert(012 === 10, "八进制");
    assert(0x12 === 18, "十六进制");
});

test("浮点数字面量", function() {
    assert(_floatEqual(3.14, 3.1400000001), "浮点数");
    assert(_floatEqual(3.1415e2, 314.1500000001), "科学计数法");
    
    assert(_floatEqual(.42, 0.42), ".42不推荐");
    assert(_floatEqual(42., 42.0), "42.不推荐");
});    

test("特殊数字", function() {
    assert(NaN !== NaN, "NaN");
    assert(Infinity === Infinity, "Infinity");
    assert(-Infinity === -Infinity, "-Infinity");
});

string是个小小的文学家,他会用文字写文章,还有一些特殊的符号来写自己的日记:

test("字符串字面量", function() {
    assert("abc" === "abc", "'abc'");
    assert('abc' === "abc", "'abc'");
});

test("转义字符", function() {
    assert("a\nb" === "a\nb", "\\n");
});

是的,这三个家伙就是镇长管不了的,他们整天神出鬼没,四处闯祸,搞得镇长不知道吹胡子瞪眼了多少次,最后镇长大人终于想到一个好办法,那就是:把三个熊孩子的妈妈招聘到镇长办公室。

三个好妈妈

这三个妈妈其实没啥好介绍的,因为他们的孩子和她们长得非常象:

自从三个妈妈上岗了以后,三个熊孩子闯的祸就明显少了很多,因为很多时候,熊孩子们的行为会被妈妈们自动接管过去。

一对老夫妻

镇子里住着一对老夫妻,或许小镇还不存在的时候他们就已经在这里了。是的,他们也不归镇长管。

老奶奶undefined是个接生婆,只要报上一个名字,她就可以告诉你这个人是不是镇子里的出生的:

var p;
assert(p === undefined, "undefined");

//ReferenceError: q is not defined
assert(q !== undefined, "undeclared");

老爷爷null是个老中医,只要得到了他的假条,你就可以什么都不用干了:

var obj = null;
assert(obj === null, "null");

var work = function() {                
}
work = null;
assert(work === null, "null");

其他职员

镇长办公室里还有其他几个职员:

  • Array负责组织排队

  • Date负责时间管理;

  • RegExp负责复杂的文档处理;

  • Error负责错误处理

初次见面,先打个招呼吧,以后你会慢慢熟悉的:

var arr = [1, 2, 3];
assert(arr.length === 3, "Array");

var reg = /abc/i;
assert("Abc".replace(reg, "xyz") === "xyz", "RegExp");

var date = new Date("2016-12-17");
assert(date.getYear() === 2016 - 1900 && date.getMonth() 
    === 11 && date.getDate() === 17, "Date");
    
var error = new Error("错误");
assert(error.message === "错误", "Error");

新来的家伙

有一天,小镇里发生一件影响深远的的大事,一个臭流氓花了一元买了一张车票,然后他就拿这张票看了一场票价100的电影:

let rogue = {
  name : "张三",
  age : 25,
};

function buy_bus_ticket(person) {
  person.is_ticket = true;
}

function go_bus(person) {
  if (person.is_ticket) {
      console.log("发车啦");
      person.is_ticket = false;
  }
}

function go_cinema(person) {
  if (person.is_ticket) {
      console.log("看电影");
      person.is_ticket = false;
  }
}

buy_bus_ticket(rogue);
go_cinema(rogue);

要不是票还要收回去,这家伙可以凭这一张票玩遍整个小镇。镇长大人雷霆震怒,下令彻查,但是结果却是:代码没有错误。

看来解决问题的办法只能是让is_ticket变成is_bus_ticket,is_cinema_ticket。但是Javascript是一门动态语言,天知道以后还要裂变出来多少的is_xxx_ticket。

镇长大人没招了,只好向上级单位(Javascript标准委员会),上级单位很够意思,没过多久就派来了一个新的家伙symbol,专门解决这个问题:

symbol有什么本事?据说只有一个,就是会变脸,底下人每次求他办事他都会变个面孔,但是面对编译器大人,他又永远只有一个面孔:

let id = Symbol("name");

assert(id.toString() === "Symbol(name)", "display");

let id_ = Symbol("name");
assert(id !== id_, "unique");

symbol很好的解决了属性名冲突的问题:

let isTicket = Symbol("isTicket");
let isEmployee = Symbol("isEmployee");
let isVip = Symbol("isEmployee");
let me = {
    name : "张三",
    age : 25,
    
    isTicket : true,
    isEmployee : true,
};
me.isVip = false;

assert(me.isTicket && me.isEmployee && !me.isVip, "object");

现在各个商家只要先请教symbol,就可以随意的给顾客打标记了,绝对不用担心属性名会重复。至于symbol实际上是怎么实现的,是用uuid还是其它什么能够保证不重复的东西,我们就不需要关心了。

但是每次请教symbol都会变脸,这在有时候是不利于共享的,这时候就要用到全局symbol了:

let me = Symbol.for("me");
assert(me.toString() === "Symbol(me)", "display");

let me_ = Symbol.for("me");
assert(me_ === me, "not unique");

assert(Symbol.keyFor(me) === "me", "keyFor");

全局symbol会被统一管理,保证名称一样标识符也一样。

symbol备受青睐,javascript里内置了很多他的职位:

assert(Symbol.hasInstance.toString() === 
    "Symbol(Symbol.hasInstance)", "Symbol.hasInstance");
assert(Symbol.isConcatSpreadable.toString() === 
    "Symbol(Symbol.isConcatSpreadable)", "Symbol.isConcatSpreadable");
assert(Symbol.iterator.toString() === 
    "Symbol(Symbol.iterator)", "Symbol.iterator");
assert(Symbol.toPrimitive.toString() === 
    "Symbol(Symbol.toPrimitive)", "Symbol.toPrimitive");

typeof

typeof和小镇里的每个人都认识,它专职就是分辨谁是哪个数据类型:

assert(typeof null === "object", "null");    // 是一个bug,需要特别注意
assert(typeof undefined === "undefined", "undefined");

assert(typeof true === "boolean", "true");
assert(typeof false === "boolean", "false");

assert(typeof 0 === "number", "number");
assert(typeof -0 === "number", "number");
assert(typeof +0 === "number", "number");
assert(typeof 1 === "number", "number");
assert(typeof 3.14 === "number", "number");
assert(typeof NaN === "number", "number");
assert(typeof Infinity === "number", "number");
assert(typeof -Infinity === "number", "number");

assert(typeof "abc" === "string", "string");

var obj = {
  name : 'wgs'
};

function fun() {
  return 1;
}

assert(typeof {} === "object", "object");
assert(typeof [] === "object", "object");
assert(typeof obj === "object", "object");
assert(typeof fun === "function", "function");

assert(typeof Symbol() === "symbol", "symbol");

基本上,typeof的工作还算是称职的,7种数据类型它能正确的识别出6种,唯一的例外就是null被认作了object,据说这是一个bug,但是再也改不了了。

还有一个问题,typeof或许对function情有独钟,每次都能正确的叫出她的名字,而对于镇长办公室里的其它人,typeof则很敷衍地一律打上了object的标签。

2人推荐
随时随地看视频
慕课网APP