JavaScript中的类型(一)———— 类型

Author Avatar
GeniusFunny 2月 06, 2018
  • 在其它设备中阅读本文章

引入

类型:对语言引擎和开发人员来说,类型是值的内部特征,它定义了值的行为,以使其区别于其他值。
JavaScript是一门弱类型(偏向容忍隐式类型转换)语言,同时也是一门动态类型(编译的时候就知道每个变量的类型)语言。

没有严格的类型的限制,使得JavaScript成为了一门特别灵活的语言,但是也带了一些麻烦,例如强制类型转换

内置类型

JavaScript中暂时有7种内置类型:

  • 空值(null)
  • 未定义(undefined)
  • 布尔值(boolean)
  • 数字(number)
  • 字符串(string)
  • 对象(object)
  • 符号(symbol)
    通常,我们可以通过typeof操作符来查看值的类型,它会返回类型的字符串值,但是并不是这七种类型和它们的字符串值并不是一一对应。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //下面六种类型均有同名的字符串值与之对应,'==='会返回true。
    typeof undefined === 'undefined'
    typeof false === 'boolsean'
    typeof 3 === 'number'
    typeof '3' === 'string'
    typeof {number: 3} === 'object'
    typeof Symbol() === 'symbol'

    //对于null类型,存在一个bug(从JavaScript诞生就一直存在,以后估计也会存在),对null进行typeof操作,返回的值居然是'object';
    typeof null === 'object' //true
    typeof null === 'null' //false
    //我们需要使用复合条件来检测null值的类型:
    const a = null;
    //对于&&操作,如果运算符左边的值为真,则该表达式直接返回右边的值,例如 'true && 3'表达式的结果为3。
    (!a && typeof a === "object"); //true

函数

函数是’object’的一个子类型,函数是一个“可调用对象”,它有一个内部属性[[Call]],该属性使其可以被调用。但是,对函数进行typeof操作时,返回的值可不是’object’。

1
2
typeof function(){} === 'object'    //false
typeof function(){} === 'function' //true

没错,就是’function’。看起来function就是另外一种内置类型,但是它不是。:)

值和类型

变量没有类型,值才有类型
JavaScript中的变量是没有类型的,只有值才具有类型,变量可以随时持有任何类型的值。前面提到过,JavaScript是一门动态弱类型的语言。例如:变量a持有的值为42,那么这个值的类型为number,并且无法直接更改42的类型(number),但可以通过强制转换将这42转换为’42’,此时值拥有的类型就为字符串(string)。

undefined and undeclared

变量未持有值时为undefined,此时typeof返回’undefined’。
已在作用域中声明但未赋值的比变量是undefined的,未在作用域声明过的变量是undeclared的。

1
2
3
let a;
a; //undefined
b; //ReferenceError:b is not defined,报错

每次看到“not defined”,总以为等价于”undefined”,真让人糟心,还有更糟心的:)

1
2
3
let a;
typeof a; //undefined
typeof b; //undefined

一向被认为比较安全的操作符typeof也会这样闹着玩:)
注:推荐一本必看的书《JavaScript语言精粹》,作者是Douglas Crockford(大神)。

安全防范机制

并不是没有办法让开发人员解决’undeclared’问题,有时候通过typeof的安全防范机制(阻止报错)来检查undeclared变量不失为一个方法。
当一个窗口加载多个.js文件时,这些.js文件中的代码会共享一个全局作用域,如果有重名的变量名,那么就太可怕了……减少全局变量是编写可维护的代码的基础,所有东西都应该被封装到模块或者私有/独立的命名空间里。
例如:调试模式下,在debug.js声明了一个DEBUG的全局变量,把它作为调试模式的开关,在输出调试信息时我们会先判断DEBUG是否已经被声明。可是如何在程序中检查全局变量DEBUG且不会出现ReferenceError错误呢?typeof的安全防范机制就成了我们的帮手

1
2
3
4
5
6
7
8
//这样做是要挨Error的
if (DEBUG) {
console.log("调试开始啰");
}
//这样就比较安全了
if (typeof DEBUG !== "undefined") {
console.log("调试开始啰")
}

不仅对于自定义的变量有用,对于内建的API也有帮助。甚至不一定要求作用域为全局,也可以用于检查我们的变量是否在宿主作用域声明过。

还有一个方法,就是检查所有全局变量是否是全局对象的属性,浏览器的全局对象是window,服务器端的全局对象为global。上述的例子我们可以这样操作:

1
2
3
if (window.DEBUG) {
//...
}

访问不存在的对象属性与undeclared变量不同,是不会报错的。

关于

参考文献:
《你不知道的JavaScript(中卷)》
《JavaScript语言精粹》