web前端面试中常问的问题

目录

vue2和vue3的vue-route

vuex

vuex模块化

微信小程序的授权登录

小程序版:

nui版:

父子组件传值

宏任务与微任务

async和awite优化promise

深拷贝

面向对象与面向过程的本质的区别

vue 中v-if 和 vi-for为什么不能一起使用

电商中spu和sku?

一、什么是SPU?

二、什么是SKU?

v-html和v-text

xss攻击原理

arguments

vue生命周期中created和mounted有什么区别?

找出数组中出现最多的数字

消元法

水平居中 

行内元素

 块级元素

方案一:(分宽度定不定两种情况)

找出数组中的重复数据

上传,修改头像的使用

Vue-router路由中的导航守卫和拦截器(Axios)之间的区别

VueRouter-router 与 route 区别

手写简易的ajax请求

递归

vue路由跳转的几种方式

Js 添加、复制、移除、移动、创建和查找节点

1、document.createDocumentFragment() //创建一个 DOM 片段

document.createDocumentFragment()

2、document.createElement() //创建一个具体的元素

3、createTextNode() //创建一个文本节点

二、)添加、移除、替换、插入

2、removeChild() //移除

三)查找

什么是闭包?闭包的优缺点

es6的新增特性

class与class继承

async await

Git

http和https的区别

三次握手和四次挥手

使用基于token的登录流程

 Get和post的区别

web安全及防护

html和XML-

This的指向

箭头函数与普通函数的区别

localStorage、sessionStorage 和 Cookie 区别及用法


vue2和vue3的vue-route

vue2的中是使用this.$router进行跳转页面,传递参数,使用this.$route来接受参数,而在vue3中时都是写在setup中拿不到this所以需要进行那个单独的引入,从vue-router中引入并解构useroute或userouter并将其执行后的返回值用一个变量接收,那么这个变量就想当于vue2中的this.$toute或this.$touter,其余跳转页面传信或接收参数的方式和vue2一致。

vuex

因为setup中无法获取this实例,如果想要使用vuex就不再是this.$store需要单独引入,let一个store等于usestore执行这个store就相当于是vue2中的this.$store,其余方式一致。

vuex模块化

创建一个js文件,在js文件中翻出一个对象,这个对象里面包含satate,getters,mutations,actions这四个属性把,namespace:true代表他是一个独立名利的空间,这样这个js文件命名就不会和route的index.js的命名冲突,然后在route的index.js文件按照路径引入并注册在model中。

this.$store.state.name            //原来的
this.$store.state.模块名.属性名     //模块化

微信小程序的授权登录

小程序版:

微信小程序有一个button组件,他有一个open-type属性来设置他的按钮来按钮类型,open-type有一个值,get-UseInfo,它代表获取用户信息功能,另一个事件,bind-getuseInfo,是获取点击后的数据,他有一个形参,这个形参中就有用户的信息。

nui版:

nui.getUseProfile这个api会拉取用户授权,点击取消子自动隐藏,点击确定时触发success函数,这个函数返回的值就是用户当前的个人信息。他必须要有一个desc属性必须写值,这个值就是描述我为什么要拉取个人授权。

父子组件传值

首先说这么定义子组件,创建compunents文件夹,里面创建对应的子组件,在引入的子组件的那个父组件的json文件里,书写usingComponents根绝路径引入,微信ml文件中就可以把子组件当成标签使用。

父传子:

在子组件标签上设置自定义属性,而子组件的js文件里的properties就相当于props用来接收数据。

子传父:

在子组件标签中设置自定义事件,子组件调用this.triggerEvent,用来接收事件调用事件并传递参数,使用对象格式传值。

宏任务与微任务

异步事件setTimeout setInterval Ajax DOM事件 promise async awite 除了这些都是同步,异步事件分为微任务与宏任务,其中微任务是promise async awite 其余异步事件都是异步宏任务。事件的执行是先执行同步宏任务在执行异步微任务,之后才是异步的宏任务。需要注意是,awite后面的异步事件同步执行,但是在往后的事件会变成异步的微任务。

async和awite优化promise

