前端js面试题大全2020

1、介绍一下js的数据类型有哪些,值是如何存储的?
基本数据类型:Number、String、Boolean、null、undefined、Symbol(es6新增,表示独一无二的值)和 Bigint(es10新增)
引用类型:object
原始数据类型:直接存储在栈(stack)中,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。

引用数据类型:同时存储在栈(stack)和堆(heap)中,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

2、说一下js的数据类型的转换都有哪些?
在 JS 中类型转换只有三种情况,分别是:

转换为布尔值(调用Boolean()方法)
转换为数字(调用Number()、parseInt()和parseFloat()方法)
转换为字符串(调用.toString()或者String()方法)
注:null 和 underfined 没有 .toString 方法

3、如何去判断js数据类型?
首先我们可以用typeof去判断,typeof只能判断基本数据类型,对于引用数据类型,一律返回object,在js中,数组是一种特殊的对象类型,因此typeof一个数组,返回的是object。
还可以通过instanceof来判断,它不能检测基本数据类型,它是用来判断一个实例是否属于某种类型,使用它的方式可以用A
instanceof B ,如果A是B的实例,则返回true,否则返回flase。
然后还可以用constructor来判断,除了undefined和null之外,其它类型都可以通过constructor来判断,但是如果声明了一个构造函数,并且把它的原型指向改变了,这种情况下,constructor也不能准确的判断。
通过Object.prototype.toString,判断一个对象只属于某种内置类型,但是不能准确的判断一个实例是否属于某种类型。原因是因为实例对象可能会自定义toString方法,把这个方法给覆盖掉,我们可以通过函数.call( )方法,可以在任意值上调用这个方法,帮助我们判断这个值的类型。
4、介绍 js 有哪些内置对象?
一般我们经常用到的如全局变量值 NaN、undefined,全局函数如 parseInt()、parseFloat() 用来实例化对象的构 造函数如 Date、Object 等,还有提供数学计算的单体内置对象如 Math 对象。👇

《标准内置对象的分类》

5、javascript 创建对象的几种方式?
我们一般使用字面量的形式直接创建对象,但是这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码。但 js和一般的面向对象的语言不同,在 ES6 之前它没有类的概念。但是我们可以使用函数来进行模拟,从而产生出可复用的对象创建方式,我了解到的方式有这么几种:

(1)第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系。

(2)第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。执行构造函数首先会创建一个对象,然后将对象的原型指向构造函数的 prototype 属性,然后将执行上下文中的 this 指向这个对象,最后再执行整个函数,如果返回值不是对象,则返回新建的对象。因为 this 的值指向了新建的对象,因此我们可以使用 this 给对象赋值。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此我们可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建,因为在 js 中函数也是一个对象,因此如果对象属性中如果包含函数的话,那么每次我们都会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有的实例都可以通用的。

(3)第三种模式是原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此我们可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例。

(4)第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此我们可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,因为使用了两种不同的模式,所以对于代码的封装性不够好。

(5)第五种模式是动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。这一种方式很好地对上面的混合模式进行了封装。

(6)第六种模式是寄生构造函数模式,这一种模式和工厂模式的实现基本相同,我对这个模式的理解是,它主要是基于一个已有的类型,在实例化时对实例化的对象进行扩展。这样既不用修改原来的构造函数,也达到了扩展对象的目的。它的一个缺点和工厂模式一样,无法实现对象的识别。
1
2
3
4
5
6
7
8
9
10
11
6、js 获取原型的方法?
p.proto
p.constructor.prototype
Object.getPrototypeOf§
7、什么是闭包,为什么要用它?
说白了就是函数嵌套函数,内部函数能够访问外部函数的变量,且在外部被执行,就产生了闭包。

第一个用途:创建私有变量,避免全局变量的污染
第二个用途:可以使已经运行结束的函数中 的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收。
8、三种事件模型是什么?
事件 是用户操作网页时发生的交互动作或者网页本身的一些操作,现代浏览器一共有三种事件模型。

