JavaScript面试题

相关面试题

作用域和闭包

词法作用域

JavaScript 中有两个机制可以“欺骗”词法作用域:eval(..) 和 with。前者可以对一段包含一个或多个声明的“代码”字符串进行演算,并借此来修改已经存在的词法作用域(在 运行时)。后者本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作作 用域中的标识符来处理,从而创建了一个新的词法作用域(同样是在运行时)。
这两个机制的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认 为这样的优化是无效的。使用这其中任何一个机制都将导致代码运行变慢。不要使用它们。

原型和原型链

原型:在JavaScript中原型是一个prototype对象,用于表示类型之间的关系。

  • 函数都带有一个prototype 属性,这是属性是指向构造函数的原型对象,这个对象包含所有实例共享的属性和方法。
  • 原型对象都有一个constructor 属性,这个属性指向所关联的构造函数。
  • 每个对象都有一个proto 属性[非标准的方法],这个属性指向构造函数的原型 prototype

原型链:JavaScript万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。

  • 当访问实例对象的某个属性时,会先在这个对象本身的属性上查找,如果没有找到,则会 通过 proto 属性去原型上查找,如果还没有 找到则会在构造函数的原型的 proto中查 找, 这样一层层向上查找就会形成一个作用域链,称为原型链

闭包

1
2
3
4
for (var i=1; i<=5; i++) { setTimeout( function timer() {
console.log( i );
}, i*1000 );
}

输出:666666

改变:

1
2
3
4
5
for (var i=1; i<=5; i++) { (function(j) {
setTimeout( function timer() { console.log( j );
}, j*1000 );
})( i );
}

输出:123456

块作用域和闭包联手便可天下无敌。把var改成let

1
2
3
4
for (let i=1; i<=5; i++) { setTimeout( function timer() {
console.log( i );
}, i*1000 );
}

this和对象原型

ES6

  1. 数组常用遍历的方法

forEach、map、filter、find、every、some、reduce,它们有个共同点:不会改变原始数组。

  • forEach:遍历数组
1
2
3
4
var numbers = [1,2,3,4,5];
var sum = 0;
numbers.forEach(number=>sum+=number)
console.log(sum)//15
  • map:将数组映射成另一个数组(map通过指定函数处理数组的每个元素,并返回处理后新的数组,map 不会改变原始数组。forEach和map的区别在于,forEach没有返回值。)

map需要返回值,如果不给return,默认返回undefined

  • filter:从数组中找出所有符合指定条件的元素
  • find:返回通过测试(函数内判断)的数组的第一个元素的值
  • every&some
    every:数组中是否每个元素都满足指定的条件
    some:数组中是否有元素满足指定的条件
    Some: 一真即真;Every: 一假即假

  • reduce:将数组合成一个值(reduce() 方法接收一个方法作为累加器,数组中的每个值(从左至右) 开始合并,最终为一个值。)

  1. 浅拷贝与深拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝的实现方式:

  • Object.assign()拷贝的是对象的属性的引用,而不是对象本身。当object只有一层的时候,是深拷贝
  • Array.prototype.concat()
  • Array.prototype.slice()

Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

深拷贝的实现方式

  • JSON.parse(JSON.stringify())这种方法虽然可以实现数组或对象深拷贝,但不能处理函数
  • 函数库lodash提供_.cloneDeep用来做 Deep Copy
  • 手写递归方法
    递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

问题

堆栈内存以及闭包作用域

  1. JS的八种数据类型?

基本数据类型: number 数字; boolean 布尔值;string 字符串;
null 空对象; undefined 未定义的值(很多浏览器的初始值是undefined);Symbol() 产生一个唯一的值,和谁都不重复;

引用数据类型:

基本数据类型与引用数据类型的区别:
基本数据类型是操作值,引用数据类型操作的是堆内存空间地址

  1. JS堆栈内存的运行机制?
  2. 变量提升机制?
  3. 作用域和作用域链?

    JS中的作用域分为两种:
      全局作用域和函数作用域。
      函数作用域中定义的变量,只能在函数中调用,外界无法访问。
      没有块级作用域导致了if或for这样的逻辑语句中定义的变量可以被外界访问,
      因此ES6中新增了let和const命令来进行块级作用域的声明。
    

    作用域链 变量的查找机制
    // 上级作用域 函数在哪里定义的,那么该函数执行形成的作用的上级作用域就是谁

  1. 闭包的两大作用:保存和保护
  • 闭包就是在函数里面声明函数,本质上说就是在函数内部和函数外部搭建起一座桥梁,使得子函数可以访问父函数中所有的局部变量
  • 是保护变量不受外界污染,使其一直存在内存中
  1. JS编译机制
  2. JS高级编程技巧

