Js前端面试题

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多平台发布

你可能感兴趣的:(Js前端面试题)