DOM0级模型:这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过js属性来指定监听函数。这种方式是所有浏览器都兼容的。
IE 事件模型:在该事件模型中,一次事件共有两个过程,事件处理阶段,和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。这种模型通过 attachEvent来添加监听函数,可以添加多个监听函数,会按顺序依次执行。
DOM2 级事件模型:在该事件模型中,一次事件共有三个过程,第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE事件模型的两个阶段相同。这种事件模型,事件绑定的函数是 addEventListener,其中第三个参数可以指定事件是否在捕获阶段执行。

9、哪些操作会造成内存泄漏?
1.意外的全局变量
2.被遗忘的计时器或回调函数
3.脱离 DOM 的引用
4.闭包
第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
第二种情况是我们设置了setInterval定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
第三种情况是我们获取一个DOM元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回收。
第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。
10、简述javascript中this的指向?
第一准则是:this永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。

普通的函数调用,函数被谁调用,this就是谁。
构造函数的话,如果不用new操作符而直接调用,那即this指向window。用new操作符生成对象实例后,this就指向了新生成的对象。
匿名函数或不处于任何对象中的函数指向window 。
如果是call,apply等,指定的this是谁,就是谁。
11、解释一下原型链?
每一个函数有一个prototype的属性,当他作为构造函数的时候,它实例化出来的函数会有一个_proto_的属性,
当访问一个对象的某个属性或者方法的时候,会现在这个对象自身查找,如果没有找到,则会去它的_proto_隐式原型上查找,也就是它构造函数的prototype,如果还没有找到就会再在构造函数的prototype的_proto_中查找,知道找到或者返回undefined,这个链式查找的过程,我们称为原型链。

12、深拷贝、浅拷贝、以及如何实现?
深拷贝和浅拷贝都是针对复杂类型来说的,深拷贝式是层层拷贝,浅拷贝是只拷贝一层。
浅拷贝:使用Object.assign 只拷贝地址,它是将数据中的所有数据引用下来,指向同一个存放地址,拷贝后的数据修改后,会影响到原数据中的对象数据。
深拷贝:JSON.parse(JSON.Stringify(…)),递归拷贝每一层对象是内容拷贝,将数据中的所有数据都拷贝下来,对拷贝后的数据进行修改,不会影响到原数据。
可 以 使 用 for in 、 扩 展 运 算 符 … 、递归等递归函数实现深拷贝
递归:递归就是一个函数调用其本身,通过栈来实现。每执行一个函数,就新建一个函数栈。

13、DOM事件流和事件委托?
DOM事件流分为三个阶段:

捕获阶段
目标阶段
冒泡阶段
捕获阶段:在事件冒泡的模型中,捕获阶段不会响应任何事件;
目标阶段:目标阶段就是指事件响应到触发事件的最底层元素上;
冒泡阶段:冒泡阶段就是事件的触发响应会从最底层目标一层层地向外到最外层(根节点),事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层
事件流描述的是从页面中接受事件的顺序,IE和网景推出了两个正好相反的概念,IE推出的是冒泡流,从下到上,网景则是事件捕获流,从上到下。
首先通过addEventListener方法给元素添加点击事件,前两个参数分别是点击事件的名称和执行的回调,第三个参数就是是否开启捕获,确定事件发生的阶段,默认是false,也就是冒泡流。

事件委托,一般来说,会把一个或一组元素的时间委托到它的父元素上或者更外层元素上,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。在一些场景下,可以让性能得到优化。
比如给所有的列表添加点击事件,如果采用冒泡流,那么我们需要给每个元素添加点击事件,而采用事件委托的话,只需要在ul上绑定一个事件即可。

14、ajax是什么?以及如何去创建它?
ajax就是用来实现客户端与服务器端的异步通信效果,实现页面的局部刷新,标准浏览器是通过XMLHttpRequest,IE浏览器则是通过ActiveXObject来实现异步通信的效果。

