前端JavaScript基础面试题(每天更新两道)

40 篇文章 1 订阅
39 篇文章 5 订阅

1.介绍JavaScript的基本数据类型

  • 一共是八种:基本类型(原始):String、Number 、Boolean 、null 、undefined
    、bigint(谷歌版本中出现,有些地方并不承认)、symbol ;
    引用类型:Object
    object:是所有对象的父对象,像Array、Date、Function等都是其子对象.

2.JavaScript有几种类型的值,内存图是什么样的?

上面的数据类型这里还涉及到的一个问题存储,栈是先进后出,而堆是优先队列,按优先级来排序,二叉树就是堆的一个实现

  • 基本数据类型存储在栈中,因为其所占内存小,使用频繁、大小固定,所以存储在栈中。
  • 引用类型存储在堆中(包括其子对象),因为其占据空间大,且大小不固定,所以放在堆中,如果放在栈中则会影响程序运行性能,所以会在栈中存放引用类型的一个指针,其指针指向堆中概实体的起始地址

3.堆和栈的区别

栈:先进后出,由编译器自动分配释放,存放函数的参数值,局部变量等。
堆:一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放

4.如何判断数据类型

1.typeof:不能判断 数组和null,可以判断的类型有:String、Number 、Boolean 、undefined 、Function(基本类型中除去symbol和null)
2.将其他类型转换为字符串类型
1)toString(): 将Number、Boolean、 Object、String 类型转换为字符串
2)toLocaleString ( ):将数组转换为字符串
3.检测数组类型的方法
1)instanceof 操作符

  let arr1=[1,2,3]
  alert(arr1 instanceof Array)    //true

2)对象的constructor 属性

console.log(arr1.construtor === Array)  //true

3)ES6新增方法:Array.isArray()

console.log(Array.isArray(arr1))

5.JavaScript实现继承的六种方式

1.原型链
利用原型让一个引用类型继承另一个引用类型的属性和方法

function SuperType() {
this .property = true ;
}
SuperType.prototype.getSuperValue = function () {
return this .property;
}
function subType() {
this .property = false ;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this .property;
}
var instance = new SubType();
console.log(instance.getSuperValue()); //true

2.借用构造函数法(又叫经典继承):借用父类的构造函数
在子类型构造函数的内部调用超类构造函数,使用call() 和apply() 方法可以在新创建的对象上执行构造函数
(关于call()和apply()不懂的小伙伴可以看我的“透彻看懂apply()和call()方法,以及一些妙用”这篇文章,应该会理解很透彻)

 function SuperType() {
this .colors = [ "red" , "blue" , "green" ];
}
function SubType() {
SuperType.call( this ); //继承了SuperType
}
var instance1 = new SubType();
instance1.colors.push( "black" );
console.log(instance1.colors); //"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors); //"red","blue","green"

3.组合继承(最经常使用)
function SuperType(name) {
this .name = name;
this .colors = [ “red” , “blue” , “green” ];
}
SuperType.prototype.sayName = function () {
console.log( this .name);
}
function SubType(name, age) {
SuperType.call( this ,name); //继承属性
this .age = age;
}
//继承方法
SubType.prototype = new SuperType();
Subtype.prototype.constructor = Subtype;
Subtype.prototype.sayAge = function () {
console.log( this .age);
}
var instance1 = new SubType( “EvanChen” ,18);
instance1.colors.push( “black” );
consol.log(instance1.colors); //“red”,“blue”,“green”,“black”
instance1.sayName(); //“EvanChen”
instance1.sayAge(); //18
4.原型式继承
借助原型可以基于已有的对象创建新对象,同时还不必须因此创建自定义的类型
5.寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。
6.寄生组合式继承
借用函数来继承属性,通过原型链的混成形式来继承方法

6.JavaScript创建对象的四种方法:

1.工厂方法
2.构造函数方法
3.原型方法
4.组合使用构造函数和原型方法

7.JavaScript的作用域链

域链的原理和原型链很类似,如果这个变量在自己的作用域没有,那么它会寻找父级,直到最顶层。并且js没有块级作用域,要想形成块级作用域,可通过闭包,立即执行的形式实现。
(如果想要理解的更加深入,看我的“作用域、作用域链、闭包的面试”)

