js经典面试题及答案汇总(持续更新)

1.js基本数据类型

Undefined 、Null、Boolean、Number、String、Symbol(es6新增)、Bigint(谷歌67版本新增)

2.js引用数据类型

Object(对象)、Array(数组)、Function(函数)

3.js有哪些内置对象?

数据封装类对象:Object、Array、Boolean、Number和String;

其他对象:Function、Arguments、Math、Date、RegExp(正则表达式对象)、Error;

arguments是一个类似于数组的对象,对应于传递给函数的参数。

4.Array和String的常用方法:

String:
charAt() 返回在指定位置上的字符;

​ charCodeAt() 返回在指定位置字符的Unicode编码;

​ indexOf() 检索字符串;

​ match() 可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配 ;

​ replace() 在字符串中查找匹配的子串,并替换与正则表达式匹配的子串;

​ search() 查找与正则表达式相匹配的值;

​ slice() 提取字符串的片段,并在新的字符串中返回被提取的部分,原字符串不会改变;

​ toUpperCase() 把字符串转换为大写。;

​ toLowerCase() 把字符串转换为小写;

​ toString() 把数字转化为字符串;

Array:
shift() 删除并返回数组的第一个元素;

​ unshift() 向数组的开头添加一个或更多元素,并返回新的长度;

​ pop() 删除数组的最后一个元素并返回删除的元素;

​ push() 向数组的末尾添加一个或更多元素,并返回新的长度;

​ concat() 连接两个或更多的数组,并返回结果;

​ reverse() 反转数组的元素顺序;

​ splice()从数组中添加或删除元素 ;

​ slice() 选取数组的一部分,并返回一个新数组,原数组不会改变;

​ from()将伪数组转化为真正的数组,es6新增方法

​ of()将一组数据转化为数据,类似于合并数组,es6新增方法

​ copyWithin()用于从数组的指定位置拷贝元素到数组的另一个指定位置中,截取替换,es6新增方法

5.this对象的理解

this总是指向函数的直接调用者(而非间接调用者);

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

在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this是指向全局对象window。

6.eval是做什么的?

它的功能是把对应的字符串解析成JS代码并运行;

应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)由JSON字符串转换为JSON对象的时候可以用eval, var obj = eval('('+str+')')

	var json="{name:'Mr.CAO',age:30}";
    var jsonObj=eval("("+json+")");
    console.log(json);  
    console.log(jsonObj);

7.DOM怎样添加、移除、移动、复制、创建和查找结点

//创建新节点
createDocumentFragment()  //创建一个DOM片段
createElement()  //创建一个具体的元素
createTextNode() //创建一个文本节点
//添加、移除、替换、插入
appendchild()
removeChild()
replaceChild()
insertBefore()  //在已有的子节点前插入一个新的子节点
//查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性

8.null和undefined的区别

null是一个表示“无”的对象,转为数值时为0;undefined是一个表示“无”的原始值,转为数值时为NaN。

undefined:

​ (1)变量被声明了,但没有赋值时,就等于undefined。

​ (2)调用函数时,应该提供的参数没有提供,该参数等于undefined。

​ (3)对象没有赋值的属性,该属性的值为undefined。

​ (4)函数没有返回值时,默认返回undefined。

null:

​ (1)作为函数的参数,表示该函数的参数不是对象

​ (2)作为对象的原型链的终点。

9.new操作符具体干了什么呢?

​ (1)创建了一个空对象,并且this变量引用该对象,同时还继承了该函数的原型。

​ (2)属性和方法被加入到this引用的对象中。

​ (3)新创建的对象由this所引用,并且最后隐式的返回this。

10.JSON的了解?

​ JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单,易于读写,占用带宽小。

​ 格式:采用键值对,例如:{“age”:“12”,“name”:“back”}

11.call()和apply()、bind()的区别和作用?


都可改变函数运行时的this指向。
第一个参数都是this要指向的对象,apply第二个参数是一个数组,callbind第二个参数都是参数列表,但是bind可以多次传入,applycall都是立即执行,且只临时改变一次this指向,而bind不会立即执行,而是返回一个永久改变this指向的函数。

12.如何获取UA?

function whatBrowser() {
    document.Browser.Name.value = navigator.appName;
    document.Browser.Version.value = navigator.appVersion;
    document.Browser.Code.value = navigator.appCodeName;
    document.Browser.Agent.value = navigator.userAgent;
}

13.哪些常见操作会造成内存泄露?

​ 内存泄露指任何对象在您不再拥有或需要它之后任然存在。

​ (怎样解决内存泄露?)垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存即可回收。

