web前端面试题合集

web前端面试题合集1.线程和进程是什么?

欢迎大家来到IT世界,在知识的湖畔探索吧!

1.线程和进程是什么?举例说明

进程:cpu分配资源的最小单位(是能拥有资源和独立运行的最小单位)

线程:是cpu最小的调度单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

栗子:比如进程=火车,线程就是车厢

一个进程内有多个线程,执行过程是多条线程共同完成的,线程是进程的部分。

一个火车可以有多个车厢

每个进程都有独立的代码和数据空间,程序之间切换会产生较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。

【多列火车比多个车厢更耗资源】

【一辆火车上的乘客很难换到另外一辆火车,比如站点换乘,但是同一辆火车上乘客很容易从A车厢换到B车厢】

同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

【一辆火车上不同车厢的人可以共用各节车厢的洗手间,但是不是火车上的乘客无法使用别的火车上的洗手间】

为什么js是单线程

JS是单线程的原因主要和JS的用途有关,JS主要实现浏览器与用户的交互,以及操作DOM。

如果JS被设计为多线程,如果一个线程要修改一个DOM元素,另一个线程要删除这个DOM元素,这时浏览器就不知道该怎么办,为了避免复杂的情况产生,所以JS是单线程的。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

2. js中的基础数据类型有哪几种? 了解包装对象吗?

答:六种,string, number, boolean, undefiend, null, symbol

基础数据类型临时创建的临时对象,称为包装对象。其中 number、boolean 和 string 有包装对象,代码运行的过程中会找到对应的包装对象,然后包装对象把属性和方法给了基本类型,然后包装对象被系统进行销毁。

3.对内存泄漏的了解

1. 理解

– 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题

– 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。

2. 生命周期

1. 分配期

分配所需要的内存,在js中,是自动分配的

2. 使用期

使用分配的内存,就是读写变量或者对象的属性值

3. 释放期

不需要时将该内存释放,js会自动释放(除了闭包和一些bug以外)

内存泄漏就是出现在这个时期,内存没有被释放导致的

3. 可能出现内存泄漏的原因

1. 意外的全局变量

2. DOM元素清空时,还存在引用

3. 闭包

4. 遗忘的定时器

如何优化内存泄漏?

全局变量先声明在使用

避免过多使用闭包。

注意清除定时器和事件监听器。

4.js中数组合并的方法

js 数组合并

let arr1 = [‘温情’, ‘刘聪’]

let arr2 = [‘杨和苏’, ‘邓紫棋’]

let arr3 = [‘周延’]

1. arr1.concat(arr2, ······)

es5 Array.concat() 合并两个数组, 返回新数组,不会改变原数组

arr = arr1.concat(arr2, arr3);

console.log(arr); // [“温情”, “刘聪”, “杨和苏”, “邓紫棋”, “周延”]

2. […arr1, …arr2,······]

es6 展开运算符(…)

arr = […arr1, …arr2, …arr3];

console.log(arr); // [“温情”, “刘聪”, “杨和苏”, “邓紫棋”, “周延”]

3. push(…arr)

push 结合 …[] 来实现, 会更改原数组

arr1.push(…arr2, …arr3)

console.log(arr1); // [“温情”, “刘聪”, “杨和苏”, “邓紫棋”, “周延”

适合两个数组,不适合多个数组的方法

1. for + push

for(let i in arr2) {

arr1.push(arr2[i])

}

console.log(arr1); // [“温情”, “刘聪”, “杨和苏”, “邓紫棋”]

2. arr1.push.apply(arr1, arr2)

arr1.push.apply(arr1, arr2)

console.log(arr1); // [“温情”, “刘聪”, “杨和苏”, “邓紫棋”]

5.合并对象的方法

Object.assign()

es6 Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。

let obj1 = {name: ‘温情’}

let obj2 = {age: ’22’}

const newObj = Object.assign({}, obj1, obj2);

console.log(newObj); // {name: “温情”, age: “22”}

!注意! Object.assign()实行的是浅拷贝,也就是说如果源对象的属性是一个对象,那么目标对象得到的是这个对象的引用

let obj1 = {name: {chinese: ‘杨和苏’, english: ‘keyNG’}}

const newObj = Object.assign({}, obj1);

console.log(newObj); // name: {chinese: “杨和苏”, english: “keyNG”}

obj1.name.english = ‘pig’;

console.log(newObj); // name: {chinese: “杨和苏”, english: “pig”}

6.什么是作用域,什么是作用域链?

规定变量和函数的可使用范围称为作用域

查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作用域链。

7.JS如何实现异步编程(5种)?

1)回调函数(callback)

优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)

缺点:回调地狱,每个任务只能指定一个回调函数,不能 return.

2)事件监听。这种思路是说异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。比如一个我们注册一个按钮的点击事件或者注册一个自定义事件,然后通过点击或者trigger的方式触发这个事件。

3)Promise

4)Generator

5)生成器 async/await,是ES7提供的一种解决方案。

8.js中的堆内存与栈内存

在js引擎中对变量的存储主要有两种位置,堆内存和栈内存。

和java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null,**以及对象变量的指针,这时候栈内存给人的感觉就像一个线性排列的空间,每个小单元大小基本相等。

而堆内存主要负责像对象Object这种变量类型的存储,如下图

栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存存储的对象类型数据对于大小这方面,一般都是未知的。个人认为,这也是为什么null作为一个object类型的变量却存储在栈内存中的原因。

因此当我们定义一个const对象的时候,我们说的常量其实是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。而对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变。

既然知道了const在内存中的存储,那么const、let定义的变量不能二次定义的流程也就比较容易猜出来了,每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误。