8.谈谈对this的理解

它默认指向的是window对象,这个window可以忽略不写,比如 this.alert() <=> window.alert()<=> alert();
这里可以分为全局环境和局部环境:
1.全局环境:全局环境中this指向始终为window对象
2.局部环境
1)在局部环境下直接调用this,那么它指向的就是window对象
2)对象函数调用,this总是指向函数的直接调用者
3)如果有new 关键字this指向new出来的那个对象
4)用call() 和apply()可以改变this的指向
这两个方法在第五条第二种方法有提到,我也有文章对这两种方法进行了详解,建议看一看加深印象和理解

9.eval是做什么的?

这个函数的功能是吧对应的字符串解析成js代并运行,应该避免使用这个,因为它既不安全还非常消耗性能。(它需要一次执行成js语句,一次执行)

10.什么是window对象?什么事document对象?

window对象代表浏览器中打开的一个窗口
document对象代表整个html文档。
实际上,document对象是window对象的一个属性

11.null 和undefined 的区别

  • 对一个变量声明了没有赋值,那么调用时就会出现undefined,表示声明的变量未初始化;
 let  a ; 
   console.log(a)
  • 那么什么时候出现null呢,一般这个是我们主动赋值,就是不知道是什么值,就先赋一个null,表示空对象不占什么空间,存放了一个空指针,这个只能主动去赋,一个变量值在任何情况下它的值都不会主动是null
  let obj=document.getElementById("id")   
  console.log(obj);

null在转换为数值时为0,undefined转换为数值为NAN

typeof(null) ;    //object
typeof(undefined);    //undefined

12.什么是闭包?为什么要用它

在一个函数内部,如果对外部函数的变量进行引用,那么这个内部函数就是闭包,简单点说闭包就是一个函数,只不过位于一个函数的内部而已。内部函数可以引用外部函数的变量,外部变量不会被垃圾回收机制回收。
闭包的原理是作用域链,所以闭包访问的上级作用域的变量是个对象,其值是运算结果的最后一个值
优点:避免全局变量污染
缺点:容易造成内存泄漏,造成内存占用增加
由于其值是运算结果的最后一个值,但有的时候我们想要的并不是这样的结果,比如最经典的打印一个循环的问题
var data = [];

 
for (var i = 0; i < 3; i++) {
  data[i] = function () {
    console.log(i);
  };
}
 
data[0]();	// 3
data[1]();	// 3
data[2]();	// 3

解决这个问题的方法有三个:立即执行函数、使用es6的let,返回一个匿名函数赋值。
这里对这三个方法就不进行展开说了,有兴趣可以看一下“作用域、作用域链、闭包的面试问题”这篇文章

13.AJAX 的使用

首先AJAX就是可以在不重新加载整个网页的情况下,对网页进行部分更新。
异步请求:发送请求后,并不会等待相应结果,而是会继续向下执行,所以必须在ajax监听的回调函数中,才能保证获取响应数据。
创建AJAX的过程:
1)创建XMLHttpRequest对象(异步调用对象)

var xhr=new XMLHttpRequest();

2)创建新的Http请求(方法、URL、是否异步)
xhr.open(‘get’,‘example.php’,false)
3)设置响应Http请求状态变化的函数
4)发送http请求
5)获取异步调用返回的函数

14.JavaScript代码中的“use strict”是什么意思?使用它区别是什么?

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

  • 消除js不合理,不严谨的地方,减少怪异行为;
  • 消除代码运行不安全的地方
  • 提高编译器的效率,添加运行的速度
  • 为未来的js新版本做铺垫
    比如在严格模式下:不允许使用with,不允许给未声明的变量赋值;删除参数名,函数会报错,函数参数名重复会报错
    更多详细的大家有兴趣可以看一下MDN 上对 JS 严格模式 的介绍

15.如何判断一个对象是否属于某个类?

使用instanceof

16.new 操作符具体干了啥

创建一个空对象,并且this 变量引用该对象,同时还继承了该函数的原型。
属性和方法都被加入到this 引用的对象中
被创建的对象由this 所引用,并且最后隐式的返回this

17.对JSON 的了解?

