值 | 字符串的操作环境 | 数字的运算环境 | 逻辑运算环境 | 对象的操作环境 |
---|---|---|---|---|
undefined | "undefined" | NaN | false | Error |
null | "null" | 0 | false | Error |
非空字符串 | 不转换 | 字符串对应的数字值 | true | string |
空字符串 | 不转换 | 0 | false | string |
0 | "0" | 不转换 | false | Number |
NaN | "NaN" | 不转换 | false | Number |
Infinity | "Infinity" | 不转换 | true | Number |
Number.POSITIVE_INFINITY | "Infinity" | 不转换 | true | Number |
Number.NEGATIVE_INFINITY | "-Infinity" | 不转换 | true | Number |
-Infinity | "-Infinity" | 不转换 | true | Number |
Number.MAX_VALUE | "1.7976931348623157e+308" | 不转换 | true | Number |
Number.MIN_VALUE | "5e-324 | 不转换 | true | Number |
其它数字 | " 数字的字符串值 " | 不转换 | true | Number |
true | "true" | 1 | 不转换 | Boolean |
false | "false" | 0 | 不转换 | Boolean |
对象 | toString() | valueOf() toString() NaN() | true | 不转换 |
把数字转化为字符串
var a = 123456;
a = a + '';
alert(typeof a); // 返回字符串 string
布尔值转化为字符串,返回字符串 "true" 或 "false"
var a = true;
a = a + '';
alert(a); //返回字符串 "true"
把数组转化为字符串,返回数组元素列表,以逗号分开
var a = [1, 2, 3];
a = a + '';
alert(a);
// 返回字符串 1 , 2 , 3
把函数转化为字符串,返回函数的代码字符串
var a = function () {
return 1;
};
a = a + '';
alert(a);
// 返回字符串 "var a = function () {return 1;}"
如果把 JavaScript 内置对象转化为字符串,则只返回构造函数的基本结构代码,而自定义的构造函数,则与普通函数一样,返回函数结构的代码字符串。
a = Date + '';
alert(a);
// 返回字符串 "functionDate() {[native code]}"
如果内置对象为静态函数,则返回字符串有所不同。
const a = Math + '';
// 返回字符串 "[object Math]"
alert(a);
对象直接量,则返回字符串为 "object object"
var a = { x: 1 };
a += '';
alert(a);
// 返回字符串 "[object object]"
如果是自定义的对象实例,则返回字符串为 "[object object]"
var a = new (function () {})();
a += '';
// 返回字符串 "[object object]"
alert(a);
如果是内置对象实例,则返回值必须根据传递的参数而定
a = new RegExp(/^\w$/) + '';
alert(a);
// 返回字符串 "/^\w$/"
加号运算符有两个功能:数值求和、字符串连接。但字符串连接的优先级要大于求和运算。因此,在可能的情况下,即运算元的类型不同的情况下,加号运算符会先尝试把数值运算元转化为字符串,再执行连接操作。
var a = 1 + 1 + 'a';
var b = 'a' + 1 + 1;
var c = 'a' + (1 + 1);
alert(a); // 返回字符串 "2a"
alert(b); // 返回字符串 " a11 "
alert(c); // 返回字符串 "a2"
当原始值调用 toString() 方法时, JavaScript 会自动把它们封装成对象,然后再调用 toString() 方法,把它们转化为字符串。
var a = 123456;
a.toString();
alert(a);
// 返回字符串 "123456"
使用加号运算符转换字符串,实际上也是调用 toString() 方法来实现的。只不过是 JavaScript 自动调用 toString() 方法来实现的。
JavaScript 能够自动转化变量的类型。在自动转换中, JavaScript 一般会遵循:根据运算的类型环境,按需要运行转换。例如,如果在执行字符串连接操作时,则会有把字符串转换为字符串;如果在执行基本数学运算时,则会尝试把字符串转换为数值;如果在逻辑运算环境中,则会尝试转化为布尔值。
toString() 是 Object 类型的原型方法 ,Number 继承该方法后 , 重写 toString() , 允许传递一个整数的参数 , 设置显示模式 . 数字的默认为十进制显示模式,通过设置参数可以改变数字的模式。
Number 扩展了 toString() 方法,允许传递一个参数,该参数可以设置数字大的显示模式。数字默认为十进制显示模式,通过设置参数可以改变数值模式。
默认模式,直接转换成字符串类型的数字
var a = 1.0;
var b = 0.0001;
var c = 1e-4;
alert(a.toString()); // 返回字符串 "1"alert(b.toString()); // 返回字符串 "0.0001"
alert(c.toString()); // 返回字符串 "0.0001"
toString ()方法可以直接输出整数和浮点数,保留小数位小数位末尾的零会清除。但是科学计数法,则在条件许可的情况下把它转换为浮点数,否则就使用科学计数法输出字符串。
var a = 1e-14;
alert(a.toString()); // 返回字符串
1e-14;
八进制和十六进制会被转换成 十进制 输出
var a = 010;
var b = 0x10;
alert(a.toString()); // 返回字符串 "8"
alert(b.toString());
// 返回字符串 "16"
如果设置参数,则按参数进行相对应的进制输出
var a = 10;
alert(a.toString(2)); // 返回 进制数字字符串 "1010"
alert(a.toString(8)); // 返回 进制数字字符串 "12"
alert(a.toString(16)); // 返回 进制数字字符串 "a"
转化为小数格式的字符串
使用 toString() 方法将数值转化为字符串时,无法保留小数部分。于是,从 1.5 版本开始, JavaScript 定义了 3 个新方法: toFixed() 、 toExponential() 、 toPrecision() 。
把数值转化成字符串,并显示小数后的指定位数。
var a = 10;
alert(a.toFixed(2)); // 返回字符串 "10.00"
alert(a.toFixed(4)); // 返回字符串 "10.0000"
把数字转化成科学计数法形式的字符串。
var a = 123456789;
//返回字符串 "1.23e+8"
alert(a.toExponential(2));
// 返回字符串 "1.2345e+8"
alert(a.toExponential(4));
与 toExponential() 类似,但可以指定有效数字的位数,而不是小数位数。
// 返回字符串 "1.2e+8"
var a = 123456789;
alert(a.toPrecision(2));
// 返回字符串 "1.234e+8"
alert(a.toPrecision(4));
将值转化为数字有 parseInt() 和 parseFloat() 。其中 parseInt() 把值转化为整数,而 parseInt() 把值转化为浮点数。
parseInt() 和 parseFloat() 函数对字符串类型的值有效,其它类型调用这两个函数都会返回 NaN 。在转换之前,它们会对字符串进行分析,以验证转换是否继续。
再开始转换时, parseInt() 函数会先查看位置 0 的字符,如果该位置不是有效数字,则返回 NaN ,不再深入分析若是位置 0 位为有效数字,则将移位分析。
alert(parseInt('123abc')); // 返回数字 123
alert(parseInt('1.73')); // 返回数字 1
alert(parseInt('.123')); // 返回 NaN
如果首位是 0 开头的字符串,则 parseInt() 会把它当作八进制进行处理,先转换成数值,然后再再换成十进制输出如果是 0X 开头,则按十六进制进行转换。
var d = '010';
var e = '0x10';
alert(parseInt(d)); // 返回十进制数字 8
alert(parseInt(e)); // 返回十进制数字 16
parseInt() 也支持基数模式,可以把二进制、八进制、十六进制等不同进制数字字符串转换为整数,基模式由 parseInt() 第二个参数决定
parseInt('123abc', 16); // 返回十进制数字 1194684
parseInt('10', 2); // 返回十进制数字 2
parseInt('10', 8); // 返回十进制数字 8
parseInt('10', 10); // 返回十进制数字 10
parseInt('010'); // 返回十进制数字 8
parseInt('010', 8); // 返回十进制数字 8
parseInt('010', 10); // 返回十进制数字 10
parseFloat()
parse() 函数与 parseInt() 函数用法基本相同,但是它能识别打一个出现的小数点号,而第二个小数点被视为违法。
此外,数字必须是十进制的字符串,而不能是八进制或十六进制的数字字符串。同时对于数字前加 0 的会忽略,且十六进制字符串会返回 0 。
parseFloat('1.234.5'); // 返回数值 1.234
parseFloat('123'); // 返回数值 123
parseFloat('123abc'); // 返回数值 123
parseFloat('010'); // 返回数值 10
parseFloat('0x10'); // 返回数值 0
parseFloat('x10'); // 返回数值 NaN
加号运算符不仅可以执行求值还能执行字符串连接。由于 JavaScript 处理字符串连接连接优先级又高于数值求和。因此,当数字字符串与数值使用加号相连接时,将优先执行连接,而不是求和。
var a = 1;
var b = '1';
alert(a + b);
// 返回字符串 "11"
在执行表达式 a + b 时,变量 a 现被转换成字符串,然后进行计算,所以得到的是 "11" ,而不是 2 。
var a = 1;
var b = '1';
alert(a + b * 1);
// 返回数值 2
console.log(!!0);
console.log(Boolean(0));
不过使用这种方法会把布尔值包装为引用对象,而不再是原始值。
var a = 1;
var b = !!a;
var c = new Boolean(a);
alert(typeof b); // 返回 'boolean'
alert(typeof c); // 返回 'object'
使用 new 命令调用 String 、 Number 、 Boolean 类型函数,可以把字符串和布尔值转化为 3 类简单的值包装成对应类型的对象。
// 下面都会返回 'object'
console.log(typeof new String(123));
console.log(typeof new Number(123));
console.log(typeof new Boolean(123));
在逻辑运算环境中,所有的复合型数据对象转化为布尔值都是 true 。
在数值的运算环境中,对象先尝试调用 valueOf() 方法,如果不成功,则调用 toString() 方法 , 获取一个值或 NaN 。
在字符串的运算环境中,对象会调用 toString() 方法获取对象的字符串表示,然后根据运算环境,再把字符串转化为简单值。
数组转化为简单值时,会调用 toString() 方法获取一个字符串表示,然后根据具体的运算环境,再把该字符串转化成对应的简单值 。
函数转化为简单值时,会调用 toString() 方法获取字符串表示。对应于普通的函数,则返回的是函数的代码本身,然后根据运行环境,再把该字符串转化为对应的值。
把非对象在逻辑运算符中,则对象转换 成 true ,即便是值为 false 的包装对象。
对象被自动转换成数值,转换失败,则返回 NaN 。
数组将根据包含的元素决定。
如果是空数组,转换为 0 先调用 toString ()转换成空字符串,再强制转换成数值 0 。 若包含一个数字元素则转换为该值。 若含多个值,或者仅包含一个非数字,返回 NaN
对象在模糊运算环境中转换
对象和数字加号运算时,尽可能求和,否则按字符串连接 对象与字符串加号运算时,直接连接为新的字符串 对象与数值进行比较运算时,尝试将对象转换成数值,若不然,按字符串比较 对象与字符串比较时,直接转换成字符串,进行比较操作
强制类型转化
堆( heap )用于为复杂数据类型分配空间,例如数组对象、 Object 对象。它是在运行时动态分配内存的,因此存取速度较慢。
栈( stack )中主要存放一些基本类型的变量和对象的引用。其优势是存取速度比堆要快,并且栈内的数据可以共享。但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。例如下面的代码定义两个变量,变量的值都是数字类型。
var a = 3;
var b = 3;
JavaScript 解释引擎先处理 var a=3; ,首先会在栈中创建一个变量为 a 的引用,然后查找栈中是否有 3 这个值,如果没找到,就将 3 存放进来,然后将 a 指向 3 。接着处理 var b=3; ,在创建完 b 的引用变量后,查找栈中是否有 3 这个值,因为在栈中已经存在了,便将 b 直接指向 3 。这样,就出现了 a 与 b 同时指向 3 的情况。
此时,如果再令 a=4 ,那么 JavaScript 解释引擎会重新搜索栈中是否有 4 这个值,如果没有,则将 4 存放进来,并令 a 指向 4 ;如果已经有了,则直接将 a 指向这个地址。因此 a 值的改变不会影响到 b 的值。
JavaScript 堆不需要程序代码来显式地释放,因为堆是由自动的垃圾回收来负责的,每种浏览器中的 JavaScript 解释引擎有不同的自动回收方式,但一个最基本的原则是,如果栈中不存在对堆中某个对象堆的引用,那么就会认为该对象已经不再需要,在垃圾回收时就会清除该对象占用的空间。
因此,在不需要时应该将对对象的引用释放掉,以利于垃圾回收,这样可以提高程序的性能。释放对对象的引用最常用的方法就是为其赋值为 null ,例如下面代码将 newArray 赋值为 。
null : newArray = null;
在堆和栈的使用问题上,最易犯的错误就是 String 的使用,例如下面的代码:
var str = new String('abc');
var str = 'abc';
同样是创建两个字符串,第一种是用 new 关键字来新建 String 对象,对象会存放于堆中,每调用一次就会创建一个新的对象;而第二种是在栈中,栈中存放值 "abc" 和对值的引用。
推荐使用第二种方式创建多个 "abc" 字符串,这种写法在内存中只存在一个值,有利于节省内存空间。同时它可以在一定程度上提高程序的运行速度,因为存储在栈中,其值可以共享,并且由于栈访问更快,所以对于性能的提高大有裨益。
而第一种方式每次都在堆中创建一个新的 String 对象,而不管其字符串值是否相等及是否有必要创建新对象,从而加重了程序的负担。并且堆的访问速度慢,对程序性能的影响也大。
另外,出于逻辑运算的考虑,当对两个变量进行比较时,使用堆和栈存储就会有差异。
例如下面的代码,实际只比较栈中的值:
var str1 = 'abc';
var str2 = 'abc';
alert(str1 == str2); // true
alert(str1 === str2); // true
不管是逻辑等于还是逻辑全等运算都返回 true ,可以看出 str1 和 str2 指向同一个值。
例如下面的代码,实际只比较堆中的值:
var str1 = new String('abc');
var str2 = new String('abc');
alert(str1 == str2); // false
alert(str1 === str2); // false
不管是逻辑等于还是逻辑全等运算都返回 false ,可以看出 str1 和 str2 指向的不是同一个对象。
例如下面的代码,比较堆中和栈中的值:
var str1 = new String('abc');
var str2 = 'abc';
alert(str1 == str2); // true
alert(str1 === str2); // false
在进行逻辑等于运算时,会首先将变量转成相同的数据类型,然后进行对比。变量 str1 和 str2 的数据类型虽然不同,但比较运算还是返回 true 。但逻辑全等运算与逻辑等于运算不同,它会对数据类型进行比较,看是否是引用的同一个数据。