说到这里,有一个十分很容易忽略的点,之前也是自己一直没有注意的就是,使用new关键字初始化的之后是不存储在栈内存中的。为什么呢?new大家都知道,根据构造函数生成新实例,这个时候生成的是对象,而不是基本类型。再看一个例子

我们可以看到new一个String,出来的是对象,而直接字面量赋值和工厂模式出来的都是字符串。但是根据我们上面的分析大小相对固定可预期的即便是对象也可以存储在栈内存的,比如null,为啥这个不是呢?再继续看

很明显,如果a,b是存储在栈内存中的话,两者应该是明显相等的,就像null === null是true一样,但结果两者并不相等,说明两者都是存储在堆内存中的,指针指向不一致。

9.如何去判断js数据类型?

首先我们可以用typeof去判断,typeof只能判断基本数据类型,对于引用数据类型,- -律返回object,在js中,数组是一种特殊的对象类型, 因此typeof-个数组,返回的是object.

还可以通过instanceof来判断,它不能检测基本数据类型,它是用来判断个实例是否属于某种类型, 使用它的方式可以用Ainstanceof B,如果A是B的实例,则返回true,否则返回flase。

然后还可以用constructor来判断,除了undefined和nul1之外,其它类型都可以通过constructor来判断,

但是如果声明了一个构造函数,并且把它的原型指向改变了,这种情况下,constructor也不能准确的判断。

通过0bject . prototype . toString,判断一个对象 只属于某种内置类型,但是不能准确的判断一个实例是否属于某种类型。

原因是因为实例对象可能会自定义toString方法,把这个方法给覆盖掉,我们可以通过函数. call( )方法,可以在任意值上调用这个方法,帮助我们判断这个值的类型。

10,怎么允许跨域(跨域解决办法)

A、JSONP

在页面上,js脚本,css样式文件,图片这三种资源是可以与页面本身不同源的。jsonp就利用了script标签进行跨域取得数据。

JSONP允许用户传递一个callback参数给服务器端,然后服务器端返回数据时会将这个callback参数作为函数名来包裹住JSON数据。这样客户端就可以随意定制自己的函数来自动处理返回的数据了。

JSONP只能解决get请求,不能解决post请求。

<script>

function callback(data){

console.log(data);

}

</script>

<script src=”http://localhost:80/?callback=callback”></script>

使用ajax实现跨域:

<script src=”http://code.jquery.com/jquery-latest.js”></script>

$.ajax({

url:’http://localhost:80/?callback=callback’,

method:’get’,

dataType:’jsonp’, //=> 执行jsonp请求

success:(res) => {

console.log(res);

}

})

function callback(data){

console.log(data);

}

B、 CORS跨域资源共享:

浏览器会自动进行CORS通信,实现CORS通信的关键是后端。服务端设置Access-Control-Allow-Origin就可以开启CORS。该属性表示哪些域名跨域访问资源。

主要设置以下几个属性:

Access-Control-Allow-Origin//允许跨域的域名

Access-Control-Allow-Headers//允许的header类型

Access-Control-Allow-Methods//跨域允许的请求方式

C、Nginx反向代理

通过nginx配置一个代理服务器将客户机请求转发给内部网络上的目标服务器;并将服务器上返回的结果返回给客户端。

D、webpack (在vue.config.js文件中)中 配置webpack-dev-server

devServer: {

proxy: {

‘/api’: {

target: “http://39.98.123.211”,

changeOrigin: true, //是否跨域

},

},

},

11.怎么让对象的一个属性不可被改变

(1) Object.defineProperty()

可以使用Object.defineProperty()方法,让对象的某一个属性不可变,把对象某一属性的writable和configurable设置为false.

let obj = {a:1,b:2};

Object.defineProperty(obj,’c’,{

value:100000,

writable:false,//当该属性的 writable 键值为 true 时,属性的值才能被赋值操作修改

configurable:false//当为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。

})

obj.c = 282031283

console.log(obj.c)//100000

2)object.preventExtensions()

让对象不能添加新属性,可以使用object.preventExtensions()方法。(但是可以修改属性值)

let obj = {a:1,b:2};

Object.preventExtensions(obj);

obj.c = 1000;

console.log(obj)

12.浏览器所用的内核

IE:Trident内核

Chrome:以前是webkit内核,现在是Blink内核

Firefox:Gecko(/ˈɡekoʊ/)内核

Safari:webkit内核

Opera:最初使用的是presto内核,后来加入谷歌大军,从webkit内核又变成了Blink内核

360,猎豹浏览器:IE+chrome双内核

13、判断一个函数是普通函数还是构造函数(补全funcA(){})

构造函数中this指向new创建的实例。所以可通过在函数内部判断this是否为当前函数的实例进而判断当前函数是否作为构造函数。

function A(){

if(this instanceof A){

console.log(‘我是构造函数’)

}else{

console.log(‘我是普通函数’)

}

}

A();

new A();

14.JavaScript 中的提升是什么?

提升意味着所有的声明都被移动到作用域的顶部。这发生在代码运行之前。

对于函数,这意味着你可以从作用域中的任何位置调用它们,甚至在它们被定义之前。

hello(); // Prints “Hello world! ” even though the function is called “before” declaration

function hello(){

console.log(“Hello world! “);

}

对于变量,提升有点不同。它在作用域的顶部将 undefined 分配给它们。

例如,在定义变量之前调用它:

console.log(dog);//undefined

var dog = “Spot”;

结果是:

undefined

这可能令人惊讶,因为你可能预计它会导致错误。

用var声明一个函数或变量,无论你在哪里声明它,它总是被移动到作用域的顶部。

15、js有哪些内置对象? 

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

其他对象:Function、Arguments、Math、Date、RegExp、Error….

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/21769.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信