前端社招(一年经验)面经二

一、js实现冒泡排序

// 封装成函数
function bubble(arr){
    if(arr instanceof Array && arr.length > 1){
        //外层循环,控制趟数,每一次找到一个最大值
         for (var i = 0; i < arr.length - 1; i++) {
            // 内层循环,控制比较的次数,并且判断两个数的大小
            for (var j = 0; j < arr.length - 1 - i; j++) {
                // 如果前面的数大,放到后面(从小到大的冒泡排序)
                if (arr[j] > arr[j + 1]) {
                    var temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;  // 将执行完的结果返回就可以
    }
}

var arr = [3,5,1,2,9,8,4,5,3,4]; 
console.log(bubble(arr)); // [1, 2, 3, 3, 4, 4, 5, 5, 8, 9]

二、js定义变量有几种方式?有什么区别?

1.js定义变量的方式:var、let和const
2.var、let和const的区别:
①var声明的变量会挂载在window上,而let和const声明的变量不会

var a = 100;
console.log(a,window.a);    // 100 100

let b = 10;
console.log(b,window.b);    // 10 undefined

const c = 1;
console.log(c,window.c);    // 1 undefined

②var声明变量存在变量提升,let和const不存在变量提升

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
const c = 10;

③let和const声明形成块作用域,而var声明的变量作用域为函数作用域或全局作用域

if(1){
    var a = 100;
    let b = 10;
    const c = 1;
}
console.log(a); // 100
console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
 console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量

④同一作用域下let和const不能声明同名变量,而var可以

var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10

let a = 100;
let a = 10;
//  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。

⑤const一旦声明必须赋值,不能使用null占位;声明后不能再修改;如果声明的是复合类型数据,可以修改其属性

const a;//报错
const a = 100; //一旦声明必须赋值,不能使用null占位

const a = 100;
a = 10;//报错,声明后不能再修改

const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'},如果声明的是复合类型数据,可以修改其属性

⑥暂存死区

var a = 100;

if(1){
    a = 10;
    //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
    // 而这时,还未到声明时候,所以控制台Error:a is not defined
    let a = 1;
}

三、闭包?

  • 各种专业文献的闭包定义都非常抽象,我的理解是:闭包就是能够读取其他函数内部变量的函数。由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数”
  • 所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
  • 闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在父方法调用后被自动清除

闭包的使用场景:
①return一个函数

function a(){
    var m=3 ;
    function b(){
        console.log(m);
        console.log('string');
    };
    return b;
}
var result=a();
result();     //3   'string'

②函数作为参数

var a = '林一一'
function foo(){
    var a = 'foo'
    function fo(){
        console.log(a)
    }
    return fo
}

function f(p){
    var a = 'f'
    p()
}
f(foo())
/* 输出
*   foo
* 使用 return fo 返回回来,fo() 就是闭包,f(foo()) 执行的参数就是函数 fo,因为 fo() 中的 a 的上级作用域就是函数foo(),所以输出就是foo
/

所有回调函数都是闭包

window.name = '林一一'
setTimeout(function timeHandler(){
  console.log(window.name);
}, 100)

四、原型链?如果要给对象添加一个自定义方法属性/方法怎么实现?

1.原型
在这里插入图片描述

  • 每个对象都有_proto_属性,并且指向它的原型对象
  • 每个构造函数都有它的prototype原型对象
  • prototype原型对象里的constructor指向它的构造函数
  • new一个构造函数会形成它的实例对象

通过代码来看:

function Person(name,age){
     this.name=name;
     this.age=age;
}
 
var p1=new Person('小满',18);
var p2=new Person('大雪',20);
        
console.log(p1,p2)
console.log(Person.prototype);
console.log(p1.__proto__);
 
console.log(p1.__proto__===Person.prototype);
console.log(p2.__proto__===Person.prototype);
console.log(p1.__proto__===p2.__proto__);
 
console.log(p1.__proto__.constructor);
console.log(Person.prototype.constructor);

在这里插入图片描述
2.原型链

  • 概念:每个对象都可以有一个原型,这个原型还可以有它自己的原型,以此类推,形成一个原型链
  • 什么时候用:当我们查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去原型对象的原型对象里去寻找…这个操作就是被委托在整个原型链上。
  • 如果没有找到会一直找下去吗:原型链是有终点的,不会一直找下去。当Object.prototype.__proto__ === null时,查找结束,返回undefined。

3.利用prototype给对象添加一个自定义方法属性/方法

 Array.prototype.duplicator = function() {
 let s = this.concat(this);
 return s;
 }
 let t = [1,2,3,4,5].duplicator();
 console.log(t);// [1,2,3,4,5,1,2,3,4,5]

五、tcp三次握手?知道tcp长连接吗?抓过包吗?QQ发消息用的是什么协议?

1.三次握手
在这里插入图片描述

1)第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编(Synchronize
Sequence Numbers)。
2)第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
3)第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

拓展:四次挥手
在这里插入图片描述
1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

2.长连接与短连接
1)长连接:

  • client方与server方先建立连接,连接建立后不断开,然后再进行报文发送和接收。
  • 这种方式下由于通讯连接一直存在。此种方式常用于P2P通信。
  • 有些服务需要长时间连接到服务器,比如CMPP,一般需要自己做在线维持。

2)短连接:

  • Client方与server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。
  • 此方式常用于一点对多点通讯。C/S通信。
  • 比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。

3.抓过包,发现QQ主要使用的是UDP协议发送聊天消息

六、计算机网络结构?

计算机网络体系结构分为3种:OSI体系结构(七层),TCP/IP体系结构(四层),五层体系结构。

  • OSI体系结构: 概念清楚,理论也比较完整,但是它既复杂又不实用。
  • TCP/IP体系结构:TCP/IP是一个四层体系结构,得到了广泛的运用。
  • 五层体系结构:为了方便学习,折中OSI体系结构和TCP/IP体系结构,综合二者的优点,这样既简洁,又能将概念讲清楚。
    在这里插入图片描述
    在这里插入图片描述

七、HTTP协议了解吗?

1.简介:

  • HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
  • HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP使用面向连接的TCP作为传输层协议,HTTP本身无连接。
  • HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。

2.http和https区别
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全
HTTPS和HTTP的区别主要如下:
总的来说: HTTPS=SSL+HTTP
①https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
②http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
③http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。(这个只是默认端口不一样,实际上端口是可以改的)
④http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

3.http1.0 1.1 2.0的区别

(1)在http1.0中,当建立连接后,客户端发送一个请求,服务器端返回一个信息后就关闭连接,当浏览器下次请求的时候又要建立连接,显然这种不断建立连接的方式,会造成很多问题。
(2)在http1.1中,引入了持续连接的概念,通过这种连接,浏览器可以建立一个连接之后,发送请求并得到返回信息,然后继续发送请求再次等到返回信息,也就是说客户端可以连续发送多个请求,而不用等待每一个响应的到来。
(3)http2.0与http1.1相比,主要区别包括:

  • http2.0采用二进制格式而非文本格式
  • http2.0是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
  • http2.0使用报头压缩,降低了开销
  • http2.0让服务器可以将响应主动“推送”到客户端缓存中

4.http协议中有那些请求方式?

  • GET:用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器
  • POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式
  • PUT:传输文件,报文主体中包含文件内容,保存到对应URI位置。
  • DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
  • HEAD:获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效
  • OPTIONS:查询相应URI支持的HTTP方法。

拓展:增删改查
(增查改删)
(CRUD)
(create-retrieve-update-delete)
(POST-GET-PUT-DELETE)

5.http常见状态码

  • 200(成功)服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的 robots.txt 文件显示此状态码,则表示Googlebot 已成功检索到该文件。
  • 304(未修改)自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容
  • 400(错误请求)服务器不理解请求的语法。
  • 404(未找到)服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码。
  • 500(服务器内部错误)服务器遇到错误,无法完成请求

八、vue的生命周期?

Vue实例需要经过创建、初始化数据、编译模板、挂载DOM、渲染、更新、渲染、卸载等一系列过程,这个过程就是Vue的生命周期,Vue中提供的钩子函数有beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed

九、computed和methods的区别?

(1)首先最明显的不同就是调用的时候,methods要加上()
(2)我们可以使用 methods 来替代computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值;而使用methods ,在重新渲染的时候,函数总会重新调用执行

拓展1:watch
watch侦听器是侦听一个特定的值,当该值变化时执行特定的函数。例如分页组件中,我们可以监听当前页码,当页码变化时执行对应的获取数据的函数。

拓展2:什么情况下分别使用computed、watch、methods
(1)数据量大,需要缓存的时候用computed;每次确实需要重新加载,不需要缓存时用methods。
(2)尽量用computed计算属性来监视数据的变化,因为它本身就这个特性,用watch没有computed“自动”,手动设置使代码变复杂。
(3)虽然计算属性在大多数情况下是非常适合的,但是在有些情况下我们需要自定义一个watcher,在数据变化时来执行异步操作,这时watch是非常有用的。

十、栈和队列的区别?在js中有对应吗?数组方法有哪些?

1.栈:后进先出;队列:先进先出
2.(1)JS为数组提供了方法可以实现类似入栈出栈功能:入栈push()、 出栈pop()
在这里插入图片描述
(2)JS为数组提供了方法可以实现队列功能:入队unshift()、 出队pop()
在这里插入图片描述
3.数组方法:
1)Array.length
返回或设置一个数组中的元素个数
设置 length 属性的值来截断任何数组

2)Array.from()
对伪数组或可迭代对象(包括arguments Array,Map,Set,String…)转换成数组对象
语法 Array.from(arrayLike, mapFn, thisArg)

  • arrayLike:想要转换成数组的伪数组对象或可迭代对象。
  • mapFn (可选参数):如果指定了该参数,新数组中的每个元素会执行该回调函数。
  • thisArg (可选参数):可选参数,执行回调函数 mapFn 时 this对象。
  • 返回值:一个新的数组实例

3)Array.isArray()
用于确定传递的值是否是一个 Array

Array.isArray([]) => true;
Array.isArray({}) => false;

4)Array.of()

Array.of(7);       // [7] 
Array.of(1, 2, 3); // [1, 2, 3]

Array(7);          // [ , , , , , , ]
Array(1, 2, 3);    // [1, 2, 3]

5)concat()
用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

  var arr1 = ['a', 'b', 'c'];
  var arr2 = ['d', 'e', 'f'];
  var arr3 = ['f'];
  var arr4 = arr1.concat(arr2,arr3);
  // arr4 is a new array [ "a", "b", "c", "d", "e", "f" ]

6)forEach()
方法对数组的每个元素执行一次提供的函数

array.forEach(callback(currentValue, index, array){
    //do something
}, this)

7)indexOf()
返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1

let a = [2, 9, 7, 8, 9]; 
a.indexOf(2); // 0 
a.indexOf(6); // -1
a.indexOf(7); // 2
a.indexOf(8); // 3
a.indexOf(9); // 1
if (a.indexOf(3) === -1) {
  // 数组中不包含3
}

8)map()
创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果

9)pop()
从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度

let a = [1, 2, 3];
a.length; // 3
a.pop(); // 3
a.length; // 2

10)push()
将一个或多个元素添加到数组的末尾

11)toString()
返回一个字符串,表示指定的数组及其元素

12)unshift()
将一个或多个元素添加到数组的开头,并返回新数组的长度

13)reverse
方法将数组中元素的位置颠倒

14)shift()
从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度

15)slice
返回一个从开始到结束(不包括结束)选择的数组的一部分到一个新数组对象

16)some()
测试数组中的某些元素是否通过由提供的函数实现的测试。

const isBiggerThan10 = (element, index, array) => {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  
// false

[12, 5, 8, 1, 4].some(isBiggerThan10); 
// true

17)sort()
对数组的元素进行排序,并返回数组

18)splice()
通过删除现有元素和/或添加新元素来更改一个数组的内容

19)join()
将数组(或一个类数组对象)的所有元素连接到一个字符串中

let a = ['Wind', 'Rain', 'Fire'];
a.join(); 
// 默认为 ","
// 'Wind,Rain,Fire'

20)toLocaleString()
返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开

var number = 1337;
var date = new Date();
var myArr = [number, date, "foo"];
var str = myArr.toLocaleString(); 
console.log(str); 
// 输出 "1337,2017/8/13 下午8:32:24,foo"
// 假定运行在中文(zh-CN)环境,北京时区

21)includes()
用来判断一个数组是否包含一个指定的值,返回 true或 false

let a = [1, 2, 3];
a.includes(2); 
// true 
a.includes(4); 
// false

22)reduce()
累加器和数组中的每个元素(从左到右)应用一个函数

var total = [0, 1, 2, 3].reduce(function(sum, value) {
  return sum + value;
}, 0);
// total is 6

23)lastIndexOf()
返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找第一个出现位置的索引

24)copyWithin(target, start, end)
浅复制数组的一部分到同一数组中的另一个位置

25)every(callback)
方法测试数组的所有元素是否都通过了指定函数的测试

26)fill()
用一个固定值填充一个数组中从起始索引到终止索引内的全部元素

// arr.fill(value, start, end)
ar numbers = [1, 2, 3]
numbers.fill(1);
// results in [1, 1, 1]

27)filter()
创建一个新数组, 其包含通过所提供函数实现的测试的所有元素

var arr= [1,10,20,30]
var brr = arr.filter((item)=>{
    return item>10;
})
//[20,30]

28)find()
返回数组中满足提供的测试函数的第一个元素的值

function isBigEnough(element) {
return element >= 15;
}
[12, 5, 8, 130, 44].find(isBigEnough); // 130

29)findIndex()
返回数组中满足提供的测试函数的第一个元素的索引

function isBigEnough(element) {
  return element >= 15;
}
[12, 5, 8, 130, 44].findIndex(isBigEnough); 
//'3'

30)reduceRight()
接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值