多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 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(); // .. } ~~~