面试

作者: 艾萨克菊花 | 来源:发表于2019-03-18 18:42 被阅读0次

    跨域

    1、jsonp【回调函数、数据】

    同源策略:协议、域名、端口号都相同。

    js动态创建一个script标签,通过script标签中的src不受同源策略的影响来进行跨域;

    var script = document.createElement('script');

    script.src="链接+callback";

    ducument.body.insetBrfore(script,document.body.firstChild);

    2、$.ajax({})

     dataType : "jsonp", // 返回的数据类型,设置为JSONP方式

    jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback

    jsonpCallback: 'handleResponse', //设置回调函数名

    3、$.getJSON()

    需要在链接中加入callback

    4、axios

    安装axios,重启vue=>在main.js中引入axios=>config下的index.js文件的proxyTable配置代理

    //axios

    this.$axios.post("链接地址",{})

    .then(data=>{console.log(data)}

    缺点:

    安全问题【请求代码中存在安全隐患】、要确定jsonp请求是否失败很难


    闭包

    【相关内容根据此篇文章编辑】原文链接https://www.jianshu.com/p/132fb6d485ee

    能够读取其他函数内部变量的函数。【应用场景:要获取其他函数内部变量】

    闭包的优点:

    1、能够读取其他函数内部的变量;

    2、能让这些变量一直存储于内存中,不会在调用结束后,被垃圾回收机制回收♻️;

    闭包的缺点:【占内存、内存泄漏

    由于闭包使函数内部的变量保存在内存中,内存消耗很大,所以不能滥用闭包;

    解决办法就是:退出函数之前将不使用的局部变量删除。

    使用场景:

    1、解决setTimeout第一个函数不能传递参数问题:

    原生的setTimeout有一个缺点,传递的第一个函数不能带参数:

    setTimeout(demo(param),1000);    //错误❌

    这里我们可以用闭包来实现:

    function demo(param) {

        return function(){ alter(param) }

    }

    var d = demo(1);

    setTimeout(d, 1000);    //正确✅

    2、通过循环给页面上多个DOM节点绑定事件:

    //页面上有3个button

    var btn = document.getElementsByTagName(button);

    for(var i=0;i<btn.length;i++){

        btn[i].onclick=function(){console.log(i)}    

        //btn的click是异步触发的,所以当click事件顺着作用域链从内向外查找变量i时,找到i的值总是3

    }    //无论那个btn点击之后都是console.log(3)

    在js中只有函数作用域,没有块级作用域,所以采用立即函数的方法:

    for(var i=0;i<btn.length;i++){

        (function(i){

            btn[i].onclick=funciton(){console.log(i)}

        }(i))

    }

    3、闭包可以将一些不希望暴露在全局的变量封装成“私有变量”;

    假如有一个计算乘积的函数,mult函数接收一些number类型的参数,并返回乘积结果。为了提高函数性能,我们增加缓存机制,将之前计算过的结果缓存起来,下次遇到同样的参数,就可以直接返回结果,而不需要参与运算。这里,存放缓存结果的变量不需要暴露给外界,并且需要在函数运行结束后,仍然保存,所以可以采用闭包。

    全局变量封装为私有变量

    4、延续局部变量的’寿命‘

    这段代码中,在函数运行完成之后,img变量会被回收机制销毁;

    var report = function report(){

        var imgs = [];

        return function(src){

            var img = new Image();

            imgs.push(img);

            img.src = src;

        }

    }

    5、前端很多设计模式中,很多应用到闭包;


    冒泡、事件委托

    1、事件冒泡事件从最深的节点开始,逐步向上传播事件

    阻止冒泡:【IE:e.cancelBubble = true】

    e.stopPropagation()阻止冒泡

    event.preventDefault()取消事件的默认行为

    return false;阻止运行

    2、事件委托事件委托就是利用了事件冒泡原理来实现的,委托他们父级代为执行事件

    如果我们有100个li,我们需要给每个li绑定click事件,传统的做法就是for循环;

    javascript中添加页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为我们需要不断的与dom节点进行交互,访问的dom次数越多,浏览器重绘与重排的次数也就越多,对浏览器性能很不友好;

    如果使用事件委托,那么我们只需要对它的父级这一个对象进行操作

    //传统做法

    var ul = document.getElementById('ul');

    var li = document.getElementById('li');

    for(var i=0;i<li.length;i++){

        li[i].onclick=funciton(){console.log('li')}

    }

    //这里父级ul做事件处理,当点击li时,事件向上传递给ul,因为ul有事件,当点击ul的时候也会触发

    var ul = document.getElementById('ul');

    ul.onclick = funciton(){console.log('li')}

    //如果我们想事件代理的效果跟直接给节点事件效果一样,比如我们只有点击li的时候才会触发:

    //event对象提供了一个属性叫target,可以返回事件的目标节点,我们称为事件源

    var ul = document.getElementById('ul');

    ul.onclick = function(e){

        var ev = e || window.event;

        var target = ev.target || ev.srcElement;

        if(target.nodeName.toLowerCase() == 'li'){

            console.log('li')

        }

    }

    【对浏览器性能优化拓展】

    Vue虚拟dom:

    10次DOM操作=>虚拟DOM=>将十次更新的diff内容存储到本地的js对象上=>将这个js对象一次性attch到DOM树上

    React虚拟dom:

    react组件在内部维护了一套虚拟DOM的状态,这套DOM状态最终会映射到真实DOM节点上;但是当虚拟DOM状态发生变化的时候,它的内部需要计算虚拟DOM之间的区别,产生diff,最终在真实DOM上并不会整体刷新,而是只将diff部分用一种高效更新到ui上。


    jQuery链式原理

    var myJq = function(){};

    myJq.prototype = {

        css: function(){return this;},

        show: funciton(){return this;},

        hide:function(return this;)

    }

    var m = new myJq();

    m.css().show().hide();


    Vue项目性能优化

    1、代码包优化

    屏蔽sourceMap】对项目开发环节的开发提示信息以及错误信息进行屏蔽:减少上线代码包的大小;提高系统的安全性

    对项目代码中的js、css、svg等文件进行压缩

    对路由组件进行懒加载】如果使用同步的方式加载路由组件,在首屏加载时会对网络资源加载加载比较多、慢

    2、源码优化

    v-if和v-show选择调用】v-if是懒加载,当状态为true的时候才开始加载,并且为false的时候不占用空间;v-show无论状态false还是true都会进行渲染

    为item设置唯一的key值】在列表数据进行遍历渲染时,需要为每一项item设置唯一的key值;当state更新时,新的状态值和旧的状态值对比,能够较快的找到diff。

    细分vue组件】如果把所有组件的布局都写到一个组件里,当数据变更时,由于组件代码比较大,vue的数据驱动视图更新比较慢,造成渲染比较慢。

    减少watch的数据】watch监听的数据比较大时,系统会出现卡顿。

    内容类系统的图片资源按需加载】如果出现图片加载比较多,可以使用v-lazy之类的懒加载库或者绑定dom的scroll事件,滚动到可视区域,在对需要的资源进行加载

    SSR(服务端渲染)】如果项目比较大,首屏无论怎么做优化,都出现闪屏或者一阵黑屏的情况。可以考虑使用SSR(服务端渲染),vuejs官方文档提供next.js很好的服务端解决方案,但是局限性就是目前仅支持Koa、express等Nodejs的后台框架,需要webpack支持。目前自己了解的就是后端支持方面,vuejs的后端渲染支持php,其它的不太清楚

    3、用户体验优化

    better-click防止iphone点击延迟】在开发vue项目时,手指触摸时会出现300ms的延迟效果,可以使用better-click对iphone系列的兼容体验优化

    loading】在加载资源过程中可以显示loding

    骨架屏加载】在首屏加载资源比较多,可能会出现白屏、闪屏的情况,可以使用骨架屏加载传送门


    vuex-状态管理模式

    vuex是专门为vue应用程序开发的状态管理模式,采用集中式存储管理所有组件的公共状态,并以相应的规则保证状态以一种可预测的方式发生变化

    vuex

    为什么使用vuex:

    组件通讯

    如果父组件下面有多个子组件,子组件之间的通讯就会变的非常繁琐,父组件需要监听大量的事件,还需要分发给不同的组件,vuex就是解决这一问题的。

    核心概念:

    1、state【state就是vuex中公共的data,用于保存所有组件的公共数据。】

    2、getters【getters属性理解为所有组件的computed属性-计算属性】

    getters的返回值会根据它的依赖被缓存起来,只有它的依赖值发生变化时才会被重新计算。

    3、mutations【mutations理解为store中的methods】

    mutations对象中保存着更改数据的回调函数,该函数名官方叫type,第一个参数为state,第二个参数为payload,也就是自定义参数。

    4、actions【类似于mutations】

    -actions提交的是mutations而不是直接变更状态;

    -actions可以包含异步操作,mutations中不允许出现异步;

    -actions回调函数中第一个参数是context,是一个与store实例具有相同属性和方法的对象;

    5、modules【分割模块】

    由于使用单一状态树,应用所有的状态会集中到一个比较大的对象。当应用比较复杂时,store对象就会变得非常臃肿。为了解决这一问题,vuex允许我们将store分割称模块。每个模块都拥有自己的state、getters、mutaions、acrtions,甚至是嵌套子模块,从上至下进行相同的方式分割。

    使用

    vuex通过store选项,提供了一种机制将状态从根组件“注入”到每一个组件中(需效用Vue.use(Vuex)),

    通过在根实例中注册“store”选项该store实例会注入到根组件下的所有子组件中,且通过this.$store访问。

    mapState辅助函数

    getter会暴露为store;getters对象,可以以属性的形式访问这些值:


    浏览器存储-传送门

    一、cookie和session

    cookie和session都是用来跟踪浏览器用户身份的会话方式。

    区别:

    1、保持状态:cookie存储在浏览器端、session存储在服务器端

    2、使用方式:

    cookie机制:

    如果在浏览器端设置过期时间,cookie被保存在内存中,生命周期随浏览器的关闭而结束【会话cookie

    如果在浏览器设置了cookie的过期时间,cookie保存在硬盘中,关闭浏览器后,cookie应然存在,直到过期时间结束【设置时间cookie

    cookie是服务器发给客户端的特殊信息,cookie以文本字符串的形式存储在客户端,浏览器每次请求都会带上它。

    session机制:【可以通过response.encodeURL(url) 进行实现】

    当服务器收到请求需要创建session对象时,首先会检查客户端请求中是否包含sessionId。如果有sessionId,服务器将会根据id返回对应的session对象。如果客户端请求中没有sessionId,服务器会创建新的session对象,并把本次响应返回给客户端。通常使用cookie方式存储sessionid到客户端,在交互中浏览器按照规则将sessionid发送给服务器。如果用户禁用cookie,则要使用url重写,可以通过response.encodeURL(url) 进行实现。

    默认session过期时间为30分钟,从session不活动的时候开始计算,从该Session未被访问,开始计时; 一旦Session被访问,计时清0;

    3、存储内容:cookie只能保存字符串类型,以文本的方式;session通过类似与Hashtable的数据结构来保存,能支持任何类型的对象【可包含多个对象】

    4、存储大小:cookie-4k;session没有限制

    5、安全性:cookie的安全性低于session

    (1)sessionID存储与cookie,如果要攻破session,首先要攻破cookie;

    (2)sessionID是要有人登陆,或者启动session_start才会有,所以攻破cookie也不一定能够攻破session;

    (3)第二次启动session_start后,前一次的sessionID就会失效,session过期后,sessionID也会随之消失;

    (4)sessionID是加密的;

    (5)综上所述,攻击者必须要在短时间内攻破加密的sessionID;

    6、应用场景

    cookie:

    (1)判断用户是否登陆过网站,以便下次访问时自动登陆或记住密码。如果删除cookie,则每次登陆需要重新填写;

    (2)保存上次登陆时间等信息;

    (3)保存上次查看的页面;

    (4)浏览计数;

    cookie

    session:用于保存每个用户的专用信息,变更的值保存在浏览器端,通过sessionID来区分不同的用户。

    (1)网上商城中的购物车;

    (2)保存用户登录信息;

    (3)将某些数据放入session,供统一用户不同页面使用;

    (4)防止用户非法登陆;

    7、缺点:

    cookie:

    (1)大小受限;

    (2)用户可以操作(禁用)cookie,使功能受限;

    (3)安全性低;

    (4)有些状态不可能保存在客户端;

    (5)每次访问都会带给服务器,浪费带宽;

    session:

    (1)session保存的东西越多,占用的内存越大,对于在线人数较多的网站,服务器的内存压力比较大;

    (2)依赖于cookie,如果禁用cookie,则要使用url重写,不安全;

    (3)session变量有很大的随意性,可以随时调用。过度使用session会导致代码不可读、不好维护;

    sessionStroage:将数据保存在session对象中。所谓session,是指用户在浏览每个网站时,从进入网站到浏览器关闭所经历的这段时间【用户浏览这个网站所花费的时间】,session对象可以用来保存这段时间内所要求保存的任何数据。【临时保存-客户端(不与服务端进行通信)-5M-字符串类型】会话存储(刷新、同源页面一样)(同一浏览器另一个会话不一样)】【长期登陆

    localStorage:将数据保存在客户端本地的硬件设备,即使浏览器关闭了,该数据仍然存在,下次打开浏览器访问网站时,可以继续使用。【永久保存-客户端(不与服务端进行交互)-5M-字符串类型】【本地存储】【敏感账号一次性登陆

    cookie、sessionStorage、localStorage

    webStroage与cookie:

    (1)存储空间更大;

    (2)节省网络流量;

    (3)对于一次性数据,webStorage方便;

    (4)快速显示;

    (5)安全;

    (6)webStorage提供了以下api,操作更加方便;


    原型与原型链(继承)传送门

    1、构造函数

    构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。构造函数模式中拥有了类和实例的概念,并且类和实例之间是相互独立的,即实例识别。

    2、原型

    在js中,每定义一个函数数据类型(普通函数、类)的时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。

    构造函数与实例原型之间的关系

    3、原型链

    (1)__proto__和constructor

    每一个对象数据类型(普通对象、实例、prototype...)也天生自带一个属性__proto__,属性值是当前实例所属类的原型(prototype)。原型对象中有一个属性constructor,它指向函数对象。

    _proto_和constructor

    (2)何为原型链

    在js中万物都是对象,对象与对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在js中是通过prototype对象指向父类对象,直到指向Object对象为止,这样形成了一个原型指向的链条-原型链。

    当我们访问一个对象的属性或方法时,它会现在对象自身查找,如果有则直接使用,如果没有则去原型对象中使用,如果还没有则到原型的原型中查找,直到找到Object对象的原型,Object的原型是没有原型的,如果在Object中还没找到则返回undefined。

    Object是JS中所有对象数据类型的基类【最顶层的类】,在Object.prototype是没有__proto__这个属性。

    原型链

    Array.splice()、Array.slice()

    Array.splice(index,howmany,itemn) 向/从数组中添加/删除项目,return 被删除的项

    index:必需,删除/添加的位置,负数可从数组尾部操作;

    howmany:必需,要删除项目的数量,0 则不删除;

    item:可选,向数组添加新项目;

    var arr = [1,2,3];

    arr.splice(0,1)    //[1]    //[2,3]

    arr.splice(0,1,1)    //[1]    //[1,2,3]

    Array.slice(start,end) 从已有的数组中返回选定的元素【返回一个数组】

    var arr = [1,2,3];

    arr.slice(0,1)    //[1]


    typeof [1,2,3]    //object

    [1,2,3] instanceof Array

    Array.isArray([1,2,3])

    转化为字符串join()


    object === object传送门

    var obj1 = {a:1,b:2}

    var obj2 = {a:1,b:2}

    obj1 == obj2    //false

    obj1 === obj2 // false

    通过上面的例子可以看出,无论使用==还是使用===都是返回的false,原因是number、string通过值来比较,而对象通过指针指向的内存中的地址来做比较

    functionfoo(a){

        a = a * 10;

    }functionbar(b){

        b.value = 'new';

    }var a = 1;var b = {value: 'old'};

    foo(a);

    bar(b);console.log(a); // 1console.log(b); // value: new

    这就是因为Number类型的a是按值传递的,而Object类型的b是按共享传递的。

    如果要判断两个对象是否相等,必须要判断两个对象的属性以及对应的值是否相等

    function isObjectValueEqual(a,b){

        var aProps = Object.getOwnPropertyNames(a);

        var bProps = Object.getOwnPropertyNames(b);

        if(aProps.length !== bProps.length) {

            return false;

        }

        for (var i = 0; i < aProps.length; i++) {

            var propName = aProps[i];

            if (a[propName] !== b[propName]) {

                return false;

            }

        }

        return true;

    }

    Underscore和Lo-Dash有一个名为_.isEqual()方法,用来比较好的处理深度对象的比较。

    var o1 = {a:1}

    var o2 = {a:1}

    _.isEqual(o1,o2)    //true


    restful API

    特征:

    1、每个url代表一张资源;

    2、客户端与服务端之间,传递这种资源的某种表现层;

    3、客户端通过四个http动词【GET、POST、DELETE、PUT】,对服务器端资源进行操作,实现表现层状态转化【增删改查】;

    4、url通常不出现动词,只有名词;

    5、使用json不使用XML;

    设计方式:

    HEAD:只获取某个资源的头部信息;

    GET:获取资源;

    POST:创建资源;

    PATCH:更新资源的部分属性【很少用,一般用post代替】;

    PUT:更新资源,客户端需要提供新建资源的所有属性;

    DELETE:删除资源;

    使用方式:

    GET:http://www.birjemin.com/api/user    #获取列表

    POST:http://www.birjemin.com/api/user    #创建用户

    PUT:http://www.birjemin.com/api/user/{id}    #修改用户信息

    DELETE:http://www.birjemin.com/api/user/{id}    #删除用户信息

    状态码:

    状态码

    2XX成功:

    -200:ok

    -204:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般只需要从客户端向服务器发送信息,而不返回数据使用。

    -206:表示客户端进行了范围请求。响应报文包含由 Content-Range 指定范围的实体内容。

    3XX重定向:

    -301:永久性重定向

    -302:临时性重定向

    -303:和302有相同的功能,但是303明确要求客户端应该采用GET方法获取资源【注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。】

    -304:如果请求报文首部包含一些条件,例如:If-Match,If-ModifiedSince,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。【缓存的状态码,如果If-Match,If-ModifiedSince,If-None-Match,If-Range,If-Unmodified-Since的标识符改变了,代表是不缓存,没改变代表缓存,缓存相关文章:https://segmentfault.com/a/1190000010690320】

    -307:临时重定向,与302的含义相似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。

    4XX客户端错误:

    -400:请求报文中存在语法错误;

    -401:该状态码表示发送的请求需要有认证信息【BASIC 认证、DIGEST 认证】,如果之前已经请求过一次,则表示用户认证失败。【一般是未登陆出现】

    -403:请求被拒绝,服务端没有必要给出拒绝的理由【一般是登陆了,没有权限,服务端拒绝请求】

    -404:【一般是请求url拼接错误,请求路径不对】

    5XX:服务器错误

    -500:服务器正在执行请求时发生错误;

    -503:服务器暂停处于超负载或正在进行停机维修,现在无法处理请求。

    相关文章

      网友评论

          本文标题:面试

          本文链接:https://www.haomeiwen.com/subject/hdafmqtx.html