跳到主要内容

类型

原始(Primitive)类型

有 6 中原是值类型,分别是:

  • boolean
  • number
  • string
  • undefined
  • symbol
  • null

原始类型存储的都是值,没有方法可以调用。

注意区分 string 和 String,后者表示 String 对象,有内置方法可以调用。

string 类型是不可变的,无论你在 string 类型上调用何种方法,都不会对值有改变。

另外对于 null 来说,很多人会认为他是个对象类型,其实这是错误的。虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。

面试题:原始类型有哪几种?null 是对象嘛?

对象(Object)类型,引用类型

引用类型有

对象、数组、函数

在 JS 中,除了原始类型那么其他的都是对象类型了。对象类型和原始类型不同的是,原始类型存储的是值,对象类型存储的是地址(指针)。

面试题:对象类型和原始类型的不同之处?函数参数是对象会发生什么问题?

typeof vs instanceof

面试题:typeof 是否能正确判断类型?instanceof 能正确判断对象的原理是什么?

typeof 对于原始类型来说,除了 null 都可以显示正确的类型。

typeof true // 'boolean'
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'

typeof 对于对象来说,除了函数都会显示 object,所以说 typeof 并不能准确判断变量到底是什么类型。

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof typeof BigInt(9007199254740991) // 'bigint'

bigint

instanceof 能正确判断对象的原理是什么?

判断一个对象与构造函数是否在一个原型链上

const Person = function () {};
const p1 = new Person();
p1 instanceof Person; // true

var str = "hello world";
str instanceof String; // false

var str1 = new String("hello world");
str1 instanceof String; // true

实现类型判断的函数

function getType(target) {
if (target === null) {
return "null";
}
const typeOfTarget = typeof target;
if (typeOfTarget !== "object") {
return typeOfTarget;
}
const template = {
"[object Object]": "object",
"[object Array]": "array",
// 包装类型
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",

"[object Function]": "function",
"[object Symbol]": "symbol",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Set]": "set",
"[object Map]": "map",
"[object WeakMap]": "weakmap",
"[object WeakSet]": "weakset",
};
const typeString = Object.prototype.toString.call(target);
return template[typeString];
}

'string' 为什么会有 length 方法

通过字面量的方式创建:var a = 'string';,这时它就是基本类型值; 通过构造函数的方式创建:var a = new String('string');这时它是对象类型。

基本类型是没有属性和方法的,但仍然可以使用对象才有的属性方法。这时因为在对基本类型使用属性方法的时候,后台会隐式的创建这个基本类型的对象,之后再销毁这个对象

如何判断一个数据是不是 Array

  • Array.isArray(obj)
    • ECMAScript 5 种的函数,当使用 ie8 的时候就会出现问题。
  • obj instanceof Array
    • 当用来检测在不同的 window 或 iframe 里构造的数组时会失败。这是因为每一个 iframe 都有它自己的执行环境,彼此之间并不共享原型链,所以此时的判断一个对象是否为数组就会失败。此时我们有一个更好的方式去判断一个对象是否为数组。
  • Object.prototype.toString.call(obj) == '[object Array]'
    • 这个方法比较靠谱
  • obj.constructor === Array
    • constructor 属性返回对创建此对象的函数的引用

undefined 可被赋值

在 ES3 中(Firefox4 之前),window.undefined 就是一个普通的属性,你完全可以把它的值改变成为任意的真值,但在 ES5 中((Firefox4 之后),window.undefined 成了一个不可写,不可配置的数据属性,它的值永远是 undefined。

var undefined = 1;
alert(undefined); // chrome: undefined, ie8: 1

不管是标准浏览器,还是老的 IE 浏览器,在函数内部 undefined 可作为局部变量重新赋值

function fn() {
var undefined = 100;
alert(undefined); //chrome: 100, ie8: 100
}
fn();

有时候我们需要判断一个变量是不是 undefined,会这样用

if (str === undefined) {
console.log("I am empty");
}

但假如 str 这个变量没声明就会出现报错,用下面的方式会更好一些

if (typeof str === "undefined") {
console.log("I am better");
}

有时候我们会看到这种写法

if (str === void 0) {
console.log("I am real undefind");
}

那是因为 「void 0」的执行结果永远是「undefined」, 即使在某些老旧浏览器 或者在某个函数中 undefined 被重新赋值,我们仍然可以通过void 0得到真正的 undefined