​ setTimeout的第一个参数使用字符串而非函数的话,会引发内存泄露。

​ 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)。

14.线程与进程的区别

一个程序至少有一个进程,一个进程至少有一个线程。

​ 线程的划分尺度小于进程,使得多线程程序的并发性高。

​ 另外,进程在执行过程中拥有独立的内存单元,多个线程共享内存,从而极大地提高了程序的运行效率。

​ 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

​ 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

15.如何解决跨域问题

JSONP、Nginx反向代理

​ 反向代理是在服务器端进行处理。首先修改hosts文件,将域名指向开发者的电脑本身,把自己伪装成服务端,再通过nginx对不同的请求进行转发,把静态资源指向开发者本地电脑的资源,将接口指向实际的服务器。
此外,还有几种解决方案:CORS(跨域资源分享)、服务端配置、webpack本地代理、websocket等

16.对ES6的了解

​ 新增模板字符串(为JavaScript提供了简单的字符串插值功能)、箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值input=>outputs。)、for-of(用来遍历数据一例如数组中的值。)arguments对象可被不定参数和默认参数完美代替。

​ ES6将promise对象纳入规范,提供原生的promise对象。增加了let和const命令,用来声明变量。增加了块级作用域。let命令实际上就增加了块级作用域。ES6规定,var命令和function命令声明的全局变量,属于全局对象的属性;let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。还有就是引入module模块的概念。

17.用过哪些设计模式?

(1)工厂模式:

主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。

(2)工厂模式解决了重复实例化的问题,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

(3)构造函数模式

使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:

构造函数方法没有显示的创建对象(new Object());

直接将属性和方法赋值给this对象;

没有return语句。

(4)原型链模式

(5)构造和原型链的组合模式

18.说说你对闭包的理解

​ 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染缺点是闭包会常驻内存会增大内存使用量使用不当很容易造成内存泄露,在js中,函数即闭包,只有函数才会产生作用域的概念。

​ 闭包有三个特性:

​ (1)函数嵌套函数

​ (2)函数内部可以引用外部的参数和变量

​ (3)参数和变量不会被垃圾回收机制回收

19.请你谈谈cookie的弊端

​ cookie虽然在持久保存客户端数据提供了方便,分担了服务器存储的负担,但还是有很多局限性的。

第一:每个特定的域名下最多生成20个cookie

​ (1)IE6或更低版本最多20个cookie

​ (2)IE7和之后的版本最多可以有50个cookie。

​ (3)Firefox最多50个cookie

​ (4)Chrome和Safari没有做硬性限制

IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie。

cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节。

IE 提供了一种存储可以持久化用户数据,叫做userdata,从IE5.0就开始支持。每个数据最多128K,每个域名下最多1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。

优点:极高的扩展性和可用性

通过良好的编程,控制保存在cookie中的session对象的大小。

通过加密和安全传输技术(SSL),减少cookie被破解的可能性。

只在cookie中存放不敏感数据,即使被盗也不会有重大损失。

控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。

缺点:

Cookie数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉.

安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。

20.浏览器本地存储

HTML5中的web storage包括了两种存储方式:sessionStorage和localStorage

sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。

localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

web storage和cookie的区别

​ Web Storage的概念和cookie相似,区别是它为了更大容量存储设计的。cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外coolie还需要指定作用域,不可跨域调用。

​ 除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。

但是cookie也是不可以或缺的:cookie的作用是与服务器进行交互,作为http规范的一部分而存在,而Web Storage仅仅是为了在本地“存储”数据而生

浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行),值得一提的是IE总是办好事,例如IE7、IE6中的userData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。

21.cookie和session的区别:

​ (1)cookie数据存放在客户的浏览器上,session数据放在服务器上。

