其他分享
首页 > 其他分享> > 腾讯一面面经总结1(题+答案)

腾讯一面面经总结1(题+答案)

作者:互联网

1、块作用域

      JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。

     ECMAScript 6(简称ES6)中新增了块级作用域。

     块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

     var、let、const的区别:

     (1)var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问 ;

     (2)let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问 ;

     (3) const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改 ;

 

2、三次握手四次挥手:

      过程图解:

      

     三次握手:

     首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。

     四次挥手:

   【注意】中断连接端可以是Client端,也可以是Server端。

    假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。

     (下面图片是我之前看到做的笔记)

   【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
    因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

  【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

   (1) 为了保证主动关闭方最后发送的那个ACK报文段能够达到被动关闭方。这个ack报文段可能丢失,因而处在last-ack状态的被动关闭方收不到对已发送的FIN+ACK报文段的确认,被动关闭方超时会重传这个FIN+ACK报文段,客户机就能在2MSL时间内收到这个重传的报文段并重传一次确认,重新启动2MSL计时器,最后再进入closed状态。如果没有这个时间,那么就无法收到重传的FIN+ACK包,无法进入正常的CLOSED状态。

    (2) 防止“已失效的连接请求报文段”出现在本连接中。

 

3. 节流和防抖 (性能优化)

       防抖(debounce):一段时间内如果大量触发同一事件,只会执行一次函数。

         在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:

         a. 如果在200ms内没有再次触发滚动事件,那么就执行函数

         b. 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时

      节流(throttle):一段时间内如果大量触发同一事件,那么函数执行一次后,该函数在指定的时间期限内不再工作,直至过了这段时间才能再次执行。

    防抖将多次执行变为最后一次执行,节流将多次执行变成每隔一段时间内可执行一次!

 

4. js继承

    (1) 原型链继承

function Person(){
    this.name = 'xiaopao';
}

Person.prototype.getName = function(){
    console.log(this.name);
}

function Child(){
}

Child.prototype = new Person();
var child1 = new Child();
child1.getName(); // xiaopao

         缺点:

         a. 引用类型的属性被所有实例共享

         b. 在创建Child的实例时, 不能向Person传参

    (2) 借用构造函数继承(经典继承)-- apply 和 call

// 借用构造函数继承(经典继承)
function Person(){
    this.name = 'xiaopao';
    this.colors = ['red', 'blue', 'green'];
}

Person.prototype.getName = function(){
    console.log(this.name);
}

function Child(){
    Person.call(this);
}

var child1 = new Child();
var child2 = new Child();
child1.colors.push('yellow');
console.log(child1.name);
console.log(child1.colors); // ["red", "blue", "green", "yellow"]
console.log(child2.colors); // ["red", "blue", "green"]

        优点:

        a.避免了引用类型的属性被所有实例共享
        b.可以在Child中向Parent传参 

        缺点:

        a. 只是子类的实例,不是父类的实例
        b. 方法都在构造函数中定义,每次创建实例都会创建一遍方法

   (3) 组合继承  ---  组合 原型链继承 和 借用构造函数继承
        思路是:使用原型链实现对原型方法的继承,通过借用构造函数来实现对实例属性的继承

        function Parent(name){
            this.name = name;
            this.colors = ['red', 'blue', 'green'];
        }

        Parent.prototype.getName = function(){
            console.log(this.name);
        }

        function Child(name,age){
            Parent.call(this,name);// 第二次调用 Parent()
            this.age = age;
        }

        Child.prototype = new Parent(); // 第一次调用 Parent()

        var child1 = new Child('xiaopao',18);
        var child2 = new Child('lulu',19);
        child1.getName(); // xiaopao
        child2.getName(); // lulu
        console.log(child1.age); // 18
        console.log(child2.age); // 19
        child1.colors.push('yellow');
        console.log(child1.colors);  // ["red", "blue", "green", "yellow"]
        console.log(child2.colors); // ["red", "blue", "green"]
        console.log(child1 instanceof Child); // true
        console.log(child1 instanceof Parent); // true

         优点:融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式
         缺点:调用了两次父类构造函数,组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部)

 

5. 闭包

  「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包

       内部函数--即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。

function f1(){
    var n=999;

    function f2(){
        alert(n); // 999
    }
}

       函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

       闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

        它最大的用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

 

6. 原型和原型链

 

7. cookie

        cookie是储存在用户本地终端上的数据,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息,可以帮助我们实现记录用户个人信息的功能。

       Cookie是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。

 