JSON对象通过 “{}”来标识,一个{}代表一个对象,比如{“Aewald”:“123”},对象的值是键值对的形式(key:value)。 JSON是js 的一个严格的子集,一种轻量级的数据交换格式,类似于xml。数据格式简单,易于读写,占用带宽小。
两个函数
1.JSON.parse(str): 解析JSON字符串,把JSON字符串变成JavaScript 值或者对象
2.JSON.stringify(obj): 将一个JavaScript 值(对象或数组)转换为一个JSON字符串

18.哪些操作会造成内存泄漏?

全局变量、闭包、DOM清空或删除时、时间未清除,子元素存在引用。

19.Js 延迟加载的方式有哪些?

Js 延迟加载有助于提高页面的加载速度。
方法有:defer、async、动态创建DOM方式(用的最多)、按需异步载入JS(把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度)、使用setTimeout延迟方法

defer:延迟脚本。立即下载,但是延迟执行(延迟到整个页面都解析完毕后再运行),按照脚本出现的先后顺序执行
async:异步脚本下载完立即执行,但不保证按照脚本出现的先后顺序执行。
async和defer一样,都不会阻塞其他资源下载,所以不会影响页面的加载。

20.同步和异步的区别?

同步的概念在操作系统中是:不同进程协同完成某项工作而先后次序调整,同步强调的是顺序性,而异步不讲顺序性。
同步:浏览器访问服务器,用户刷新,重新发送请求页面,等请求完,页面刷新,新内容出现,用户看到新内容进行下一步操作
异步:浏览器访问服务器请求,用户正常工作,浏览器在后端发送请求,等请求完,用户不需要刷新页面,新内容也会出现。

21.requireJS的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何缓存的?)

核心是js 的加载模块,通过正则表达式匹配模块以及模块的依赖关系,保证文件加载的先后顺序,根据文件的路径对加载过的文件进行了缓存。
特点是:异步加载模块、按照依赖顺序加载、依赖模块前置

22.AJAX请求的页面历史记录状态问题?

通过location.hash 记录状态,让浏览器记录AJAX 请求时页面状态的变化
通过HTML5的history.pushstate,来实现浏览器地址栏的无刷新改变

23.JavaScript 中,执行时对象查找时,永远不会去查找原型的函数?

Object.hasOwnProperty(proName):是用来判断一个对象是否有你给出名称的属性
该方法无法检查该对象的原型链中是否有该属性,只能判断是否存在于对象本身

24.什么是跨域问题,如何解决跨域问题?

在解释什么是跨域问题之前,先解释一下什么是同源策略?
同源策略就是用来限制一个源加载的文档或脚本与另一个源的资源进行交互,那怎么判断是否同源呢?
如果协议、端口和主机对于两个页面是相同的,则两个页面具有相同的源,也就是同源(满足前面三个条件相同)
对于一个网址来说:https://news.company.com/dir/distindex.html
这里的协议就是https,端口是80(默认的端口号是80,不是的话会写在com 后面,比如com:81),主机对应部分就是com前的。
如果这三个有一个不相同,即为跨域访问,接下来就说几种跨域解决方案
jsonp跨域、
1.document.domain方法: 这种方法只能解决主域相同的跨域问题
页面 http://www.example.com/a.html ,它里面有一个iframe,这个iframe的源是 http://example.com/b.html ,很显然它们是不同源的,所以我们无法在父页面中操控子页面的内容。

  <!-- b.html -->
<script>
document.domain = 'example.com';
</script>
<!-- a.html -->
<script>
document.domain = 'example.com';
var iframe = document.getElementById('iframe').contentWindow.document;

//后面就可以操作iframe里的内容了...
</script>

所以我们只要将两个页面的document.domain设置成一致就可以了,需要注意的是document.domain的设置是有限的,我们只能把document.domain设置成自身或更高一级的父域。

2.window.name方法
window对象有name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
在一个页面 example.com/a.html 中,我们想获取 data.com/data.html 中的数据,以下是解决方案:

	 <!-- data.html -->
<script>
window.name = 'data'; //这是就是我们需要通信的数据
</script>
<!-- a.html -->
<html>
<head>
<script>
    function getData () {
        var iframe = document.getElementById('iframe');
        iframe.src = 'example.com/b.html'; // 这里让iframe与父页面同源
        
        iframe.onload = function () {
            var data = iframe.contentWindow.name; //在这里我们得到了跨域页面中传来的数据
        };
    }
