JavaScript面试总结及基础面试题

一、面试方法及学习方法

1. 创建知识体系

  • 高效学习三部曲:找准知识体系;刻意训练;及时反馈
  • 知识体系:结构化的知识范围
  • 涵盖所有知识点;结构化、有组织、易扩展

2.编程误区

  1. 只看不练习,注重基础练习(听懂+大量练习 = 学会)

  2. 多做笔记+思维导图(多沉淀+不能只做流水+写出自己的理解)

  3. 背语法规则,其他要理解原理,不能死记硬背(比如说数据结构、底层原理、优化等等)

  4. 不要纠结记不住算法,报错要积极调错不能逃避才能提高,反了足够的错误就是高手了

  5. 不能闭门造车,找学习、高手;不想学习就确定一个高手或者搞定一本书

  6. 不能只是疲于奔命,什么都学,什么都不精通,没有建立真正的体系;

  7. 明确方向和目标,确定每个阶段,以及完成情况,要抓紧落实

  8. 只专注看一本书或者一个视频,其他的只作为某个知识点的补充和参考

3.面试总结

重要的五种题型

  1. 前端页面加载流程TCP请求到页面交互
  2. 前端框架对比react和vue
  3. 理解函数式组件的产生背景和有事;理解js class逐渐被react和vue抛弃的原因
  4. js基础知识,社招特别重视结合实际业务场景出题
  5. 优化方案,建议从TCP请求到接口请求到页面的绘制
  6. 加分题:算法题

二、基础面试题集锦

js基本数据类型

Number、String 、Boolean 、Null、Undefined、Symbol(新类型,表示全局唯一)
数据封装类对象:Object、Array、Boolean、Number 和 String
其他对象:Function、Arguments、Math、Date、RegExp、Error

谈谈对this的理解

  1. this总是指向最后调用它的那个对象
  2. 如果有new关键字,this指向new出来的那个对象
  3. 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。

另外,this的绑定规则

eval是做什么的

它可以把字符串转化为对应的JavaScript代码并运行;尽量避免使用,不安全且耗能(2次,解析、执行)

javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?

除了正常模式运行外,ECMAscript添加了第二种运行模式:“严格模式”。
作用:

  1. 消除js不合理,不严谨地方,减少怪异行为
  2. 消除代码运行的不安全之处,
  3. 提高编译器的效率,增加运行速度
  4. 为未来的js新版本做铺垫

对箭头函数有什么了解

箭头函数是es6里面新加的,表示方法比传统创建函数对象的方法更加简洁。但是箭头函数不能使用argument、super、new.target、不绑定this,没有prototype属性,也不能使用构造函数。

如何判断数组

  • Array.isArray(arr)
  • arr instanceof Array
  • arr.constructor === Array 或 arr.proto.constructor === Array
    弊端:instanceof和constructor的判定也存在一些弊端,他们判定的数组必须定义在同一个页面,否则将会判定为false。如果在iframe中的数组判定,就会出错。

最高级的实现:polyfill