8. webStorage

        使用HTML5可以在本地存储用户的浏览数据。早些时候,本地存储使用的是 cookie。但是Web 存储需要更加的安全与快速,这些数据不会被保存在服务器上,但是这些数据只用于用户请求网站数据上。它也可以存储大量的数据,而不影响网站的性能。数据以 键/值 对存在, web网页的数据只允许该网页访问使用。

        Web Storage的目的是为了克服由cookie带来的一些限制,当数据需要被严格控制在客户端上时,无须持续地将数据发回服务器。Web Storage的两个主要目标是:

        Web Storage又分为两种: sessionStorage 和localStorage ,即这两个是Storage的一个实例。从字面意思就可以很清楚的看出来,sessionStorage将数据保存在session中,浏览器关闭也就没了(页面刷新不会消除数据);而localStorage则一直将数据保存在客户端本地--除非主动删除。

 

9. http 和 https(安全套接字层超文本传输协议) 的区别

    https是安全协议连接,在信息传输上更为保密和安全,而http则安全性较低,会发生信息泄露和被劫持篡改。

    HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息;为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

    /* SSL属于应用层协议,位于应用层协议与TCP(运输层之间),提供了加密、数据完整性、端点鉴别等功能,实现进程间安全通信 */

    http使用的数据端口是80端口,而https使用的数据端口是443。

 

10. 声明提升

      声明提升就像把声明(变量声明和函数声明)从它们所在代码中出现的位置移到了最上面。且只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。

 

11. 从在浏览器中输入地址到在界面上显示中间发生了什么

      a. 在浏览器中输入地址,如:www.baidu.com
      b. 向DNS服务器查询网站IP地址
      c. DNS服务器返回网站IP地址(如:119.75.217.56)
      d. 浏览器得到IP地址后.浏览器会把用户输入的域名转化为HTTP服务请求
      e. 服务器接收到请求后,返回网页信息
      f. 客户端浏览器将这些信息组织成用户可以查看的网页形式

      从输入网址到获得页面的网络请求的过程 -- 参考:https://blog.csdn.net/qq_36520235/article/details/82559847

 

12. vue双向绑定原理

      Object.defineProperty()

      使用Object.defineProperty可以定义新属性或修改原有的属性

      

      Vue是采用数据劫持结合发布/订阅模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调。

      

        Observer部分:

        对每个vue中的data中定义的属性循环用Object.defineProperty()实现数据劫持,以便利用其中的setter和getter,然后通知订阅者,订阅者会触发它的update方法,对视图进行更新。

       在vue中v-model,v-name,{{}}等都可以对数据进行展示,也就是说假如一个属性都通过这三个指令了,那么每当这个属性改变的时候,相应的这个三个指令的html视图也必须改变;

  于是vue中就是每当有这样的可能用到双向绑定的指令,就在一个Dep中增加一个订阅者(addSub),其订阅者只是更新自己的指令对应的数据,也就是v-model='name'和{{name}}有两个对应的订阅者,各自管理自己的地方;

  每当属性的set方法触发,就循环更新Dep中的订阅者(notify);

       总结:

       首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;

  然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会;

  接着为input会添加监听事件,修改值就等于为该属性赋值,则会触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。

 

13. v-if(条件渲染) 和 v-show(条件隐藏) 区别:

      v-if有更高的切换开销,v-show有更高的初始渲染开销。如果需要频繁的切换,使用v-show比较好,如果运行条件很少改变,使用v-if比较好。

     v-show比v-if性能更高,因为v-show只能动态的改变样式,不需要增删DOM元素。所以当程序不是很大时候,v-if和v-show区别都不大,如果项目很大,推荐多用v-show,较少浏览器后期操作的性能。

     vue生命周期区别:v-if由于是重新渲染,所以每次切换一次会重新走一次生命周期,v-show由于只是控制显示隐藏,所以除了初始化渲染,其他时候都不会再走相关生命周期了。

 

14. 判断js的类型

(1) typeof方法

     typeof null返回的是object;

     特殊值NaN返回的是 "number";

     复杂数据类型里,除了函数返回了"function"其他均返回“object”;

(2) object.property.toString.call

(3) obj instanceof Object 

     左边放你要判断的内容,右边放类型来进行JS类型判断,只能用来判断复杂数据类型,因为instanceof 是用于检测构造函数(右边)的 prototype 属性是否出现在某个实例对象(左边)的原型链上。

 

(纯属复习面经自用,部分答案我直接引用了搜到的回答,如果介意,可以私信给我删掉)

标签:总结,child1,函数,一面面,ACK,报文,Client,腾讯,name
来源: https://blog.csdn.net/weixin_43516406/article/details/115133857