</script>
</head>
<body>
</body>
</html>

3.JSONP方法:
JSONP是JSON的一种使用模式,基本原理如下:

<!-- a.html -->
<script>
    function dealData (data) {
        console.log(data);
    }
</script>

<script src='http://example.com/data.php?callback=dealData'></script>

<?php
    $callback = $_GET['callback'];
    $data = 'data';
    echo $callback.'('.json_encode($data).')';
?>

这时候在 a.html 中我们得到了一条 js的执行语句,dealData(‘data’),从而实现跨域的目的
所以JSONP的原理就是利用引用script不限制源的特点,把处理函数名作为参数传入,然后返回执行语句,仔细阅读以上代码就可以明白了。

25.页面编码和被请求的资源编码如果不一致如何处理?

若请求的资源编码,如外引js 文件编码与页面编码不同。可根据外引资源编码方式定义为 charset=“utf-8” 或 “gbk”
比如:http://www.yyy.com/a.html 中嵌入了一个 http://www.xxx.com/test.js
a.html 的编码是gbk 或gb2312 的,而引入的js编码为utf-8的,那就需要在引入的时候

26.模块化开发怎么做?

模块化开发值得是在解决某一个复杂问题或者一系列问题时,依照一种分类的思维把问题进行系统化的分解。
模块化是将一种复杂系统分解为代码结构更合理,可维护性更高的可管理模块方式。对于软件行业:系统被分解为一组高内聚、低耦合的模块。
定义等装的模块,定义新模块对其他模块的依赖,可对其他模块的引入支持。
在JavaScript中出现了一些非传统模块开发方式的规范。common.js 的模块规范,AMD,CMD 等
AMD是异步模块定义,所有的模块将被异步加载,模块加载不影响后边语句的运行。

27.call()和apply()

这两个方法的作用相同,把特定的函数当做一个方法绑定到指定的对象上进行调用。常用于用于改变this的指向,也用这两个来实现函数的继承。
他们的区别在于接受的参数不同,call用数值的方式进行传参,apply用于数组的方式进行传参。
其中apply可根据其用数组的方式进行传参而用来比较数组的最大值,最小值,以及将一个数组添加到另一个数组的尾部

28.document.write()和innerHTML的区别

document.write()只能重绘整个页面,innerHTML可以重绘页面的一部分

29.回流与重绘

回流:当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变需要重新构建,这就称为回流。
每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。
完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称之为重绘

30.数组对象有哪些原生方法,列举一下

push,pop,shift,unshift,contact,reverse,sort,splice,join,slice,toLocaleString,indexOf,lastIndexOf,reduce,map,filter,every,some,forEach
⚠️:slice是对数组进行部分截取,并返回新数组;
splice会改变原来数组,根据传参的不同,进行增删改查
与此相似的还有一个split方法,将字符串根据特定的字符分割成数组

31.响应事件

onclick:鼠标点击某个对象
onfouse:获取焦点
onblur:失去焦点
onmousedown:鼠标被按下

32.attribute 和property的区别?

attribute是dom元素在文档中作为html标签拥有的属性
property是dom元素在js中作为对象拥有的属性
所以,对于html的标准属性来说,attribute 和 property是同步的,是会自动更新的。但对于自定义属性,他们不同步。

33.如何删除一个cookie?

将cookie的失效时间设置为过去时间
将系统时间设置为当前时间往前一点时间

34.什么是事件代理(事件委托)?

由于事件在冒泡阶段会向上传播到父节点,因此可以把子节点的监听函数定义到父节点上,由父节点的监听函数统一处理多个子节点的事件。这种方法就叫做事件的代理。
优点:减少年内存消耗,提高性能,动态绑定事件

35.http 301 和302 的区别

301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,
区别在于301 代表永久性重定向,302是暂时性

36.es6新增的for …of

