## 3.1 类型
### 3.1.1 类型
类型:是值的内部特征,它定义了值的行为,以使其区别于其他值。
### 3.1.2 内置类型
JavaScript 有七种内置类型:
• 空值(null)
• 未定义(undefined)
• 布尔值( boolean)
• 数字(number)
• 字符串(string)
• 对象(object)
• 符号(symbol,ES6 中新增)
除对象之外,其他统称为“基本类型”。
可以用typeof 运算符来查看值的类型,它返回的是类型的字符串值。
~~~
typeof undefined === "undefined"; // true
typeof true === "boolean"; // true
typeof 42 === "number"; // true
typeof "42" === "string"; // true
typeof { life: 42 } === "object"; // true
// ES6中新加入的类型
typeof Symbol() === "symbol"; // true
~~~
null 是基本类型中唯一的一个“假值”类型,typeof对它的返回值为"object"。
~~~
typeof null === "object"; // true
//需要使用复合条件来检测null 值的类型:
var a = null;
(!a && typeof a === "object"); // true
~~~
function(函数)也是JavaScript 的一个内置类型,它实际上是object 的一个“子类型”,具体来说,函数是“可调用对象”,它有一个内部属性[[Call]],该属性使其可以被调用。
~~~
`typeof function a(){ /* .. */ } === "function"; // true`
~~~
函数不仅是对象,还可以拥有属性。例如:
~~~
function a(b,c) {
/* .. */
}
~~~
函数对象的length 属性是其声明的参数的个数:`a.length; // 2`,因为该函数声明了两个命名参数,b 和c,所以其length 值为2。
数组也是对象,也是object 的一个“子类型”,数组的元素按数字顺序来进行索引(而非普通像对象那样通过字符串键值),其length 属性是元素的个数。
~~~
typeof [1,2,3] === "object"; // true
~~~
### 3.1.3 值和类型
JavaScript 中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值。换个角度来理解就是,JavaScript 不做“类型强制”;也就是说,语言引擎不要求变量总是持有与其初始值同类型的值。一个变量可以现在被赋值为字符串类型值,随后又被赋值为数字类型值。
在对变量执行typeof 操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型,因为**JavaScript 中的变量没有类型。**
~~~
var a = 42;
typeof a; // "number"
a = true;
typeof a; // "boolean"
~~~
typeof 运算符总是会返回一个字符串:
~~~
typeof typeof 42; // "string"
~~~
typeof 42 首先返回字符串"number",然后typeof "number" 返回"string"。
**1. undefined 和undeclared**
变量在未持有值的时候为undefined。此时typeof 返回"undefined":
~~~
var a;
typeof a; // "undefined"
var b = 42;
var c;
// later
b = c;
typeof b; // "undefined"
typeof c; // "undefined"
~~~
已在作用域中声明但还没有赋值的变量,是`undefined` 的。相反,还没有在作用域中声明过的变量,是`undeclared` 的。
~~~
var a;
a; // undefined
b; // ReferenceError: b is not defined
~~~
“`undefined`”和“`is not defined`”是两码事!
更要注意typeof 处理undeclared 变量的方式:
~~~
var a;
typeof a; // "undefined"
typeof b; // "undefined"
~~~
对于undeclared(或者not defined)变量,typeof 照样返回"undefined"。请注意虽然b 是一个undeclared 变量,但typeof b 并没有报错。这是因为typeof 有一个特殊的安全防范机制。
**2. typeof Undeclared**
该安全防范机制对在浏览器中运行的JavaScript 代码来说还是很有帮助的,因为**多个脚本文件会在共享的全局命名空间中加载变量**。
举个简单的例子,在程序中使用全局变量DEBUG 作为“调试模式”的开关。在输出调试信息到控制台之前,我们会检查DEBUG 变量是否已被声明。顶层的全局变量声明var DEBUG = true 只在debug.js 文件中才有,而该文件只在开发和测试时才被加载到浏览器,在生产环境中不予加载。
问题是如何在程序中检查全局变量DEBUG 才不会出现ReferenceError 错误?
~~~
// 这样会抛出错误
if (DEBUG) {
console.log( "Debugging is starting" );
}
// 这样是安全的
if (typeof DEBUG !== "undefined") {
console.log( "Debugging is starting" );
}
~~~
这不仅对用户定义的变量(比如DEBUG)有用,对内建的API 也有帮助:
~~~
if (typeof atob === "undefined") {
atob = function() { /*..*/ };
}
~~~
还有一种不用通过typeof 的安全防范机制的方法,就是检查所有全局变量是否是全局对象的属性,浏览器中的全局对象是`window`。
~~~
if (window.DEBUG) {
// ..
}
if (!window.atob) {
// ..
}
~~~
与undeclared 变量不同,访问不存在的对象属性(甚至是在全局对象window 上)不会产生ReferenceError 错误。
如果想让别人在他们的程序或模块中复制粘贴你的代码,就需要检查你用到的变量是否已经在宿主程序中定义过:
~~~
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
~~~
其他模块和程序引入doSomethingCool() 时,doSomethingCool() 会检查FeatureXYZ 变量是否已经在宿主程序中定义过;如果是,就用现成的,否则就自己定义:
~~~
(function(){
function FeatureXYZ() { /*.. my XYZ feature ..*/ }
// 包含doSomethingCool(..)
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
doSomethingCool();
})();
~~~
还有一种“依赖注入”(dependency injection)设计模式,就是将依赖通过参数显式地传递到函数中,如:
~~~
function doSomethingCool(FeatureXYZ) {
var helper = FeatureXYZ ||
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
~~~
- 前言
- 第一章 JavaScript简介
- 第三章 基本概念
- 3.1-3.3 语法、关键字和变量
- 3.4 数据类型
- 3.5-3.6 操作符、流控制语句(暂略)
- 3.7函数
- 第四章 变量的值、作用域与内存问题
- 第五章 引用类型
- 5.1 Object类型
- 5.2 Array类型
- 5.3 Date类型
- 5.4 基本包装类型
- 5.5 单体内置对象
- 第六章 面向对象的程序设计
- 6.1 理解对象
- 6.2 创建对象
- 6.3 继承
- 第七章 函数
- 7.1 函数概述
- 7.2 闭包
- 7.3 私有变量
- 第八章 BOM
- 8.1 window对象
- 8.2 location对象
- 8.3 navigator、screen与history对象
- 第九章 DOM
- 9.1 节点层次
- 9.2 DOM操作技术
- 9.3 DOM扩展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件处理程序
- 10.3 事件对象
- 10.4 事件类型
- 第十一章 JSON
- 11.1-11.2 语法与序列化选项
- 第十二章 正则表达式
- 12.1 创建正则表达式
- 12.2-12.3 模式匹配与RegExp对象
- 第十三章 Ajax
- 13.1 XMLHttpRequest对象
- 你不知道的JavaScript
- 一、作用域与闭包
- 1.1 作用域
- 1.2 词法作用域
- 1.3 函数作用域与块作用域
- 1.4 提升
- 1.5 作用域闭包
- 二、this与对象原型
- 2.1 关于this
- 2.2 全面解析this
- 2.3 对象
- 2.4 混合对象“类”
- 2.5 原型
- 2.6 行为委托
- 三、类型与语法
- 3.1 类型
- 3.2 值
- 3.3 原生函数