面向对象和this的处理

  1. 单例设计模式
  2. 类和实例
  3. 原型和原型链
  4. new运算符的实现机制
  5. call/apply/bind
  6. constructor构造模式
  7. JS中this的五种情况的梳理
  8. JS中四大数据类型的检测方案
  9. JS中四大继承检测包含深浅拷贝

DOM和BOM以及事件的处理机制

  1. DOM/BOM的核心操作
  2. 事件对象
  3. 拖拽及拖拽插件封装
  4. 发布订阅设计模式
  5. 深度解析JQ源码
  6. 事件传播机制和事件代理
  7. DOM2级事件的核心运行机制
  8. 移动端TOuch/Gesture事件及封装处理
  9. 浏览器底层渲染机制和DOM的回流重绘
  10. DIALOG模态框组件的封装

ES6/ES7的核心知识

  1. let/const以及var的区别
  2. 箭头函数
  3. 解构赋值和拓展运算符
  4. Set/Map数据结构
  5. Promise设计模式
  6. async和await以及实现原理
  7. Generator生成器函数
  8. Promise A+规范
  9. JS底层运行机制:单线程和同步异步编程
  10. 事件循环机制
  11. Interator迭代器和For of循环

Ajax/HTTP前后端数据交互

  1. AJAX核心四步操作
  2. GET/POST 核心机制与区别
  3. TCP三次握手和四次挥手
  4. axios库和源码解析
  5. fetch基础和实践应用
  6. 前端开发中的9中跨域方案
  7. HTTP网络状态码和实践中的处理方案
  8. 前端性能优化汇总
  1. ES6模块化如何使用,开发环境如何打包?
    模块化的基本语法:export语法,import语法
    开发环境配置:babel编译ES6语法 npm init
    npm install --save-dev babel-core babel-preset-es2015 babel-preset-latest

创建.babelrc文件
npm install --global babel-cli
babel --version
JS众多模块化标准:
AMD成为标准,require.js(也有CMD)
前端打包工具,nodejs模块化可以被使用
模块化可以使用webpack和rollup

  1. Class和普通构造函数有何区别?
    JS构造函数:
    Class的基本语法:
    语法糖:
    继承:

  2. Promise的基本使用和原理

  3. ES6的常用功能?
  4. ES6新特性

    Let和const关键字:
    var、let、const的区别
    1. let和const声明变量不存在变量提升,如果要使用这个变量,我们需要在变量定义之后使用;
    2. let和const不能重复声明变量,如果重复声明会报错;
    3. 用let 和 const 在全局声明变量不会给window增加属性;
    4. let和const出现在代码块中,会把代码块(字面量声明对象除外)变成块级作用域,并且出现暂时 性死区
    
    变量的解构赋值
    
    class(创建类) 
    import/export(基于ES6的模块规范创建导入/导出模块(文件/组件)) 
    new set(数组去重)
    Symbol(唯一的值)  var a = Symbol('qqq')
    ...ary(展开运算符、剩余运算符)
    ${} 模板字符串 
    解构赋值  let {a} = obj; let [b] = ary
    for of 循环 
    ()=>{} 箭头函数
    

数组新增方法:flat、find、findIndex

对象新增方法: Object.assign() Object.values() Object.keys() Object.create()…

数组去重:
1、双for循环去重
2、利用对象的属性名不能重复去重
3、利用es6的Set不能重复去重

文章目录
  1. 1. 作用域和闭包
    1. 1.1. 词法作用域
    2. 1.2. 原型和原型链
    3. 1.3. 闭包
  2. 2. this和对象原型
  3. 3. ES6
  • 问题
    1. 1. 堆栈内存以及闭包作用域
    2. 2. 面向对象和this的处理
    3. 3. DOM和BOM以及事件的处理机制
    4. 4. ES6/ES7的核心知识
    5. 5. Ajax/HTTP前后端数据交互
  • 本站总访问量 本站访客数人次 ,