当我们想拿到promise的一个执行结果时,需要通过点then和点catch的链式回调,在他的内部来获取或打印信息,而在外部时拿不到拿不到当前信息的,这不符合我们的编码习惯,这也会对我们后期的工作产生困难,所以我们使用async和awite对pmise进行优化,将async放在函数前面便变成一个异步函数,异步函数内部使用awite放置当前的请求,就可以使用变量来接收请求后的结果,也可以进行解构赋值,这下我们就可以在代码的下方直接获取请求到的信息。将异步代码编程同步代码,更符合我们的一个编程习惯。

深拷贝

定义一个函数这个函数接收一个参数默认为一个对象,然后判断如果他不是一个对象或者为null的时候就直接返回,防止用户乱传,let一个变量用来接收最后的返回值,判断当前传入的数据类型,定义这个变量为空数组或者是空对象,循环传入的数据,然后是递归调用并赋值,最后返出定义的变量。(最后的结果)

面向对象与面向过程的本质的区别

一、面向对象与面向过程的区别

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展

面向对象

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低

vue 中v-if 和 vi-for为什么不能一起使用

1,v-for的优先级高于v-if

2,如果两者同时存在,可在v-for的外层使用template标签包裹来进行v-if判断,如果放在一起,每v-for循环一次都需要进行v-if判断(先判断了条件再看是否执行_),影响性能

3,如果v-if判断出现在v-for的内部,可以通过计算属性过滤掉那么不需要的选项

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true值的时候被渲染

v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组或者对象,而 item 则是被迭代的数组元素的别名

