前端面试题【JS部分】

这里我主要是在博客上搜索了前端面试相关的一些面试题目合集,并把其答案一一整理在了题目下方,有一些不好理解的也做了简单的解释。在最后有纯题目版

JS前端面试题

1.JS数据类型

  • JS的基本数据类型有8种:
    number,string,boolean,undefined,object,Null,symbol,bigInt
    • ES5语法下只有六种:number,string,boolean,undefined,object,Null
    • ES6语法下有八种:添加了 symbol , bigInt
      • symbol:这种类型的对象永不相等,可以解决属性名冲突问题。
      • bigInt:安全存储、操作大整数
    • 基本数据类型:number,string,boolean,undefined,Null
    • 引用数据类型:object,Array,Date,function

2.JS变量 和 函数声明 的 提升

  • 变量提升:在当前的作用域中,js代码自上而下执行之前,浏览器会把所有带var / function 关键字进行提前声明或定义
    • 带var的关键字只是提前声明一下
    • 带function的关键字在变量提升阶段把定义和声明都完成了
  • 函数提升——函数声明提升: 通过function声明的函数,在声明语句之前就可以直接调用
    • js中函数有两种:函数声明式、函数字面量式(函数表达式、匿名函数),只有函数声明才存在函数提升
 console.log(f1); // function f1() {}  
 console.log(f2); // undefined 
 function  f1() {}  // 函数声明式
 var f2 = function() {}  // 函数字面量式

真正的执行顺序是:

  function  f1() {}  // 函数声明式
 console.log(f1); // function f1() {}  
 console.log(f2); // undefined 
 var f2 = function() {}  // 函数字面量式
  • 变量提升和函数声明提升的优先级:函数会首先被提升,然后才是变量,函数不会被变量声明覆盖,但是会被变量赋值覆盖。
  • 函数内部变量提升优先级高于函数外部变量提升

3.闭包

  • 定义:能够读取其他函数内部变量的函数——可以理解为:定义在一个函数内部的函数
  • 闭包是函数传递和作用域链同时使用造成的结果
var a = "全局环境";
function A() {
  var a = "局部环境";
  return {
    B: function () {
      console.log(a);
    },
  };
}
var obj = A();
obj.B(); // "局部环境"

现在,我们在函数A的内部返回了一个对象,该对象内部有一个函数B.我们在全局环境下调用了这个函数B,结果打印出了局部环境。这就是一个闭包。我们成功的在全局作用域下调用到了函数A作用域中的变量。

  • 好处:可以读取函数内部的变量 、 变量始终都在内存中 、 封存对象的私有属性和私有方法
  • 坏处:耗内存,使用不当会导致内存溢出

4.== 和 === 之间的区别

  • == 非严格意义上的相等,值相等就行
  • === 严格意义上的相等,数据类型和值都要相等

5.this

  • 函数中,指向函数的直接调用者
  • new中,指向new出来的对象
  • 事件中,指向触发这个事件的对象

6.forEach 和 map

  • 相同点:都是数组方法——循环遍历数组,匿名函数的this都是指向window,只能遍历数组
  • 不同点:
    • forEach只适合读出数组中数据,但不改变其中的值,比如打印或者存入
    • map适合需要改变数组中的数值,速度更快,而且他会返回一个新的数组

7.箭头函数 和 普通函数 的区别

  • 外形不同
function func(){
    //code
}
let func=()=>{
    //code
}
  • 箭头函数都是匿名函数
// 具名函数
function func(){
  // code
}
 
// 匿名函数
let func=function(){
  // code
}

// 箭头函数全都是匿名函数
let func=()=>{
  // code
}
  • 不能使用new
function person( name , age ){
    this.name = name ;
    this.age = age ;
}
//普通函数可以new对象
let admin = new person( "xiaotu" , 21) ;
console.log(admin.name) ;
console.log(admin.age)
// xiaotu
// 21
  • 箭头函数this的指向不同——箭头函数this指向声明的作用域
var name="xiaotu" ;
let func=()=>{
    console.log(this.name) ;
}
func();
//xiaotu
// 箭头函数在全局作用域声明,this指向全局window

var name = "xiaotu1";
function wrap(){
  this.name="xiaotu2";
  let func=() => {
    console.log(this.name);
  }
  func();
}
let en=new wrap();
//xiaotu2
//箭头函数在wrap作用域中声明,this指向wrap对象
  • 不能使用argument【类数组】对象
let C = (...c) => {
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]

8.同源策略

同源指的是域名、协议、端口号相同
同源策略是一种约定,它是浏览器最核心也最基本的安全功能

  • 存在的意义
    • 非同源下的cookie等隐私数据可以被随意获取
    • 非同源下的DOM可以随意操作
    • ajax可以任意请求的话,用户的隐私肯定会泄露
  • 同源策略的限制范围
    • 不能获取不同源的cookie、localstorage、indexDB
    • 不能获取不同源的 DOM()
    • 不能发送不同源的 ajax 请求(可以向不同源的服务器发起请求,但是返回的数据会被浏览器拦截)

