类型
JavaScript的语言类型有哪些?
JavaScript有七种语言类型:
| 语言类型 | typeof 运算结果 | |
|---|---|---|
| 基本类型 | 对象 | |
| null | object | |
| undefined | undefined | |
| boolean | boolean | |
| number | number | |
| string | string | |
| symbol | symbol | |
| object | object |
如何正确的检测null值的类型?
let a = null;
!a && typeof a === 'object';
undefined 和 null 有什么区别?
undefined 表示未定义,我们可以通过全局变量 undefined 将自定义的变量指定为 undefined 类型,请注意 undefined 是一个 标识符 而不是JavaScript的关键字,所以它是可以被当作变量使用和赋值的。 null 表示已经定义了但是为空,null 是JavaScript的关键字,当你试图对它进行赋值操作时,引擎将抛出错误。
为什么说字符串具有不变性?
字符串的不变性是指字符串的成员方法不会改变其原始值,而是创建并返回一个新的字符串。
0.1 + 0.2 === 0.3?
从常规的数学运算的角度来看答案显然为true,但事实上在JavaScript中 0.1 + 0.2 = 0.30000000000000004 ,所以上面的问题的结果为false。
如何比较两个浮点数是否相等?
对于JavaScript来说,数字比较的误差范围值为 2^-52,当两数相减的结果小于误差范围值时,就认为这两个浮点数相等。
const a = 0.1 + 0.2;
const b = 0.3;
function numbersCloseEnoughToEqual(n1, n2) {
return Math.abs(n1 - n2) < Math.pow(2, -52);
}
numbersCloseEnoughToEqual(a, b); // true;
如何判别一个number类型的变量是不是NaN?
ES6开始你可以使用 Number.isNaN(...) 来判断变量是不是NaN,请不要使用 window.isNaN(...) ,因为内建的全局函数存在缺陷。当我们不支持ES6的语法时,我们可以为其设置polyfill:
if (!Number.isNaN) {
Number.isNaN = function(n) {
return n !== n; // NaN是JavaScript中唯一一个不等于自身的值
};
};
+0 === -0?
在JavaScript中 -0 是存在的,并且 +0 === -0 的结果为true,当我们将 -0 转换为字符串时我们得到的是 "0"。如果你需要判别 -0 ,那么你可以通过以下的方式:
function isNegZero(n) {
return n === 0 && 1 / n === -Infinity;
}
如何安全的检查变量类型?
我们可以利用两个个知识点相结合来解决这一问题:
- 装箱,基本类型在调用方法时,JavaScript会将它包装成一个封装对象。
- 内置属性
[[Class]],该内置属性描述了变量所持有的值是什么类型,我们可以通过Object.prototype.toString(...)来访问该属性。
var a = 'abc';
Object.prototype.toString.call(a); // [object String]
var b = null;
Object.prototype.toString.call(a); // [object Null]
强制类型转换
强制类型转换是什么,它遵循怎样的规则?
从语言角度分析,值从一种类型转换为另一种类型称之为类型转换,而隐式的情况我们称之为强制类型转换,并且强制类型转换总是返回一个标量基本类型,下方列出了三种抽象操作的转换规则: ToString:
| Boolean | Number | Null | Undefined | |
|---|---|---|---|---|
| String | 'true' and 'false' | 遵循通用规则(极大与极小的值将以指数形式呈现) | 'null' | 'undefined' |
ToNumber:
| Boolean | String | Null | Undefined | |
|---|---|---|---|---|
| Number | true -> 1 false -> 0 | 遵循数字常量的相关规则,处理失败时返回NaN | 0 | NaN |
ToBoolean: undefined 、 null 、 false 、 +0 、 -0、 NaN 、 '' ''这七个假值在进行强制类型转换时会得到 false ,相对于所列出的假值列表以外的所有值将转换为 true。
parseInt(...)操作算是强制类型转换吗,你知道下方这道题的执行结果吗?
var a = '12a';
var b = parseInt(a, 10); // 12
var c = Number(a); // NaN
答案揭晓, parseInt(...) 操作我们普遍认为它属于解析而非强制类型转换,上述的这道题你会发现解析操作允许出现非数字字符,而强制类型转换则不允许,它将返回NaN。
对普通数组[1,2,3]进行ToString抽象操作,会得到什么结果?
对普通数组进行ToString抽象操作时,引擎会将所有元素进行强制类型转换,将它们都变为字符串类型,然后使用,拼接起来。
var arr = [1, 2, 3];
arr.toString(); // 1,2,3
你真的了解JSON.stringify(...)吗,以下对象的转换结果是什么?
var o = {
name: 'O_c',
character: ['open', undefined, 'sanguine'],
getName: function() {
return this.name;
},
[Symbol.toStringTag]: 'myObject'
};
JSON.stringify(o); // "{"name":"O_c","character":["open",null,"sanguine"]}"
上述对象的转换结果可能有些出乎意料,JSON.stringify在处理对象时,当属性为undefined、function、symbol时会自动忽略,当以上三种类型的值出现在数组中时,JavaScript引擎会用null进行替换,以保证单元位置不变。
a + "" 和 String(a) 两者是否存在区别?
在多数情况下,a + ""被简单的理解为将a的值转换为字符串类型,看似和String(a)并没有太大区别,但是请你运行一下下方的例子:
var o = {
valueOf() {
return 10;
},
toString() {
return 1;
}
};
o + "";
String(o);
显然 o + "" 的结果为 10,而 String(o) 的结果为 1,实际上当 + 运算符的某个操作数是字符串时,它会对其他的操作数进行隐式强制类型转换。当遇到对象时会执行 ToPrimitive 抽象操作,首先执行 valueOf() 方法,然后通过 ToString 抽象操作将 valueOf 的返回值转换为字符串,而 String() 则是直接调用 ToString 抽象操作。
为什么我们一直在避讳宽松相等 ==, "42" == true 的结果是?
在看到上述的题目时,我们的大脑下意识见会去考虑 "42" 是一个真值还是一个假值。很显然它是一个真值,所以我们会认为上述的问题的结果为 true ,但事实则是 false。在宽松相等比较中,当有一个操作数为布尔值时,会对该布尔值进行 ToNumber 抽象操作,既发生了一次隐式强制类型转换。所以 "42" == 1 的结果为 false ,其它类型的隐式强制类型转换机制如下:
- 字符串和数字之间进行比较时,会对 String 类型的变量进行 ToNumber 抽象操作。
- 其他类型和布尔值之间进行比较时,会对 Boolean 类型的变量进行 ToNumber 抽象操作。
- 在宽松相等中,null 和 undefined 相等。
- 对象与非对象之间进行比较时,会对 Object 类型的变量进行 ToPrimitive 抽象操作。
- 对象与对象之间进行比较时,仅当两个对象指向的地址相同时才相等,不会发生任何强制类型转换。