前端面试---JavaScript(上)
Published on Feb 09, 2023, with 7 view(s) and 0 comment(s)
Ai 摘要:本文介绍了JavaScript数据类型及其检测方法。JavaScript有8种数据类型,分为基本类型(number、string等)和引用类型(object),存储方式不同。检测方法包括:typeof(对基本类型有效)、instanceof(判断引用类型)、constructor(可被修改)和Object.prototype.toString.call(最准确)。还探讨了null与undefined的区别、typeof null返回"object"的原因,以及instanceof的实现原理。最后列举了判断数组的多种方式。

一,JavaScript数据类型

1,JavaScript数据类型有哪些?区别?

八种: 基本数据类型:number,string,boolean,null,undefined,symbol,bigInt 引用数据类型:object

区别: 基本数据类型之间存储在栈中,占据空间小,大小固定,属于频繁使用的数据 引用数据类型存储在堆中,在栈中存储了一个指针指向该实体的地址。

栈和堆: 栈在数据结构中的存取方式是先进后出。堆是一个优先队列,是按照优先级来排序的优先级可以按照大小来规定。 栈内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。堆内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收器回收。

2,数据类型检测的方法

typeof

console.log(typeof 2); // number 
console.log(typeof true); // boolean 
console.log(typeof 'str'); // string 
console.log(typeof []); // object 
console.log(typeof function(){}); // function 
console.log(typeof {}); // object 
console.log(typeof undefined); // undefined 
console.log(typeof null); // object

其中数组、对象、null都会被判断为object,其他判断都正确。

instanceof 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

可以看到,instanceof只能正确判断引用数据类型,而不能判断基本数据类型。instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

**constructor **

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

constructor有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了:

function Fn(){}; 
Fn.prototype = new Array(); 
var f = new Fn(); 
console.log(f.constructor===Fn); // false 
console.log(f.constructor===Array); // true

**Object.prototype.toString.call() ** Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:

var a = Object.prototype.toString; 
console.log(a.call(2)); 
console.log(a.call(true)); 
console.log(a.call('str')); 
console.log(a.call([])); 
console.log(a.call(function(){})); 
console.log(a.call({})); 
console.log(a.call(undefined)); 
console.log(a.call(null));

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么? 这是因为toString是Object的原型方法,而Array、function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。 3. 判断数组的方式有哪些

3,判断数组的方式有哪些

通过Object.prototype.toString.call()做判断

Object.prototype.toString.call(obj).slice(8,-1) === 'Array';

通过原型链做判断

obj.__proto__ === Array.prototype;

通过ES6的Array.isArray()做判断

Array.isArrray(obj);

通过instanceof做判断

obj instanceof Array

通过Array.prototype.isPrototypeOf

Array.prototype.isPrototypeOf(obj)

4,null和undefined的区别

null代表的含义是空对象,undefined代表的含义是未定义。 一般变量声明了但是还没有定义的时候会返回undefined,null主要赋值给一些可能会返回对象的变量作为初始化

undefined在JavaScript中不是一个保留字,可以用来当作变量名

5,typeof null的结果是什么,为什么?

Object 在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:

000: object - 当前存储的数据指向一个对象。 
1: int - 当前存储的数据是一个 31 位的有符号整数。 
010: double - 当前存储的数据指向一个双精度的浮点数。 
100: string - 当前存储的数据指向一个字符串。 
110: boolean - 当前存储的数据是布尔值。

如果最低位是 1,则类型标签标志位的长度只有一位;如果最低位是 0,则类型标签标志位的长度占三位,为存储其他四种数据类型提供了额外两个 bit 的长度。 有两种特殊数据类型: ● undefined的值是 (-2)30(一个超出整数范围的数字); ● null 的值是机器码 NULL 指针(null 指针的值全是 0) 那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。 javascript中不同对象在底层都表示为二进制,而javascript 中把二进制前三位都为0的判断为object类型,而null的二进制表示全都是0,自然前三位也是0,所以执行typeof时会返回'object'

6. intanceof 操作符的实现原理及实现

instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。

function myInstanceof(left, right) { // 获取对象的原型 
let proto = Object.getPrototypeOf(left) // 获取构造函数的 prototype 对象 
let prototype = right.prototype; // 判断构造函数的 prototype 对象是否在对象的原型链上 
while (true) { 
  if (!proto) return false; 
  if (proto === prototype) return true; // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型 
  proto = Object.getPrototypeOf(proto); 
  } 
}