9.如何解决跨域

跨域:从一个域名的网页请求另一个域名的资源

  1. nodejs代理请求
  2. jsonp——json的一种使用形式
    • 浏览器禁止JS跨域,但是<script>标签跨域请求。客户端使用script代替XHR(XMLHttpRequest)发起跨域请求。服务器在json响应数据前后填充一些额外的内容,就称为“填充式JSON”——JSONP

10.严格模式

  • 变量先声明后使用
  • 函数参数不能有同名属性
  • 函数声明必须在顶层,不允许在非代码块内声明函数
  • 禁止this指向全局对象(定时器的this还是指向window)

11.ES6新增

  1. let ——作用与var相似,用于声明变量
    + let不能重复声明变量
    + ES6 引入块级作用域,let声明变量在{}块级作用域内有效
    + let不存在变量提升
  2. const ——用来声明常量
  3. 解构赋值
    ES6允许按照一定的模式从数组和对象中提取值
//数组的解构
const c = [1,2,3] ;
let [l , m , n] = c ;
//1=1 ; m=2 ; n=3

// 对象的解构
 const liMing = {
     name: 'liMing',
     age: '22',
     tell: function(){
         console.log(`I am liMing`)
        }
     }

     let {name, age, tell} = liMing

     console.log(name) // 'liMing'
     console.log(age) // '22'
     console.log(tell) // f(){...}
     tell() // I am liMing
  1. 箭头函数
  2. rest参数
    ES6引入rest参数,用于获取函数的实参,用来代替arguments
        // ES5获取实参的方式
     function printStudent(){
         console.log(arguments) // arguments为一个对象
     }
     printStudent('LiMing','HanMeimei')

     // ES6获取实参的方式
     function printFriend(friend1, friend2, ...rest){ // rest参数必须放在形参列表最后,否则会报错
         console.log(friend1) 
         console.log(friend2) 
         console.log(rest) // 得到一个数组,可以使用数组api
     }
     printFriend('小猫','小狗','兔子','鸭子')
     // 小猫
     // 小狗
     // ['兔子','鸭子']
  1. 扩展运算符
    ...能将数组转化为逗号分隔的参数序列
     const STUDENTS = ['小明','小芳','小红']
     function printStudent(){
         console.log(arguments)
     }
     printStudent(STUDENTS) // 参数为一个数组,数组内包含3个元素
     printStudent(...STUDENTS) // 参数为3个元素

     //数组合并
     const STUDENTS1 = ['小明','小芳','小红']
     const STUDENTS2 = ['小吴', '小王']
     // es5写法
     const STUDENTS_ES5 = STUDENTS1.concat(STUDENTS2)
     // es6写法
     const STUDENTS_ES6 = [...STUDENTS1, ...STUDENTS2]

  1. 两种数据类型 symbol bigInt
  2. Promise【重要,要专门去理解】
    语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。可以避免回调地狱。
  3. 迭代器(iterator):是一种接口。任何一种数据结构,只要部署了iterator接口,就可以完成遍历操作
        const food = ['鱼香肉丝','糖醋里脊','酸菜鱼']
     for(let item of food){
         console.log(item)
     }
     let iterator = food[Symbol.iterator]()
     console.log(iterator.next()) // {value: "鱼香肉丝", done: false}
     console.log(iterator.next()) // {value: "糖醋里脊", done: false}
     console.log(iterator.next()) // {value: "酸菜鱼", done: false}
     console.log(iterator.next()) // {value: undefined, done: true} true 表示遍历已经结束
  1. set(集合)
    本质上是个对象,类似于数组,但是成员的值都是唯一的。集合实现了iterator接口,可以使用扩展运算符和for...of进行遍历。
  • size —— 元素个数
  • add —— 添加元素
  • delete —— 删除元素,返回 boolean 值
  • has —— 检测集合中是否包含某个元素
  1. Map
    Map——键值对的集合,Map也实现了iterator接口,所以可以使用「扩展运算符」和for…of进行遍历。
  • size 、 set 、 get 、has 、 clear

12.数组方法

map 、 foreach 、 filter 、 sort 、 reverse…

13.js深浅拷贝

  • 数据类型分为基本数据类型,引用数据类型
    • 前者存储在栈内存中
    • 后者地址存储在栈内存中,其值存在堆内存中
  • 深浅拷贝
    • 浅拷贝slice()、concat():会在栈中开辟另一块空间,并将被拷贝对象的栈内存数据完全拷贝到该块空间中。引用类型的值就是拷贝了地址
    • 深拷贝JSON.parse(JSON.stringify(obj)):引用类型会在内存中在开辟出来另一块空间存储引用类型的值