在 v-for 的时候,建议设置key值,并且保证每个key值是独一无二的,这便于diff算法进行优化
 


 
  • {{ item.label }}
  • 电商中spu和sku?

    一、什么是SPU?

    SPU全称Standard Product Unit (标准化产品单元)。译为:最小包装单元;

    SPU可以直接认为是很多个产品打包组成的一个新物品,有更多的新特性和更多的形态。

    二、什么是SKU?

    SKU全称stock keeping unit(库存量单位)。译为:最小主要单元;

    SKU不同于SPU,它可以认为就是一个很简单的物品。而这些个简单的物品打包组合就是SPU,比如,现在有5个iPhone(SKU),如果5个为一个生产最小单位,那么这5个iPhone就是组合打包产品(SPU)
     

    v-html和v-text

        
    {{msg}}

    xss攻击原理

    XSS攻击原理
    Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意 html标签或者javascript代码。

    比如:
    ①攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;
    ②或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。
     

    arguments

    arguments是一个类数组的集合,他有数组的长度和下标的特性,但是没有数组的api,

    如果你调用一个函数,当这个函数的参数数量比它显式声明的参数数量更多的时候,你就可以使用 arguments 对象。这个技术对于参数数量是一个可变量的函数来说比较有用。 你可以用 arguments.length 来得到参数的数量,然后可以用 arguments object 来对每个参数进行处理。 (想要得到函数签名的参数数量, 请使用 Function.length 属性。)

    vue生命周期中created和mounted有什么区别?

    created在这个时候虚拟dom还没有渲染出来,在这个时候是不能直接操作dom节点的。mounted中在这个时候,虚拟dom已经渲染完毕,可以直接渲染dom节点。

    找出数组中出现最多的数字

    第一种方法排序就可以得出答案中位数就可以

        public int majorityElement(int[] nums) {
            Arrays.sort(nums);
            int l=0;
            int r=nums.length-1;
            int mid=(l+r)>>1;
            return nums[mid];
        }
    

    消元法

       public int majorityElement2(int[] num) {
            //3.2.3
            int result=num[0], count = 1;
            for(int i=1; i

    水平居中 

    • 行内元素

    首先看它的父元素是不是块级元素,如果是,则直接给父元素设置 text-align: center; 

    
     
    
    我是行内元素

    如果不是,则先将其父元素设置为块级元素,再给父元素设置 text-align: center;

    
     
    
        我是行内元素
    
    •  块级元素

    方案一:(分宽度定不定两种情况)

    定宽度:需要谁居中,给其设置 margin: 0 auto; (作用:使盒子自己居中)

    
     
    
    我是块级元素

     不定宽度:默认子元素的宽度和父元素一样,这时需要设置子元素为display: inline-block; 或 display: inline;即将其转换成行内块级/行内元素,给父元素设置 text-align: center; 

    找出数组中的重复数据

     const str = 'jshdjsihh';
     const obj = str.split('').reduce((pre, item) => {
         pre[item] ? pre[item]++ : pre[item] = 1
             return pre
         }, {}
     )
    console.log(obj) // {j: 2, s: 2, h: 3, d: 1, i: 1}

    1 使用数组的 reduce() 方法,为数组中的每一个元素依次执行回调函数。以下为该方法的参数

    pre:上次调用函数的返回值(对象)
    item:当前元素
    index:当前元素索引
    arr:被遍历的数组
    2 判断返回值中,是否存在当前元素,如果存在,就将当前元素数量++,否则,数量为1

    3 然后将最终的值返出

    4 用一个变量去接受最后的返回值,这个数据,就是拥有的元素与对应数量的键值对的集合

    上传,修改头像的使用

    原生的input按钮设置他的type为file代表他是上传文件功能,第二它定义的change事件中需要一个new FormData对象将其转为对应格式这样就可以将这个修改后的数据传给我们的接口,之后在这个接口中就能拿到我们上传头像的网络地址,有些项目还需要将这些接口再次传入项目的接口,有些不需要。

    也可以使用vant或者element中使用它就可以直接获取到new FormData,原生是需要new FormData,而vant不需要。手写input需要使用一个FormData对象来转换格式,而vant的file是已经转换好的。

    Vue-router路由中的导航守卫和拦截器(Axios)之间的区别

    导航守卫:

    1. 导航守卫就是我们进行某些页面的时候需要判断当前用户是否登录过,如果登陆过,则可以跳转,否则重定向到登录页面
    2. 导航守卫是路由的导航守卫
    3. 导航守卫只是前段做出判断,检查请求头中是否带有token,并不能判断token是否失效
    4. axios拦截器:
      // 每次发送请求之前判断vuex中是否存在token
      // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
      // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
    5. 导航守卫和axios拦截器的区别

      导航守卫就是路由守卫,想进入一个页面时,判断是否有权限访问(有token,就有权限,没有就返回),但并不能判断是否失效。
      axios拦截器是发送请求判断token的有效性,如果有就将token放在请求头里。
      导航守卫和axios拦截器一起使用,进而来确保登录的状态VueRouter-router 与 route 区别

    VueRouter-router 与 route 区别

    1.router

        router 是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数的到的一个router对象。这个对象是一个全局对象,他包含可所有路由包含许多关键性的对象和属性

    2.route

          route是一个跳转路由对象,每一个路由都会有一个router对象,是一个局部的对象,可以获取对应的name、path、params、querty等

    手写简易的ajax请求

    // 第一步需要new一个XMLHttpRequest对象
            const xhr = new XMLHttpRequest()
            // 第二步使用传入请求方式,请求路径,同步还是异步
            // 最后的一个参数,true是代表异步请求,false是代表同步请求,默认是异步
            xhr.open('GET', '/api', true)
            // 当状态改变的时候发送请求
            xhr.onreadystatechange = function() {
                // xhr.readyState的几种状态
                // 0 - (未初始化)还没有调用send()方法
                // 1 - (载入)已调用send()方法,正在发送请求
                // 2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
                // 3 - (交互)正在解析响应内容
                // 4 - (完成)响应内容解析完成,可以在客户端调用
                if(xhr.readyState === 4){
                    // http请求状态码 200代表成功
                    if(xhr.status === 200){
                        alert(xhr.responseText)
                    }
                }
            }
            xhr.send(null)
    

    递归

    何为递归?程序反复调用自身即是递归。

    vue路由跳转的几种方式

    router-link (声明式路由)

    1. 不带参数
     
     
     //name,path都行, 建议用name  
    // 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
     
    2.带参数
     
      
     
    // params传参数 (类似post)
    // 路由配置 path: "/home/:id" 或者 path: "/home:id" 
    // 不配置path ,第一次可请求,刷新页面id会消失
    // 配置path,刷新页面id会保留
     
    // html 取参  $route.params.id
    // script 取参  this.$route.params.id
     
    
     
    

    router.push(编程式路由)

    // 字符串
    router.push('home')
    
    // 对象
    router.push({ path: 'home' })
    
    // 命名的路由
    router.push({ name: 'user', params: { userId: '123' }})
    
    // 带查询参数,变成 /register?plan=private
    router.push({ path: 'register', query: { plan: 'private' }})
    

    如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:

    const userId = '123'
    router.push({ name: 'user', params: { userId }}) // -> /user/123
    router.push({ path: `/user/${userId}` }) // -> /user/123
    // 这里的 params 不生效
    router.push({ path: '/user', params: { userId }}) // -> /user
    

    this.$router.push() (函数里面调用)

    1.  不带参数
     
    this.$router.push('/home')
    this.$router.push({name:'home'})
    this.$router.push({path:'/home'})
     
    2. query传参 
     
    this.$router.push({name:'home',query: {id:'1'}})
    this.$router.push({path:'/home',query: {id:'1'}})
     
    // html 取参  $route.query.id
    // script 取参  this.$route.query.id
     
    3. params传参
     
    this.$router.push({name:'home',params: {id:'1'}})  // 只能用 name
     
    // 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
    // 不配置path ,第一次可请求,刷新页面id会消失
    // 配置path,刷新页面id会保留
     
    // html 取参  $route.params.id
    // script 取参  this.$route.params.id
     
    4. query和params区别
    query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
     
    params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
    

     this.$router.replace() (用法同上,push)

    this.$router.go(n) ()

    this.$router.go(n)
    向前或者向后跳转n个页面,n可为正整数或负整数
    
    ps : 区别
    
    this.$router.push
    跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
    this.$router.replace
    跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
    
    this.$router.go(n)
    向前或者向后跳转n个页面,n可为正整数或负整数
    

    注意:获取路由上面的参数,用的是$route,后面没有r
    params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
    params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。
    params、query不设置也可以传参,但是params不设置的时候,刷新页面或者返回参数会丢失,

    两者都可以传递参数,区别是什么?
    query 传参配置的是path,而params传参配置的是name,在params中配置path无效
    query在路由配置不需要设置参数,而params必须设置
    query传递的参数会显示在地址栏中
    params传参刷新会无效,但是query会保存传递过来的值,刷新不变

    Js 添加、复制、移除、移动、创建和查找节点

    1)创建新节点

      createDocumentFragment() //创建一个DOM片段
      createElement() //创建一个具体的元素
      createTextNode() //创建一个文本节点

    2)添加、移除、替换、插入
      appendChild() //添加
      removeChild() //移除
      replaceChild() //替换
      insertBefore() //插入

    3)查找
      getElementsByTagName() //通过标签名称
      getElementsByName() //通过元素的Name属性的值
      getElementById() //通过元素Id,唯一性

    4)复制

           cloneNode() //复制节点

    1、document.createDocumentFragment() //创建一个 DOM 片段


    createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。

    当你想提取文档的一部分,改变,增加,或删除某些内容及插入到文档末尾可以使用createDocumentFragment() 方法。

    你也可以使用文档的文档对象来执行这些变化,但要防止文件结构被破坏,createDocumentFragment()方法可以更安全改变文档的结构及节点。

    语法

    document.createDocumentFragment()

    DOM中,添加DOM节点时,多次调用document.body.append(),每次都要刷新页面一次。效率也就大打折扣了,而使用document_createDocumentFragment()创建一个文档碎片,把所有的新结点附加在其上,然后把文档碎片的内容一次性添加到document中,这也就只需要一次页面刷新就可。document_createDocumentFragment()可以起到节约使用DOM的作用。每次JavaScript对DOM的操作都会改变页面的变现,并重新刷新整个页面,从而消耗了大量的时间。为解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到document中。

    var d1 = new Date();
    //创建1000个段落,常规的方式
    for(var i = 0 ; i < 1000; i ++) {
        var p = document.createElement("p");
        var oTxt = document.createTextNode("段落" + i);
        p.appendChild(oTxt);
        document.body.appendChild(p);
    }
    var d2 = new Date();
    document.write("第一次创建需要的时间:"+(d2.getTime()-d1.getTime())); //51
    
    
    //使用了createDocumentFragment()的程序
    var d3 = new Date();
    var pFragment = document.createDocumentFragment();
    for(var i = 0 ; i < 1000; i ++) {
        var p = document.createElement("p");
        var oTxt = document.createTextNode("段落" + i);
        p.appendChild(oTxt);
        pFragment.appendChild(p);
    }
    document.body.appendChild(pFragment);
    var d4 = new Date();
    document.write("第2次创建需要的时间:"+(d4.getTime()-d3.getTime())); //26

    2、document.createElement() //创建一个具体的元素

    定义和用法

    //创建一个按钮
    var btn = document.createElement("button");
    //HTML元素经常包含文本。创建指定文本的按钮你需要在按钮元素后添加文本节点:
    //创建指定文本的按钮:
    var btn2 = document.createElement("button");
    var txt = document.createTextNode("click me");
    btn2.appendChild(txt);
    document.body.appendChild(btn2);

    createElement() 方法通过指定名称创建一个元素

    3、createTextNode() //创建一个文本节点

    创建一个文本节点:

    var btn=document.createTextNode("Hello World");

    输出结果:
    Hello World

    HTML元素通常是由元素节点和文本节点组成。
    创建一个标题 (H1), 你必须创建 “H1” 元素和文本节点:

    创建一个标题:

    var h=document.createElement("h1")
    var t=document.createTextNode("Hello World");
    h.appendChild(t); 
    document.body.apppendChild(h);   //Hello World
     

    二、)添加、移除、替换、插入

    1、appendChild() //添加

    appendChild(Node)这个方法一般是在指定元素节点的最后一个子节点之后添加节点,但如果Node是页面中的DOM对象,那么就不是添加节点了,就是直接Move节点。

    向节点添加最后一个子节点

    • Apple
    • Banana
    • Pear

    从一个元素向另一个元素移动

    列表1

    • 德芙巧克力
    • 香草味八喜
    • 可可布朗尼

    列表2

    • 榴莲菠萝蜜
    • 芝士玉米粒
    • 鸡汁土豆泥
    • 黑椒牛里脊

    2、removeChild() //移除

    从子节点列表中删除某个节点:

    var list=document.getElementById("myList");
    list.removeChild(list.childNodes[0]);

    定义和用法

    removeChild() 方法可从子节点列表中删除某个节点。

    如删除成功,此方法可返回被删除的节点,如失败,则返回 NULL。

    • 德芙巧克力
    • 香草味八喜
    • 可可布朗尼
    • 榴莲菠萝蜜
    • 芝士玉米粒
    • 鸡汁土豆泥
    • 黑椒牛里脊

    4、insertBefore() //插入
    定义和用法

    insertBefore() 方法可在已有的子节点前插入一个新的子节点。

    提示: 如果你想创建一个新的文本列表项,在 LI 元素后你应该添加元素的文本节点,然后在列表中添加 LI元素。

    你也可以使用 insertBefore 方法来 插入/移除 已存在的元素。

    移动某个列表项到另一个列表项:
     

    var node=document.getElementById("myList2").lastChild;
    var list=document.getElementById("myList1");
    list.insertBefore(node,list.childNodes[0]);

    插入

    • 榴莲菠萝蜜
    • 芝士玉米粒
    • 鸡汁土豆泥
    • 黑椒牛里脊

    替换

    列表1

    • 德芙巧克力
    • 香草味八喜
    • 可可布朗尼

    列表2

    • 榴莲菠萝蜜
    • 芝士玉米粒
    • 鸡汁土豆泥
    • 黑椒牛里脊

    三)查找

    getElementsByTagName() //通过标签名称
    
    getElementsByClassName() //通过元素的class属性名称
    
    getElementById() //通过元素 Id,唯一性

    什么是闭包?闭包的优缺点

     定义:闭包 当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的变量,且返回的这个函数在外部被执行         就产生了闭包.闭包是一个环境,具体指的就是外部函数--高阶函数。

            说白了就是一个环境,能够读取其他函数内部的变量。

     本质上,闭包是将函数内部和函数外部连接起来的桥梁。

    用处:1.读取函数内部的变量;

               2.这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。

    优点:1:变量长期驻扎在内存中;

               2:避免全局变量的污染;

               3:私有成员的存在 ;

    特性:1:函数套函数;

               2:内部函数可以直接使用外部函数的局部变量或参数;

               3:变量或参数不会被垃圾回收机制回收 GC;

    缺点:

        常驻内存 会增大内存的使用量 使用不当会造成内存泄露,详解:

    (1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    (2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    es6的新增特性

    let、var、const区别  (var是es5新增)

    在ES5中,声明变量只有var和function两种形式。但是因为var声明的变量会有一定的缺点(内层变量可能覆盖外层变量的问题以及用来计数的循环变量泄露为全局变量,下面有介绍),ES6提出了使用let和const声明变量,弥补了ES5中var的缺点。

    1.是否存在变量提升?

    var声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,值为undefined。

    let和const不存在变量提升。即它们所声明的变量一定要在声明后使用,否则报ReferenceError错。

    2.是否存在暂时性死区?

    let和const存在暂时性死区。即只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

    在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

    总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

    3.是否允许重复声明变量?

    var允许重复声明变量。

    let和const在同一作用域不允许重复声明变量。

    4.是否存在块级作用域?

    var不存在块级作用域。

    let和const存在块级作用域。

    什么是块级作用域:

    ES5中作用域有:全局作用域、函数作用域。没有块作用域的概念。因此也有一系列的问题。

    ECMAScript 6(简称ES6)中新增了块级作用域。块作用域由{ }包括,if语句和for语句里面的{ }也属于块作用域。

    5. 是否能修改声明的变量?

    var和let可以。

              const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

    es6解构赋值

    解构赋值就是从目标对象或数组中提取自己想要的变量。最常用的场景是:element-ui,vant-ui按需引入,请求接口返回数据,提取想要数据。

    常见的几种方式有

    1.默认值

    2.交换变量

    3.将剩余数组赋给一个变量

    当结构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量

    4.给新的变量名赋值

    可以从一个对象中提取变量并赋值给和对象属性名不同的新的变量名

    箭头函数与普通函数的区别

    1、箭头函数是匿名函数,不能作为构造函数,不能使用new

    箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式:一种只包含一个表达式,连{ ... }return都省略掉。还有一种可以包含多条语句,这时候就不能省略{ ... }return

    2.箭头函数内没有arguments,可以用展开运算符…解决

    arguments:是一个方法调用的集合,是一个伪数组,不是真的数组,不具有数组的操作的方法,可以用展开运算解决(...)

    3.箭头函数的this,始终指向父级上下文(箭头函数的this取决于定义位置父级的上下文,跟使用位置没关系,普通函数this指向调用的那个对象)

    4.箭头函数不能通过call()、apply()、bind()方法直接修改它的this指向                                5.箭头函数没有原型属性

    class与class继承

    传统的javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其它传统面向对象语言来讲,独树一帜也可以说难以接受!

    ES5中如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成。

    构造函数生成实例的执行过程:

    1.当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;

    2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。

    3.执行构造函数的代码。

    4.返回新对象(后台直接返回);

    ES6中的类

    ES6引入了class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得javascript在对象写法上更加清晰,更像是一种面向对象的语言。

    注意项:

    1.在类中声明方法的时候,千万不要给该方法加上function关键字

    2.方法之间不要用逗号分隔,否则会报错

    ES5中的继承 (组合继承:原型链继承 + 借用构造函数)

    原型链继承:

    父类的实例作为子类的原型

    借用构造函数继承:

    在子类内,使用call()调用父类方法,并将父类的this修改为子类的this.相当于是把父类的实例属性复制了一份放到子类的函数内.

    组合继承:

    既能调用父类实例属性,又能调用父类原型属性

    promise使用及实现

    什么是promise

    promise是异步编程的一种方案,解决了地域名回调的问题,是一种链式调动的方式

    Promise 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

    promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。

    Promise是一个构造函数,对外提供统一的 API,自己身上有all、reject、resolve等方法,原型上有then、catch等方法。

    名词约定

    promise(首字母小写)对象指的是“Promise实例对象”

    Promise 首字母大写且单数形式,表示“Promise构造函数”

    Promises 首字母大写且复数形式,用于指代“Promises规范”

    Promise的两个特点

    Promise对象的状态不受外界影响

    1)pending 初始状态

    2)fulfilled 成功状态

    3)rejected 失败状态

    Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态

    Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成fulfilled或者由pending变成rejected

    使用 new 来创建一个promise对象。

    Promise接受一个「函数」作为参数,该函数的两个参数分别是resolve和reject。这两个函数就是就是「回调函数」

    resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

    reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去

    then()方法: then 方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。

    catch()方法: 当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中。

    all()方法: Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

    race()方法: race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。

    promise简单举例

    //Promise异步封装ajax

    async await

    Async 和 await 是一种同步的写法,但还是异步的操作,两个内容还是必须同时去写才会生效不然的话也是不会好使

    1.asayc的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数

    2.异步async函数调用,跟普通函数的使用方式一样

    3.异步async函数返回一个promise对象

    4.async函数配合await关键字使用(阻塞代码往下执行)是异步方法,但是阻塞式的

    优点:

    1.方便级联调用:即调用依次发生的场景;

    2.同步代码编写方式: Promise使用then函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;

    3.多个参数传递: Promise的then函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await没有这个限制,可以当做普通的局部变量来处理,用let或者const定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作;

    4.同步代码和异步代码可以一起编写: 使用Promise的时候最好将同步代码和异步代码放在不同的then节点中,这样结构更加清晰;async/await整个书写习惯都是同步的,不需要纠结同步和异步的区别,当然,异步过程需要包装成一个Promise对象放在await关键字后面;

    5.sync/await是对Promise的优化: async/await是基于Promise的,是进一步的一种优化,不过在写代码时,Promise本身的API出现得很少,很接近同步代码的写法;

    使用场景:async主要来处理异步的操作,
    需求:执行第一步,将执行第一步的结果返回给第二步使用。在ajax中先拿到一个接口的返回数据,然后使用第一步返回的数据执行第二步操作的接口调用,达到异步操作。

    Es6中新的数据类型symbol

    Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol

    类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

    注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于

    Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

    Git

    1. git init 初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件)
    2. git status 查看文件状态
    3. git add 文件列表 追踪文件
    4. git commit -m 提交信息 向仓库中提交代码
    5. git log 查看提交记录

    1.分支明细

    (1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。

    (2)开发分支(develop):作为开发的分支,基于 master 分支创建。

    (3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建

    2.分支命令

    (1)git branch 查看分支  

    (2)git branch 分支名称 创建分支

    (3)git checkout 分支名称 切换分支

    (4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支)

    (5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)

    3.暂时保存更改

    (1)存储临时改动:git stash

    (2)恢复改动:git stash pop

    多人冲突:

    是当前修改是左箭头方向,传入的是右箭头的方向,中间用等于号分割,等号上边是当前修改,下边是传入的修改。

    两人同时提交可能会出现冲突,解决办法是手动修改冲突

    http和https的区别

    1、HTTP是超文本传输协议,信息是明文传输,HTTPS是具有安全性的SSL加密传输协议。

    2、HTTPS协议需要ca申请证书,一般免费证书少,因而需要一定费用。

    3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样。前者是80,后者是443。

    4、HTTP连接是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,安全性高于HTTP协议。

    三次握手和四次挥手

    三次握手:

    第一次:建立连接时,客户端发送syn包到服务器,等待服务端确认

    第二次:服务器收到syn包,必须确认客户的syn,同时也发送一个syn包,即syn+ACK包

    第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack,发送完毕,客户端和服务端连接成功,完成三次握手

    四次挥手:

    第一次:浏览器发送完数据后,发送fin请求断开连接

    第二次:服务器发送ack到客户端,确认客户端的断开请求

    第三次:服务器请求断开fin的请求

    第四次:客户端确认服务器的断开ack

    使用基于token的登录流程

    使用基于 Token 的身份验证方法,大概的流程是这样的:

    1. 客户端使用用户名跟密码请求登录
    2. 服务端收到请求,去验证用户名与密码
    3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
    4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
    5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
    6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数

     Get和post的区别

    1. Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post提交的数据在HTTP包的请求包体中,对用户来说都是不可见的,相对安全。

      2、Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制。

      4、Get执行效率却比Post方法好。Get是form提交的默认方法。

      Ge和post的选择:

      1.私密性的信息请求使用post(如注册、登陆)。

      2.查询信息使用get。

    web安全及防护

    1. 1.XSS攻击原理:

      攻击者往Web页面里插入恶意 html标签或者javascript代码。

      用来窃取cookie中的用户信息

      解决:对一些输入的字符进行过滤,尽量采用post表单提交的方式。

      2.CSRF攻击(跨站请求伪造):

      登录受信任的网站A,并在本地生成Cookie,在不登出A的情况下,携带cookie去访问危险网站B

      解决:通过验证码的方式解决

      3.SQL注入攻击

      就是通过吧SQL命令插入到Web表单递交或输入域名,最终达到欺骗服务器执行恶意的SQL命令。

      解决:表单输入时通过正则表达式将一些特殊字符进行转换

    html和XML-

     html被称为超文本标记语言, 是一种描述性语言,用html 可以创建能在互联网上传输的信息页,是构成网页文档的主要语言,它是由很多的标签组成

    xml 即可扩展标记语言,是Internet环境中跨平台的、依赖于内容的技术,是当前处理结构化文档信息的有力工具,满足了Web内容发布与交换的需要,适合作为各种存储与共享的通用平台。

     都可以通过DOM  编程方式来访问。

     都可以通过CSS来改变外观。

     html和xml 都是标记语言,都是基于文本编辑和修改的。   

    xml不是要来取代html的,是对html的补充,用来与html协同工作的语言,基于上面这些优势,xml将来成为所有的数据处理和数据传输的常用工具非常可观。

    This的指向

    在js中this不是固定不变的,它会随着执行环境的改变而改变。要注意的是this取什么值,是在执行时确认的,定义时无法确认。

    this的调用大概分为五种场景:

    1.浏览器里,在全局范围内的this 指向window对象;

    2.在函数中,this永远指向最后调用他的那个对象;

    3.构造函数中,this指向new出来的那个新的对象;

    4.Call、apply、bind中的this被强绑定在指定的那个对象上;

    5.箭头函数中this比较特殊,箭头函数this为父作用域的this,不是调用时的this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来;

    call:参数是单个使用的,
    apply:参数是一个集合时使用,
    bind:使用bind会改变this,不会改变数据,需要在调用的地方加一个括号

    箭头函数与普通函数的区别

    一.外形不同:箭头函数使用箭头定义,普通函数中没有使用function定义

    二.箭头函数是匿名函数普通函数可以有匿名函数,也可以有具名函数,但是箭头函数都是匿名函数。

    三.箭头函数不能用于构造函数,不能使用new普通函数可以用于构造函数,以此创建对象实例。

    四.箭头函数中this的指向不同
    在普通函数中,this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。
    1.箭头函数本身不创建this
    也可以说箭头函数本身没有this,但是它在声明时可以捕获其所在上下文的this供自己使用。

    2.结合call(),apply()方法使用
    箭头函数结合call(),apply()方法调用一个函数时,只传入一个参数对this没有影响。

    3.箭头函数不绑定arguments,取而代之用rest参数…解决
    每一个普通函数调用后都具有一个arguments对象,用来存储实际传递的参数。但是箭头函数并没有此对象。

    4.其他区别

    (1).箭头函数不能Generator函数,不能使用yeild关键字。

    (2).箭头函数不具有prototype原型对象。

    (3).箭头函数不具有super。

    (4).箭头函数不具有new.target。

    总结:

    (1).箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()

    (2).普通函数的this指向调用它的那个对象

    localStorage、sessionStorage 和 Cookie 区别及用法

    区别

    localStorage: localStorage 的生命周期是永久的,关闭页面或浏览器之后 localStorage 中的数据也不会消失。localStorage 除非主动删除数据,否则数据永远不会消失

    sessionStorage: sessionStorage 的生命周期是仅在当前会话下有效。sessionStorage 引入了一个“浏览器窗口”的概念,sessionStorage 是在同源的窗口中始终存在的数据。只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源另一个页面,数据依然存在。但是 sessionStorage 在关闭了浏览器窗口后就会被销毁。同时独立的打开同一个窗口同一个页面,sessionStorage 也是不一样的

    cookie: cookie生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。 存放数据大小为4K左右, 有个数限制(各浏览器不同),一般不能超过20个。缺点是不能储存大数据且不易读取

    建议

    由于 vue 是单页面应用,操作都是在一个页面跳转路由,因此 sessionStorage 较为合适

    原因:sessionStorage 可以保证打开页面时 sessionStorage 的数据为空

    每次打开页面 localStorage 存储着上一次打开页面的数据,因此需要清空之前的数据

    你可能感兴趣的:(vue.js,前端,javascript)