​ (2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。

​ (3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能

​ (4)单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

​ (5)所以个人建议:将登陆信息等重要信息存放为session,其他信息信息如果需要保留,可以放在cookie中。

22.如何实现浏览器内多个标签页之间的通信?

​ 调用localstoragecookies等本地存储方式

23.js延迟加载的方式有哪些?

​ defer和async、动态创建DOM方式(创建script,插入到DOM中,加载完毕后callback)、按需异步载入js。

24.javascript对象的几种创建方式

​ (1)工厂模式

​ (2)构造函数模式

​ (3)原型模式

​ (4)混合构造函数和原型模式

​ (5)动态原型模式

​ (6)寄生构造函数模式

​ (7)稳妥构造函数模式

25.浅拷贝与深拷贝

浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。拷贝基本数据类型时,不受任何影响,当拷贝引用类型时,源对象也会被修改。

深拷贝:深拷贝就是完完全全拷贝一份新的对象,它会在内存的堆区域重新开辟空间,修改拷贝对象就不会影响到源对象。

​ 即深浅拷贝是针对于引用数据类型

浅拷贝代码:

let a = {
   name : '张三',
    age : '18'
}
let b = a;
b.name = '李四';
console.log(a); // {name:'李四',age:'18'}
console.log(b); // {name:'李四',age:'18'}

以上浅拷贝后,结果源数据也被修改了,这往往不是我们所需要的。

JS中深拷贝的几种实现方法:

  1. 使用递归的方式实现深拷贝
//使用递归的方式实现数组、对象的深拷贝
export function deepClone (obj) {

  let objClone = Array.isArray(obj) ? [] : {};

  if (obj && typeof obj === "object") {

      for (var key in obj) {

          if (obj.hasOwnProperty(key)) {

              //判断ojb子元素是否为对象,如果是,递归复制

              if (obj[key] && typeof obj[key] === "object") {

                  objClone[key] = deepClone(obj[key]);

              } else {
                  //如果不是,简单复制
                  objClone[key] = obj[key];
              }
          }
      }
  }
  return objClone;
};
  1. 通过 JSON 对象实现深拷贝

    //通过js的内置对象JSON来进行数组对象的深拷贝
    function deepClone2(obj) {
        var _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
        return objClone;
    }
    

    JSON对象实现深拷贝的一些问题:无法实现对对象中方法的深拷贝
    当对象内容项为number, string, boolean的时候,是没有什么问题的。但是,如果对象内容项为undefined,null,Date,RegExp,function,error的时候。使用JSON.parse(JSON.stringify())进行拷贝就会出问题了。

  2. 通过jQuery的extend方法实现深拷贝(推荐在JQ中使用)

    var array = [1,2,3,4];
    var newArray = $.extend(true,[],array);
    
  3. Object.assign()拷贝

    当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

  4. lodash函数库实现深拷贝

    lodash很热门的函数库,提供了 lodash.cloneDeep()方法实现深拷贝。

    总结:
    进行深拷贝的方法:

    递归函数 (推荐使用,项目中使用的更多,更小,更安全)

    JSON.stringify() 和JSON.parse(); (不推荐使用,如果遇到Function,Date等类型的变量容易出现一些意料之外的问题)

    第三方库lodash的cloneDeep()方法

    JQuery的extend()函数 (推荐在JQuery项目中使用,其他项目依然推荐是用递归函数)

26.原型链是什么?

原型链:就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构.称为原型链。

​ Javascript是面向对象的,每个实例对象都有一个_proto_属性,该属性指向它的原型对象,这个实例对象的构造函数有一个原型属性prototype,与实例的proto属性指向同一个对象。当一个对象在查找一个属性的时候,自身没有就会根据_proto _,向它的原型进行查找,如果都没有,则向它的原型的原型继续查找,直到查到Object.prototype.proto为null,这样也就形成了原型链。

​ 由于原型prototype本身是对象,因此,它也有隐式原型,指向的规则不变;这样一来,从某个对象出发,依次寻找隐式原型的指向,将形成一个链条,该链条叫做原型链。
​ 在查找对象成员时,若对象本身没有该成员,则会到原型链中查找
​ 特性的两个情况:

             1. function的隐式原型指向自己的原型;  
             2. Object原型的隐式原型指向null

原型链的主要作用就是减少内存消耗,提高代码的复用率

需要了解
1.a.protoa.prototype都称做为a的原型。
2.Object.prototype是原型链的顶端。
3.如果 a是由b实例化出来的,则有关系a.__proto__ === b.prototype,所以a.__proto__的地址和b.prototype指向的地址是一样的,即他们使用的是同一个对象。

原型链解读

先以函数实例的原型链为例子讲解:

function A(){}
const a = new A()
console.log(a.__proto__ === A.prototype)   // true,这里是根据上面 '需要了解'处可以推断
console.log(A.prototype.__proto__=== Object.prototype)   
// true,这里可以通过打印 A ,然后展开看到 A 就能看到该关系

知道以上关系后,可以得出原型链如下:

再以数组的原型链为例:

const arr=[]
console.log(arr.__proto__===Array.prototype)  //true,根据上面 '需要了解'处可以推断
console.log(Array.prototype.__proto__===Object.prototype)  
// true,打印 Array,然后展开Array就能看到该关系

知道以上关系后,可以得出原型链如下:

其它的原型链如:函数、对象、正则、日期的原型链和上面的基本一致。

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值