1.优点:最简洁、最直接的遍历数组元素的语法,避开了for-in循环的缺陷,与forEach不同的时候,他可以正确响应break、continue、return语句
2.不仅支持遍历数组,还支持大多数类数组对象,字符串,支持Map和Set对象遍历,不支持普通对象(可迭代对象只能遍历)
3.对于对象来说,如果是类数组对象,可以用Array.from转成数组,如果不是非类数组对象,添加一个[Symbol.iterator]属性,并指向一个迭代器即可

37.谈一谈浏览器的缓存机制

1.什么是浏览器缓存机制:
浏览器的缓存机制就是把一个请求过的web资源(例如html页面,图片,js,数据等)拷贝一份副本存储在浏览器中,缓存会根据进来的请求保存输出内容的副本,当下一个请求到来的时候,如果是相同的url,缓存会根据缓存机制决定是否直接使用副本响应访问请求,还是向资源服务器再次发送请求。
2.浏览器缓存机制的好处
减少网络带宽产生较小的流量,减轻服务器的压力,渲染缓存的页面,减少了对服务器的访问,提高了响应页面速度,用户再次打开不用等待太长时间。
3.缓存的规则
缓存的规则是根据http协议和html标签中的meta;从两个维度,新鲜度和校验度去判断浏览器是否应该使用缓存页面,还是加载新的页面。新鲜度指的就是http协议头上有没有完整的过期时间,是不是已经使用过缓存页面了,那在下一个会话中就已经检查过了,校验度就是从服务器返回的 控制头中会带有资源的标签,如果下次访问的时候,这个标签相同的那就使用缓存页面,如果不相同那证明可能被修改或过期,那就重新发送请求。

38.devtool有哪些选项,分别什么作用?

选项有element, console, sources, network,performance等
1.element元素面板
最基本的使用就是快速定位到dom节点在网页的位置,或者dom节点在html网页中的位置,方便模块以及样式的调试,也能搜索
在html代码区域和css样式区可以直接双击编辑,会直接在页面显示
能够在Event Listeners中查看元素绑定的事件
2.Console
在控制台能显示浏览器的消息,在代码总console.log的内容会在这里看到
也能在这里进行一些简单代码的调试
3.Sources 这里是源代码面板
可以在每一行代码中设置断电调试代码
这里可以查看网页的源代码
4.Network
1.“Disable cache"控制是否缓存,防止更改样式而看不到效果
2.“Request Table”中可以显示可下载资源
3.filter可以过滤不同类型的资源,支持正则表达式过滤
4.在“name”点击一个request请求,会显示出request,response,cookie等信息
在这里也能查看到接口的调用情况
5.Application
查看缓存数据

39.localstorage sessionstorage cookie 有什么区别

1。存储期限不同:localstorage的期限是永久,所以需要手动清除;sessionstorage 仅在当前会话有效,窗口关闭后会清除;cookie一般默认是浏览器关闭失效,可以自己设置失效时间。
2.存储大小:cookie只适合保存很小的数据,一般不能超过4k,另外两个存储数据大小一般在5MB,并且这两个保存在客户端,不与服务端进行交互通信
3.作用域不同:sessionStorage在不同的浏览器窗口中不共享,即使是同一个页面,localStorage在所有的同源窗口中是共享的,cookie也是在所有同源的窗口中共享的

40.在地址栏里输入一个地址回车会发生什么事情?

1.解析url 2.缓存判断 3.DNS解析 4.获取MAC地址 5.TCP三次握手 6.HTTPS握手 7.返回数据 8.页面渲染 9.TCP四次挥手
1)TCP三次握手:首先客户端向服务器发送一个 SYN 连接请求报文段和一个随机序号,服务端接收到请求后向客户端发送一个 SYN ACK报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收服务器的确认应答后,进入连接建立的状态,同时向服务器也发送一个ACK 确认报文段,服务器端接收到确认后,也进入连接建立状态,此时双方的连接就建立起来了。

41.浏览器的渲染机制

1.解析HTML(HTML Parser)2.构建DOM树(DOM Tree)3.构建渲染树(Render Tree)4.绘制渲染树(Painting)

42.宏队列和微队列

宏队列:用来保存待执行的宏任务(定时器、DOM回调、ajax回调)
微队列:用来保存待执行的微任务。(promise回调)
执行顺序:每次取出宏任务之前要先把微任务全部取出来放到栈中处理掉,再执行宏任务

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值