前端面试——JavaScript面经(持续更新)
一、数据类型
1. JavaScript用哪些数据类型、它们有什么区别?
JavaScript共有八种数据类型,分别包括5种基本数据类型和3种非基本数据类型。
- 基本数据类型:
Undefined
、Null
、Boolean
、Number
、String
。 - 非基本数据类型:
Object
、Symbol
、BigInt
。
其中Symbol
和BigInt
是ES6新增的数据类型:
Symbol
代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。BigInt
是一种数字类型的数据,它可以表示任意精度格式的整数,使用BigInt
可以安全地存储和大整数,即使这个数超出了Number的安全整数范围。
区别一:分为原始数据类型和引用数据类型。
- 原始数据类型:
Undefined
、Null
、Boolean
、Number
、String
。 - 引用数据类型:
Object
。另外还有数组Array
和函数Function
。
区别二:存储位置不同。
- 原始数据类型直接存储在**栈(stack)**中,往往占据空间小、大小固定、属于被频繁使用数据,所以放在栈中。
- 引用数据类型存储在**堆(heap)**中,往往占据空间大、大小不固定,如果存在栈中将会影响程序运行的性能。因此,引用数据类型在栈中存储了指针,指针指向堆中该实体的起始地址。当解释器寻找引用值时,会先检索其在栈中的地址,再根据地址从堆中获得实体。
扩展知识:堆与栈
堆和栈的概念存在于数据结构和操作系统内存中。
- 在数据结构中:
- 栈:先进后出
- 堆:先进先出
- 在操作系统中分为堆区和栈区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。操作方式类似于数据结构中的栈。
- 堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
2. 数据类型的检测方式有哪些?详细讲讲
2.1 typeof
// 1.typeof 数组、对象和null都会被视为object 其他类型都判定正确
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof null); // object
console.log(typeof function () {}); // function
console.log(typeof 1); // number
console.log(typeof true); // boolean
console.log(typeof "str"); // string
console.log(typeof undefined); // undefined
console.log(typeof Symbol()); // symbol
根据上面的结果可以看到数组、对象和null都会被视为object,其他类型都能判定正确。
2.2 instanceof
它的原理是:判断在其原型链中能否找到该类型的原型
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log("str" instanceof String); // false
console.log([] instanceof Array); // true
console.log(function () {} instanceof Function); // true
console.log({} instanceof Object); // true
console.log(null instanceof Object); // false 这是因为null是原型链的尽头 它没有后续原型链 更不可能找到Object类型的原型
根据上面的结果可以看到 instanceof只能正确判断引用类型,基本数据类型无法判定。
需要注意的是:null instanceof Object结果是false
,因为null是原型链的尽头,它没有后续原型链,更不可能找到Object类型的原型。
2.3 constructor
它的原理是:**除了null之外,任何对象都会在其prototype
/__proto__
上有一个constructor
属性,而constructor属性返回一个引用,这个引用指向创建该对象的构造函数,而Number
、Boolean
、String
、Array
都属于构造函数。**因此通过construct和构造函数就能判断类型是否符合。
console.log((2).constructor); // ? Number() { [native code] } Number构造函数
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(("str").constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function () {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
// console.log((null).constructor === Object); // 会报错 原因是null不存在constructor
// console.log((undefined).constructor === Object); // 会报错 原因是undefined不存在constructor
// console.log((null).constructor); // 会报错
// console.log((undefined).constructor); // 会报错
从上面的结果看到,constructor
除了不能判断null
和undefined
外,其它类型都能判断。
需要注意的是,如果创建的对象的原型被改变了,constructor
就不能用来判断数据类型了。
function Fn() {}
console.log(Fn.prototype.constructor); // f Fn() {}
Fn.prototype = new Array()
console.log(Fn.prototype.constructor); // ? Array() { [native code] }
let f = new Fn();
console.log(f.constructor); // ? Array() { [native code] }
console.log(f.__proto__); // ? Array() { [native code] }
console.log(f.constructor === Fn); // false
console.log(f.constructor === Array); // true
扩展知识:constructor
的两个作用:
- 判断数据类型。
- 对象实例通过construct对象访问它的构造函数。
2.4 Object.prototype.toString.call()
它的原理是:对象原型上的toString
方法会获取当前对象的类型然后返回[object Type]
字符串,由于部分内置对象对toString
重写了,因此需要调用.call()
来利用原本的toString
函数,.call(args)
方法实现让调用call
方法的对象的this
指向传的参数args
。
let a = Object.prototype.toString;
console.log(a.call(2)); // [object Number]
console.log(a.call(2) == Number); // false
console.log(a.call(2) == "[object Number]"); // true
console.log(a.call(true)); // [object Boolean]
console.log(a.call(true) == Boolean); // false
console.log(a.call(true) == "[object Boolean]"); // true
console.log(a.call("str")); // [object String]
console.log(a.call("str") == String); // false
console.log(a.call("str") == "[object String]"); // true
console.log(a.call(new Date())); // [object Date]
console.log(a.call(new Date()) == Date); // false
console.log(a.call(new Date()) == "[object Date]"); // true
console.log(a.call([])); // [object Array]
console.log(a.call(function () {})); // [object function]
console.log(a.call({})); // [object Object]
console.log(a.call(undefined)); // [object undefined]
console.log(a.call(null)); // [object Null]
通过上面代码可以看到,Object.prototype.toString.call()
可以验证任何类型。
2.5 封装一个类型验证的方法
大型项目中往往会使用Object.prototype.toString.call()
封装一个isType
方法来验证类型,封装代码如下:
function isType(data, type) {
const typeObj = {
"[object String]": "string",
"[object Number]": "number",
"[object Boolean]": "boolean",
"[object Null]": "null",
"[object Undefined]": "undefined",
"[object Object]": "object",
"[object Array]": "array",
"[object Function]": "function",
"[object Date]": "date", // Object.prototype.toString.call(new Date())
"[object RegExp]": "regExp",
"[object Map]": "map",
"[object Set]": "set",
"[object HTMLDivElement]": "dom", // document.querySelector('#app')
"[object WeakMap]": "weakMap",
"[object Window]": "window", // Object.prototype.toString.call(window)
"[object Error]": "error", // new Error('1')
"[object Arguments]": "arguments",
};
let name = Object.prototype.toString.call(data); // 借用Object.prototype.toString()获取数据类型
let typeName = typeObj[name] || "未知类型"; // 匹配数据类型
return typeName === type; // 判断该数据类型是否为传入的类型
}
下面我们可以测试一下封装结果:
console.log(
isType({}, "object"), // true
isType([], "array"), // true
isType(new Date(), "object"), // false
isType(new Date(), "date") // true
);
2.6 总结
方法名 | 效果 |
---|---|
typeof | 数组、对象和null 都会被视为object ,其他类型都能判定正确 |
instanceof | 只能正确判断引用类型,基本数据类型无法判定 |
constructor | 除了不能判断null 和undefined 外,其它类型都能判断 |
Object.prototype.toString.call() | 可以判断所有类型,但是返回结果是字符串【最推荐,封装isType 】 |
3. 判断数组的方式有哪些?
let arr = []
Object.prototype.toString.call(arr).slice(8,-1) === 'Array'
或者Object.protoType.toString.call(arr) === '[object Array]'
- 通过原型链判断:
arr.__proto__ === Array.prototype
- 通过
Array.isArray(arr)
- 通过
arr instanceof Array
4. null和undefined有什么区别?
- 含义不同:
undefined
代表的含义是未定义,而null
代表的含义是空对象。 - 初始化场景不同:通常变量声明了但还没有定义的时候使用
undefined
,null
主要用在初始化一些可能会返回对象的变量。 - typeof判断结果不同:
typeof undefined
返回undefined
,typeof null
返回object
一般变量声明了但还没定义的时候会返回undefined
。
需要注意的是:
使用null == undefined
返回true
,null === undefined
返回false
。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!