创建Ajax:
1、创建 XMLHttpRequest 对象,也就是创建一个异步调用对象
2、创建一个新的 HTTP 请求,并指定该请求的方法、URL 及验证信息
3、设置响应 HTTP 请求状态变化的函数
4、发送 HTTP 请求
5、获取异步调用返回的数据
6、使用 JS和 DOM 实现局部刷新

15、什么是跨域?jsonp的原理?以及怎么实现?
跨域:是浏览器对js实施的安全限制。是指浏览器不能执行其他网站的脚本。是由浏览器的同源策略造成的,jsonp的原理就是动态的创建script标签,再去请求一个带参的网址来实现跨域,只能用get请求。

有三种方法解决跨域:

1、jsonp:利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,经过处理,返回callback函数调用的形式,callback中的参数就是json。

2、通过proxy代理:在vue 中主要是通过vue 脚手架中的config 中的index 文件来配置,有个 proxyTable 来配置跨域。

3、CORS(全称叫跨域资源共享):是后台工程师设置后端代码来实现前端跨域请求。

16、防抖和节流
防抖:事件被调用后,在执行之前无论被调用多少次都会从头开始计时。

节流:不管事件被调用多少次,总是按规定时间间隔执行。

代码实现:

//防抖
function debounce(fn, time) {
var timer;
return function() {
if (timer) {
clearTimeout(timer)
timer = null;
}
timer = setTimeout(() => {
clearTimeout(timer)
timer = null;
fn();
}, time);
}
}

