Js前端面试题

178 阅读6分钟

1. Js的基本数据类型

  1. null
  2. undefined
  3. string
  4. symbol
  5. bigint
  6. boolean
  7. number
  8. object

Es6 新增了symbol和bigint两种类型,symbol一般常用可以结合redux的action的type进行使用;bigint是大数处理,一般除非项目中涉及到很大的数才会用到。

2. 数据类型检测的方式有哪些

  1. typeof , 但是在判断Array null为object
  2. instanceof , 通过prototype 判断构造函数
  3. construct,通过构造函数来判断
  4. Object.prototype.toString()

一般项目中常用的判断方式可能是使用typeof,typeof null === "object" 是一个历史遗留问题.

3 null 和 undefined 区别

两者都是基本数据类型 undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会 影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。

但是现在大多数浏览器应该是都无法使用undefined作为一个变量名。

5 intanceof 操作符的实现原理及实现

intanceof 是判断构造函数的prototype是否存在于对象的原型链上,一直找到Object.prototype.

知道了原理,实现就很简单了,就是无限循环递归

function myInstanceOf(left:object, right:object) {
  // Object.getPrototypeOf() 返回对象的原型
  const leftPrototype = Object.getPrototypeOf(left);
  const rightPrototype = right.prototype;
  while(leftPrototype) {
    if(leftPrototype === rightPrototype) return true;
    if(!rightPrototype) return false;
    leftPrototype = Object.getPrototypeOf(leftPrototype);
  }
  return fasle;
}

6 Object.is() 与比较操作符 “===”、“==” 的区别?

=== 判断两边类型和值都相等才返回true

== 会进行隐士类型转换,转换之后才判断,项目中不推荐==进行判断

Object.is() 基本上和===使用类似,这两者的区别在于如何判断+0和-0,以及NaN的处理

console.log(+0 === -0); //true
console.log(Object.is(+0, -0)); //false

console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); //true

console.log(Number.NaN === Number.NaN); // false
console.log(Object.is(Number.NaN, Number.NaN)); // true

console.log(NaN === Number.NaN); // false
console.log(Object.is(NaN, Number.NaN)); // true

7 什么是BigInt

JavaScript 中 Number.MAX_SAFE_INTEGER 表示最大安全数字,计算 结果是 9007199254740991,即在这个数范围内不会出现精度丢失(小 数除外)。

8 如何判断一个对象是一个空对象

function isEmptyObject(obj={}) {
  return Object.keys(obj).length > 0;
}
console.log(isEmptyObject({}));
console.log(isEmptyObject({'a':1}));

9 new 一个类的时候发生了什么?

  1. 创建一个对象
  2. 把该对象的__proto__指向类的原型
  3. 使用apply执行构造函数,如果返回是一个对象就返回,如果不是就返回刚才创建的对象。

10 Proxy 可以实现什么功能

在 Vue3.0 中通过 Proxy 来替换原本的 Object.defineProperty 来实现数据响应式。

之所以 Vue3.0 要使用 Proxy 替换原本的 API 原因在于 Proxy 无需一层层递归为每个属性添加代理,一次即可完成以上操作,性能上更好,并且原本的实现 有一些数据更新不能监听到,比如数组的push和pop等,但是 Proxy 可以完美监听到任何方式的数据改变,唯一缺陷就是浏览器的兼容性不好。

Proxy是Es6中添加的,基本使用如下:

const target1 = {
  message1: "hello",
  message2: "everyone"
};

const handler2 = {
  // target 原始对象,这里是指target1,prop传入的属性,receiv   // er表示是接受的对象,这里是handle2
  get(target, prop, receiver) {
    return "world";
  }
};

const proxy2 = new Proxy(target1, handler2);

11 Js 文件延迟加载方法有哪些?

  1. defer:js文件下载会和浏览器的解析同时执行,当浏览器解析完毕后,然后再执行js文件。
  2. async:js文件下载会和浏览器的解析同时执行,当js文件下载完毕后,会立即执行js文件。
  3. 如果没有defer和async,文件会立即下载和立即执行,并且会阻塞浏览器的解析。

12 ES6 模块与 CommonJS 模块的区别

相同点: ES6和CommonJS都可以对引入的对象内部重新赋值

不同点: CommonJS模块输出的是一个值的拷贝,ES6 模块输出的是值的引用; 也就是说ComonnJS是引用的一个值的拷贝,如果当我们引入之后,修改了原来文件的内容,我们引用的值不会改变,比如下面的例子,test.js中输出的值都是3,3

// lib.js
let counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};
// test.js
const mod = require("./lib");
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3

ES6是导入的引用,有点类似指针,所以当引入的文件内容改变后,会跟着改变。

可以看下下面的例子

// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}
// test.js
export let counter = 3;
export function incCounter() {
  counter++;
}

13 for...in 和 for...of 的区别

for...of 是 ES6 新增的遍历方式,允许遍历一个含有 iterator 接口 的数据结构(数组、对象等)并且返回各项的值

for...in 主要是遍历对象,并且会沿着原型链向上查找

for... in 遍历数组的时候,返回的是数组下标 for... of 遍历数组的时候,返回的是数组的值

例子如下:

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

const iterable = [3, 5, 7];
iterable.foo = 'hello';

for (const i in iterable) {
// logs "0", "1", "2", "foo", "arrCust  om", "objCustom"
  console.log(i); 
}

for (const i in iterable) {
  if (Object.hasOwn(iterable, i)) {
    // logs "0", "1", "2", "foo"
    console.log(i); 
  }
}

for (const i of iterable) {
  // logs 3, 5, 7
  console.log(i); 
}

for...of 不能遍历对象,如果想要遍历对象,可以使用如下代码

const obj = {
  a: 1,
  b: 2,
};
for (let [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

14 原型和原型链的经典图

15 this的理解

  1. 当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。

  2. 如果一个函数作为一个对象的方法来调用时, this 指向这个对象。

  3. 如果一个函数用 new 调用时,函数执行 前会新创建一个对象,this 指向这个新创建的对象。

  4. apply 、 call 和 bind 调用模式, 这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数: 一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数, 第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。 也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对 象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其 他情况下都不会改变。

  5. 箭头函数的this指向定义的时候,最外层的this

16 内存泄露的情况

  1. 全局变量
  2. 闭包
  3. dom元素的引用,当dom被删除后,引用没有清空。

本文由mdnice多平台发布