14.异步编程的实现方式

  • 回调函数
    • 优点:简单,容易理解
    • 缺点:回调地狱,代码耦合度高
  • promise对象
    • 优点:利用then方法,进行链式书写;可以书写异步错误时的回调函数
  • async 函数
    • 优点:内置执行器,更好的语义,更广适用性,返回的是promise,结构清晰
    • 缺点:没有错误处理机制

    async/await 是ES7提出的基于Promise的解决异步的最终方案
    async是一个加在函数前的修饰符,对async函数可以直接then
    await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。取到值后语句才会往下执行;

  // 使用async/await获取成功的结果
  // 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){
  return new Promise((resolve,reject)=>{
      setTimeout(()=>{
          resolve('获取成功')
      },3000)
    })
  }
  async function test(){
    let a = await getSomeThing();
    console.log(a)
  }
  test(); // 3秒后输出:获取成功

15.面向对象的编程思想

  • 基本思想就是:使用对象、类、继承、封装等基本概念来完成程序设计
  • 优点:以维护、易拓展、降低工作量

16.项目性能优化

  • 减少HTTP请求数
  • 减少DNS查询:通过DNS将网址转化为IP地址进行访问
  • 减少DOM元素数量和操作
  • 使用外部的JSCSS

17.单线程,单线程和异步的关系

单线程:一个线程,同一时间只能运行一个程序
异步:非阻塞机制,在某一进程存在阻塞和延迟状况时,不影响主进程的运行。

  • JS的单线程是负责JS解释执行的·引擎主线程·是单线程的(单线程和异步不可能同时成为一个语言的特点)。但是JS所依赖的宿主环境(浏览器,node等)是多线程的。这就使得JS拥有了异步属性。
  • 浏览器同一时间内只有一个线程在运行JS程序,但是浏览器为耗时程序开辟了另外的线程。

18.说说负载均衡

  • 负载均衡是高并发,高可用系统必不可少的关键组件,目标是:尽力将网络流量平均分发到多个服务器上,可以提高系统的整体响应速度和可用性。
  • 分类:硬件负载均衡、软件负载均衡

19.作用域链

各个作用域的嵌套关系组成一条作用域链,我们能通过作用域链访问到父级里声明的变量或者函数

20.原型,原型链,继承

  • 原型:一个函数可以看做一个类,原型是所有类都有的一个属性。作用就是给这个类的每一个对象都添加统一的方法。
    • 分类
      • 显示原型:prototype,是每个函数function独有的属性
      • 隐式原型:proto,是每个对象都具有的属性
  • 原型链:A.proto -> B.prototype / B.proto -> C.prototype / C.proto -> …
    直到找到顶层对象的显性原型,这个查找路径就是原型链。
 	//这是一个构造函数
 	function Foo(name,age){
 		this.name=name;
 		this.age=age;
 	}
 	/*所有的函数都有一个prototype属性,这个属性是一个对象
 	  所有的对象可以自由扩展属性
 	  于是就有了以下写法*/
 	Foo.prototype={
 		// prototype对象里面又有其他的属性
 		showName:function(){
 			console.log("I'm "+this.name);//this是什么要看执行的时候谁调用了这个函数
 		},
 		showAge:function(){
 			console.log("And I'm "+this.age);//this是什么要看执行的时候谁调用了这个函数
 		}
 	}
 	var fn=new Foo('小明',19)
 	/*当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的'prototype'属性中去找*/
 	fn.showName(); //I'm 小明
 	fn.showAge(); //And I'm 19

在这里插入图片描述

  • 优点节省资源,不用在每一个对象里面都有showName()showAge(),原型实现的话,每个对象都可以使用原型中的方法。

21.JS垃圾回收机制

js的垃圾回收机制是为了防止内存泄漏(已经不需要的某一块内存还一直存在着)
垃圾回收机制就是不停歇的寻找这些不再使用的变量,并且释放掉它所指向的内存。
在JS中,JS的执行环境会负责管理代码执行过程中使用的内存。

  • 垃圾回收方式:1. 标记清除——大部分浏览器使用,声明是标记,离开环境时再标记,之后将其清除 、 2. 引用计数——会引起内存泄露

22.变量生命周期

  • 局部变量:当前函数结束后就会释放内存
  • 全局变量:知道浏览器关闭,释放内存

23.逐渐增强和优雅降级

  1. 低版本->高版本
  2. 高版本->低版本

纯题:

  1. js数据类型
  2. js变量,函数声明 的提升
  3. 闭包
  4. == 和 === 之间的区别
  5. this
  6. forEach 和 map
  7. 箭头函数 , 普通函数的区别
  8. 同源策略
  9. 如何解决跨域
  10. 严格模式
  11. ES6新增
  12. 数组方法
  13. js深浅拷贝
  14. 异步编程的实现方法
  15. 面向对象的编程思想
  16. 项目性能的优化
  17. 单线程,单线程和异步的关系
  18. 负载均衡
  19. 作用域链
  20. 原型、原型链、继承
  21. JS垃圾回收机制
  22. 变量生命周期
  23. 逐渐增强和优雅降级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值