if (!Array.isArray) {
     
  Array.isArray = function(arg) {
     
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}
 
const arr = [1, 2, 3, 4]
Object.prototype.toString.call(arr) === '[Object Array]'   // true

instanceof原理

概念:instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象原型链中的任何位置
即:若A instanceof B表示判断 B 的 prototype 属性指向的原型对象(B.prototype)是否在对象 A 的原型链上。

如何判断属性是对象实例中的属性还是原型中的属性

ECMAScript5中的hasOwnProperty()方法,用于判断只在属性存在与对象实例中的时候,返回true,in操作符只要通过对象能访问到属性就返回true。
因此只要in操作符返回true而hasOwnProperty()返回false,就可以确定属性是原型中的属性。
所以有如下函数:
···js
function hasPrototypeProperty(obj, name) {
return !obj.hasOwnProperty(name) && (name in obj);
}
···

es6的模块化和commenjs模块化区别和差异

模块化就是将变量和函数 放入不同的文件中,减少全局变量 避免变量名和函数命名冲突,提高代码的复用性和维护性 。
①表达方式的不同es6 export import commonhjs module.export require
②注意点:commonJs值的拷贝,es6值的引用、只能放在顶层作用域
③common异步加载、es是同步加载
④commonJS运行时加载,es6编译时输出接口

es6的模块化和commenjs模块化区别

Promise 的优缺点

  • 缺点:

    无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
    如果不设置回调函数,promise 内部抛出的错误,不会反应到外部。
    当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

  • 优点:

    解决回调地狱(Callback Hell)问题
    代码更扁平,可读性更高
    更好地进行错误捕获

CSS有哪些字体单位?

JavaScript面试总结及基础面试题_第1张图片

js发展历史

JS的历史


  1. 原生JS操作 → DOM节点

  2. Jquery 快速操作DOM的工具集,与浏览器更加兼容

  3. Vue/React/angular 真实DOM和VDOM进行同步

    已经不是DOM驱动了,而是数据驱动了,我们只需要去关注我们的数据和我们的业务逻辑。

    获取DOM的话操作会更加灵活一些

  4. 前端工程化

前端渲染 vs 后端渲染

单页面/多页面的描述其实是不太准确的

html + css + 数据 在哪里结合很关键

html + 数据 → 服务端|服务端渲染|要有模板引擎去做html和数据的结合|最终返回的是html

html (css + js) Vue来与服务端通信,然后来进行数据渲染

数据|通过js加载 + API ⇒ 浏览器渲染的过程

所以其实不是单页面/多页面的问题而是数据在哪里渲染的问题

单页面/多页面只是说大多数场景下是这样而已

其实现在前后端是 两个应用程序之间的通信。

大部分的数据服务端渲染,少部分动态的数据浏览器渲染也是可行!ajax

大型架构的话还是以服务端渲染为主。浏览器渲染有个致命缺陷就是seo的不支持。

传统网站是不太适合用框架开发的。框架更适合去开发cms|还有就是APP里面的内置H5.

nuxt.js 对框架来进行服务端渲染,有优化的成本很高了

但这个传统的web+模版引擎已经有很多性能优化的方案了。

比如:不经常改变的html放在CDN里


2021-3-9

js基本数据类型和引用数据类型,判断基本数据类型的几种方式

  • typeof运算符用于判断对象的类型,但是对于一些创建的对象,它们都会返回’object’,有时我们需要判断该实例是否为某个对象的实例,那么这个时候需要用到instanceof运算符,后续记录instanceof运算符的相关用法。与instanceof判断原理的区别

js作用域(全局作用域和函数作用域);var、let、const区别;JS原型链与instanceof底层原理,for-in【索引】和for-of区别【值】;

  • 其中const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。

for-in for-of遍历数组和遍历对象的结果不一样

数组:for-in 遍历的是键名(索引); for-of遍历的是value值

对象:for-in 遍历的是键名 ;

for-in 更适合遍历对象,,for-of不能遍历对象

原因用for-in遍历的话:

  1. 遍历顺序有可能不是按照实际数组的内部顺序

  2. index索引为字符串型数字,不能直接进行几何运算

  3. 使用for in会遍历数组所有的可枚举属性

    原型方法method和name属性

上面的in与下面这句console.log("name" in mc);的意义不一样,这里in检查mc对象里面是否含有name属性,如果对象中没有而原型中有的话也会返回true

原型链
js对象有一个对象.prototype属性,prototype属性内有__proto__指向其父类,父类再用__proto__指向它的父类,直到指向Object原型方法内的proto属性为空,这样就形成了原型指向的链条叫原型链

另外prototype属性内还有一个constructor方法,这个方法指向所属类

ES5 和 ES6 分别几种方式声明变量

ES5 有俩种:varfunction
ES6 有六种:增加四种,letconstclassimport

注意:letconstclass声明的全局变量再也不会和全局对象的属性挂钩

闭包的概念?优缺点?

内嵌函数,函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。并且函数B内变量暂时不会被销毁
(简单理解为闭包就是能读取其他函数内部变量的函数。)

  • 优点:避免全局变量的污染、私有属性;希望一个变量长期存储在内存中

  • 缺点:内存泄露;常驻内存,增加内存使用量

  • 应用:

    • ajax请求的成功回调
    • 为节点循环绑定click事件
    • 延续局部变量的寿命
    • setTimeout的延时回调
    • 函数内部返回另一个匿名函数
var obj = {
     
    name: 'tom',
    sayName() {
     
        var name = 'alan';
        console.log(this.name);
    }
}
obj.sayName();// 'tom'

var name = 'jerry';   
var obj = {
       
    name : 'tom',  
    sayName(){
       
        return function(){
       
            console.log(this.name);  
        };
    }   
};  
obj.sayName()(); // jerry

JavaScript垃圾回收机制

定义:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束

像 C 这样的编程语言,具有低级内存管理原语,如 malloc()和 free()。开发人员使用这些原语显式地对操作系统的内存进行分配和释放。
而 JavaScript 在创建对象(对象、字符串等)时会为它们分配内存,不再使用对时会“自动”释放内存,这个过程称为垃圾收集。

内存生命周期中的每一个阶段:

分配内存 —  内存是由操作系统分配的,它允许您的程序使用它。在低级语言(例如 C 语言)中,这是一个开发人员需要自己处理的显式执行的操作。然而,在高级语言中,系统会自动为你分配内在。
使用内存 — 这是程序实际使用之前分配的内存,在代码中使用分配的变量时,就会发生读和写操作。
释放内存 — 释放所有不再使用的内存,使之成为自由内存,并可以被重利用。与分配内存操作一样,这一操作在低级语言中也是需要显式地执行。

四种常见的内存泄漏:全局变量,未清除的定时器,闭包,以及 dom 的引用
  1. 全局变量 不用 var 声明的变量,相当于挂载到 window 对象上。如:b=1; 解决:使用严格模式
  2. 被遗忘的定时器和回调函数
  3. 闭包
  4. 没有清理的 DOM 元素引用

对前端性能优化有什么了解?一般都通过那几个方面去优化的?

``前端性能优化的七大手段`

  1. 减少请求数量
  2. 减少资源大小
  3. 优化网络连接
  4. 优化资源加载
  5. 减少重绘回流
  6. 性能更好的API
  7. webpack优化

赋值、浅拷贝与深拷贝?

  • 浅拷贝
复制// 第一层为深拷贝
Object.assign()
Array.prototype.slice()
扩展运算符 ...
  • 深拷贝
复制JSON.parse(JSON.stringify())

递归函数

复制function cloneObject(obj) {
  var newObj = {} //如果不是引用类型,直接返回
  if (typeof obj !== 'object') {
    return obj
  }
  //如果是引用类型,遍历属性
  else {
    for (var attr in obj) {
      //如果某个属性还是引用类型,递归调用
      newObj[attr] = cloneObject(obj[attr])
    }
  }
  return newObj
}

2021-3-11

有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣 【具体点开跳转文章查看】

Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()

// 4种判断是否是数组的方式:
Array.isArray(arr)
arr instanceof Array
arr.constructor === Array
Object.prototype.toString.call(arr) === '[object Array]'
...
‘https://www.cnblogs.com/onepixel/p/5126046.html’

怎么理解原型链

js对象有一个对象.prototype属性,prototype属性内有__proto__指向其父类,父类再用__proto__指向它的父类,直到指向Object原型方法内的proto属性为空,这样就形成了原型指向的链条叫原型链

另外prototype属性内还有一个constructor方法,这个方法指向所属类

async/await 的详解

(1) 内置执行器
Generator 函数的执行必须靠执行器,所以才有了co模块。
Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
自动执行,输出最后结果

(2)更好的语义。
(3)适用性广
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象
await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)async函数的返回值是 Promise 对象

function stop_buble(e) {
     
    let ev = e || window.event
    if (ev && ev.stopProgation) {
     
        ev.stopProgation()
    } else {
     
        ev.cancelBubble()
    }
}

script标签中defer和async的区别是什么?

默认下载和执行脚本将会按照文档的先后顺序同步进行。当脚本下载和执行的时候,文档解析就会被阻塞,在脚本下载和执行完成之后文档才能往下继续进行解析。

下面是async和defer两者区别:

- 当script中有defer属性时,脚本的加载过程和文档加载是异步发生的,等到文档解析完,脚本才开始执行。

- 当script有async属性时,脚本的加载过程和文档加载也是异步发生的。停止HTML解析,先脚本解析完再继续HTML解析。

- 当script同时有async和defer属性时,取async

wait发生异常还能不能解析往下执行?

如果有错误发生 使用try catch 捕获异常

描述一下 V8 执行一段JS代码的过程

  1. 词法分析语法分析成ast(语法抽象树)

  2. ast -> 解释器 -> 字节码

  3. 执行字节码,编译器将字节码逐行转换成机器码。执行的过程中如果有热点代码就不会再将热点代码转换为机器码,而是直接使用之前保存好的机器码

     其中,
     字节码是介于AST 和 机器码之间的一种代码
     热点代码:js语句转换的字节码中相同的代码就叫热点代码。
    

栈和堆分别是什么?

  • 数据结构:

栈——先进后出、

堆——优先队列,可以根据文件大小进行排列,完全二叉树是其中的一种实现方式

  • 操作系统

栈——编译器自动分配释放,存储参数值或局部变量的值

堆:由程序员手动释放或垃圾回收机制释放

undefined 和 undeclared的区别

undefined 声明未赋值,undeclared未声明

shijxh

JavaScript面试总结及基础面试题_第2张图片

js的指向问题

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this永远指向最后调用它的那个对象

如果有new关键字,this指向new出来的那个对象

其中,箭头函数的this始终指向函数定义时的this,而非执行时。箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值。

apply、call、bind的区别

  • apply 与call类似,传入的是数组
    var a ={
     
        name : "Cherry",
        fn : function (a,b) {
     
            console.log( a + b)
        }
    }
    
    var b = a.fn;
    b.apply(a,[1,2])     // 3
  • call 与apply类似,传入的是参数列表
    var a ={
     
        name : "Cherry",
        fn : function (a,b) {
     
            console.log( a + b)
        }
    }

    var b = a.fn;
    b.call(a,1,2)       // 3
  • bind 创建一个新函数并需要手动调用
    var a ={
     
        name : "Cherry",
        fn : function (a,b) {
     
            console.log( a + b)
        }
    }

    var b = a.fn;
    b.bind(a,1,2)()           // 3

2021-3-20

ES5和ES6继承的区别

ES5先创建子类的实例对象,再将父类添加到子类的原型链上 Parent.apply(this)

ES6先创建父类的实例对象,子类通过extend关键字继承父类的属性和方法

具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。

你可能感兴趣的:(面试相关,JavaScript,js,面试)