//节流
function throttle(fn, time) {
var timer;
return function() {
if (timer) return;
timer = setTimeout(() => {
clearTimeout(timer)
timer = null;
fn();
}, time);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
17、同步和异步的区别,分别列举一个同步和异步的例子?
同步会阻塞代码,但是异步不会, alert是同步 setTimeout是异步

关于setTimeout的笔试题

console.log(1);
setTimeout(function() {
console.log(2);
}, 0);
console.log(3);
setTimeout(function() {
console.log(4);
}, 1000);
console.log(5);

// 输出结果:1,3,5,2,4
1
2
3
4
5
6
7
8
9
10
11
前端使用异步的场景

定时任务:setTimeout,setInterval
网络请求:ajax请求,动态img加载
事件绑定
18、描述new一个对象的过程?
创建一个新对象
this指向这个新对象
执行代码给this赋值
return this
function Foo(name) {
this.name = name;
// return this; // 本身会执行这一步
}

var f = new Foo(‘shiyanping’);

1
2
3
4
5
6
7
19、全局函数eval()有什么作用?
eval()只有一个参数,如果传入的参数不是字符串,它直接返回这个参数。如果参数是字符串,它会把字符串当成javascript代码进行编译。如果编译失败则抛出一个语法错误(syntaxError)异常。如果编译成功,则开始执行这段代码,并返回字符串中的最后一个表达式或语句的值,如果最后一个表达式或语句没有值,则最终返回undefined。如果字符串抛出一个异常,这个异常将把该调用传递给eval()。

20、原生对象和宿主对象
原生对象是ECMAScript规定的对象,所有内置对象都是原生对象,比如Array、Date、RegExp等;
宿主对象是宿主环境比如浏览器规定的对象,用于完善是ECMAScript的执行环境,比如Document、Location、Navigator等。
21、get和post有什么区别?
都是HTTP协议中的请求方法。底层实现都是基于TCP/IP协议。

GET是通过明文发送数据请求,而POST是通过密文;
GET传输的数据量有限,因为url的长度有限,POST则不受限;
GET请求的参数只能是ASCII码,所以中文需要URL编码,而POST请求传参没有这个限制
GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http、header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
22、请解释一下变量声明提升?
通过var声明的变量会被提升至作用域的顶端。不仅仅是变量,函数声明也一样会被提升。当同一作用域内同时出现变量和函数声明提升时,变量仍然在函数前面。

23、请指出document.onload和document.ready两个事件的区别?
页面加载完成有两种事件,一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件),二是onload,指示页面包含图片等文件在内的所有元素都加载完成。

24、请解释JSONP的工作原理,以及它为什么不是真正的AJAX?
JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源。例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。
AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!

25、通过new创建一个对象的时候,构造函数内部有哪些改变?
function Person(){}
Person.prototype.friend = [];
Person.prototype.name = ‘’;
var a = new Person();
a.friend[0] = ‘杨爽’;
var b = new Person();
console.log(b.friend);//Array [ “杨爽” ]
1
2
3
4
5
6
7
创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
属性和方法被加入到 this 引用的对象中。
新创建的对象由 this 所引用,并且最后隐式的返回 this 。
26、如何防范CSRF攻击,XSS攻击?
XSS攻击的防范

1、HttpOnly 防止劫取 Cookie
2、输入检查-不要相信用户的所有输入
3、输出检查-存的时候转义或者编码
1
2
3
CSRF攻击的防范

1、验证码
2、Referer Check
3、添加token验证
1
2
3
27、箭头函数与普通函数的区别?
箭头函数是匿名函数,不能作为构造函数,不能使用new
箭头函数不绑定arguments,取而代之用rest参数…解决
箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
箭头函数通过call()或apply()方法调用一个函数时,只传入了一个参数,对 this 并没有影响。
箭头函数没有原型属性
28、说一下js继承?
点击进入:JavaScript原型链与继承

29、JS 中的主要有哪几类错误
JS有三类的错误:

加载时错误:加载web页面时出现的错误(如语法错误)称为加载时错误,它会动态生成错误。

运行时错误:由于滥用HTML语言中的命令而导致的错误。

逻辑错误:这些错误是由于对具有不同操作的函数执行了错误的逻辑而导致的

30、JS中如何将页面重定向到另一个页面?
使用 location.href:window.location.href =“https://www.onlineinterviewquestions.com/”
使用 location.replace: window.location.replace(" https://www.onlineinterviewquestions.com/;");
31、JS中的Array.splice()和Array.slice()方法有什么区别?
slice和splice虽然都是对于数组对象进行截取,但是二者还是存在明显区别,函数参数上slice和splice第一个参数都是截取开始位置,slice第二个参数是截取的结束位置(不包含),而splice第二个参数(表示这个从开始位置截取的长度),slice不会对原数组产生变化,而splice会直接剔除原数组中的截取数据!

32、undefined,null 和 undeclared 有什么区别?
null表示"没有对象",即该处不应该有值,转为数值时为0。典型用法是:

作为函数的参数,表示该函数的参数不是对象。

作为对象原型链的终点。

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义,转为数值时为NaN。典型用法是:

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

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

对象没有赋值的属性,该属性的值为undefined。

函数没有返回值时,默认返回undefined。

undeclared:js语法错误,没有申明直接使用,js无法找到对应的上下文。

33、JS中的高阶函数?
高阶函数是JS函数式编程的最佳特性。它是以函数为参数并返回函数作为结果的函数。一些内置的高阶函数是map、filter、reduce 等等。

34、如何区分声明函数和表达式函数?
// 声明函数
function hello() {
return “HELLO”
}
// 表达式函数
var h1 = function hello() {
return “HELLO”
}
1
2
3
4
5
6
7
8
两个函数将在不同的时期定义。在解析期间定义声明,在运行时定义表达式;因此,如果我们控制台打印 h1,它将显示HELLO。

35、JS中的“严格”模式是什么以及如何启用?
严格模式是在代码中引入更好的错误检查的一种方法。

当使用严格模式时,不能使用隐式声明的变量,或为只读属性赋值,或向不可扩展的对象添加属性。
可以通过在文件,程序或函数的开头添加“use strict”来启用严格模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值