前端面试基础问题

1.Css中对盒子模型如何理解

CSS css盒子模型 又称框模型 (Box Model) 包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素,边框内包括element元素,元素有height和width

前端面试基础问题_第1张图片

图中最内部的框是元素的实际内容,也就是元素框,紧挨着元素框外部的是内边距padding,其次是边框(border),然后最外层是外边距(margin),整个构成了框模型。通常我们设置的背景显示区域,就是内容、内边距、边框这一块范围。而外边距margin是透明的,不会遮挡周边的其他元素。

那么,元素框的总宽度 = 元素(element)的width + padding的左边距和右边距的值 + margin的左边距和右边距的值 + border的左右宽度;

元素框的总高度 = 元素(element)的height + padding的上下边距的值 + margin的上下边距的值 + border的上下宽度。

margin越界(第一个子元素的margin-top和最后一个子元素的margin-bottom的越界问题)

以第一个子元素的margin-top 为例:

当父元素没有边框border时,设置第一个子元素的margin-top值的时候,会出现margin-top值加在父元素上的现象,解决方法有四个:

(1)给父元素加边框border (副作用)

(2)给父元素设置padding值 (副作用)

(3)父元素添加 overflow:hidden (副作用)

(4)父元素加前置内容生成。(推荐)

用盒子模型画三角形

前端面试基础问题_第2张图片

2.Js中new做了什么操作?

(1) 创建一个新对象;

(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;

(3) 执行构造函数中的代码(为这个新对象添加属性) ;

(4) 返回新对象。

var obj = ``new Base();

new操作符具体干了什么呢?其实很简单,就干了三件事情。

var obj = {};

obj.__proto__ = Base.prototype;

Base.call(obj);

第一行,我们创建了一个空对象obj
第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
第三行,我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”base”,关于call函数的用法。

3.闭包如何理解?闭包的优缺点?

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

javascript语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

function f1(){

var n=999;

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

}

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。

这就是Javascript语言特有的"链式作用域"结构(chain scope),

子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

上面代码中的f2函数,就是闭包。

各种专业文献的闭包定义都非常抽象,我的理解是: 闭包就是能够读取其他函数内部变量的函数。

由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。

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

闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

使用闭包的注意点

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

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

坑点1: 引用的变量可能发生变化
坑点2: this指向问题
var object = {
     
     name: ''object",
     getName: function() {
     
        return function() {
     
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined

因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows

坑点3:内存泄露问题
function  showId() {
     
    var el = document.getElementById("app")
    el.onclick = function(){
     
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
}

// 改成下面
function  showId() {
     
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
     
      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
    el = null    // 主动释放el
}

4.Vue中数据双向绑定的原理?

创建属性

如果对象中不存在指定的属性,Object.defineProperty()就创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。拥有布尔值的字段的默认值都是falsevalue,get和set字段的默认值为undefined。定义属性时如果没有get/set/value/writable,那它被归类为数据描述符。

var o = {
     }; // 创建一个新对象

// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
     
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});

// 对象o拥有了属性a,值为37

// 在对象中添加一个属性与存取描述符的示例
var bValue;
Object.defineProperty(o, "b", {
     
  get : function(){
     
    return bValue;
  },
  set : function(newValue){
     
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

o.b = 38;
// 对象o拥有了属性b,值为38

// o.b的值现在总是与bValue相同,除非重新定义o.b

// 数据描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
     
  value: 0x9f91102, 
  get: function() {
      
    return 0xdeadbeef; 
  } 
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

整理了一下,要实现mvvm的双向绑定,就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者

简单实现
<body>
<div id="app">
    <input type="text" id="txt">
    <p id="show-txt">p>
div>
<script>
    var obj = {
      }
    Object.defineProperty(obj, 'txt', {
      
        get: function () {
      
            return obj
        },
        set: function (newValue) {
      
            document.getElementById('txt').value = newValue
            document.getElementById('show-txt').innerHTML = newValue
        }
    })
    document.addEventListener('keyup', function (e) {
      
        obj.txt = e.target.value
    })
script>
body>

5.组件间传值方式?

子组件向父组件传值:通过绑定时间然后$emit传值
父组件向子组件传值:子组件使用props接收父组件传过来的数据

可以通过parent和​children获取父子组件参数

兄弟之间传值可以通过Vuex
父组件调用子组件的方法ref
<children :message="message">children>
//父组件中
props:{
     
     message:String
}
//子组件
$children[i].params

this.$parent.params
methods:{
     childMethod(){
          alert("我是子组件的方法");
     }
}
//子组件
<template>
     <child ref="child">child>
     <div @click="parentMethod">div>
template>
methods:{
     parentMethod(){
          this.$refs.child.childMethod();
     }
}
//父组件

通过npm加载vuex,创建store.js文件,然后在main.js中引入,store.js文件代码如下:

 import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex);
  const state = {
     
    author:'Wise Wang'
  };
  const mutations = {
     
    newAuthor(state,msg){
     
      state.author = msg
    }
  }
  export default  new Vuex.Store({
     
    state,
    mutations
  })

父组件parent代码

<template>
    <div class="parent">
      <h2>{
     {
      msg }}</h2>
      <p>父组件接手到的内容:{
     {
      username }}</p>
      <input type="text" v-model="inputTxt">
      <button @click="setAuthor">传参</button>
      <son psMsg="父传子的内容:叫爸爸" @transfer="getUser"></son>
    </div>
  </template>
  <script>
  import son from './Son'
  export default {
     
    name: 'HelloWorld',
    data () {
     
      return {
     
        msg: '父组件',
        username:'',
        inputTxt:''
      }
    },
    components:{
     son},
    methods:{
     
      getUser(msg){
     
        this.username= msg
      },
      setAuthor:function () {
     
        this.$store.commit('newAuthor',this.inputTxt)
      }
    }
  }
  </script>

子组件son代码

<template>
    <div class="son">
      <p>{
     {
      sonMsg }}</p>
      <p>子组件接收到内容:{
     {
      psMsg }}</p>
      <p>这本书的作者是:{
     {
      $store.state.author }}</p>
      <!--<input type="text" v-model="user" @change="setUser">-->
      <button @click="setUser">传值</button>
      </div>
  </template>
  <script>
  export default {
     
    name: "son",
    data(){
     
      return {
     
        sonMsg:'子组件',
        user:'子传父的内容'
      }
    },
    props:['psMsg'],
    methods:{
     
      setUser:function(){
     
        this.$emit('transfer',this.user)
      }
    }
  }
  </script>

前端面试基础问题_第3张图片

6.Http中cookie和session的区别?

1、cookie 和session的区别是:cookie数据保存在客户端,session数据保存在服务器端。

2、两个都bai可以用来存私密的东西,同样也都有有效期的说法,区别在于session是放在服务器上的,过期与否取决于服务期的设定,cookie是存在客户端的,过去与否可以在cookie生成的时候设置进去。

(1)、cookie数据存放在客户的浏览器上,session数据放在服务器上 ;

(2)、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session ;

(3)、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE ;

(4)、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K;

(5)、所以将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中。

3、cookie和session的共同之处在于:cookie和session都是用来跟踪浏览器用户身份的会话方式。

4、cookie 是一种发送到客户浏览器的文本串句柄,并保存在客户机硬盘上,可以用来在某个WEB站点会话间持久的保持数据。

7.get与post的区别?

一、功能不同

1、get是从服务器上获取数据。

2、post是向服务器传zhuan送数据。

二、过程不同
1、get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。

2、post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。

三、获取值不同

1、对于get方式,服务器端用Request.QueryString获取变量的值。

2、对于post方式,服务器端用Request.Form获取提交的数据。

四、传送数据量不同

1、get传送的数据量较小,不能大于2KB。

2、post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。

五、安全性不同

1、get安全性非常低。

2、post安全性较高。

如果没有加密,他们安全级别都是一样的,随便一个监听器都可以把所有的数据监听到。

https://www.zhihu.com/question/28586791细节

8.Linux指令用过哪些?查看日志有什么指令?

1.查看日志常用命令

tail:

​ -n 是显示行号;相当于nl命令;例子如下:

​ tail -100f test.log 实时监控100行日志

​ tail -n 10 test.log 查询日志尾部最后10行的日志;

​ tail -n +10 test.log 查询10行之后的所有日志;

head:

​ 跟tail是相反的,tail是看后多少行日志;例子如下:

​ head -n 10 test.log 查询日志文件中的头10行日志;

​ head -n -10 test.log 查询日志文件除了最后10行的其他所有日志;

cat:

​ tac是倒序查看,是cat单词反写;例子如下:

​ cat -n test.log |grep “debug” 查询关键字的日志

\2. 应用场景一:按行号查看—过滤出关键字附近的日志

1)cat -n test.log |grep “debug” 得到关键日志的行号

2)cat -n test.log |tail -n +92|head -n 20 选择关键字所在的中间一行. 然后查看这个关键字前10行和后10行的日志:

​ tail -n +92表示查询92行之后的日志

​ head -n 20 则表示在前面的查询结果里再查前20条记录

\3. 应用场景二:根据日期查询日志

sed -n ‘/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p’ test.log

特别说明:上面的两个日期必须是日志中打印出来的日志,否则无效;

​ 先 grep ‘2014-12-17 16:17:20’ test.log 来确定日志中是否有该 时间点

4.应用场景三:日志内容特别多,打印在屏幕上不方便查看

(1)使用more和less命令,

​ 如: cat -n test.log |grep “debug” |more 这样就分页打印了,通过点击空格键翻页

(2)使用 >xxx.txt 将其保存到文件中,到时可以拉下这个文件分析

​ 如:cat -n test.log |grep “debug” >debug.txt

9.position有哪些属性,有什么区别

position有四种属性分别为:静态定位,相对定位,绝对定位,固定定位

static:固定定位,是position的默认属性值,如果没有声明position就会以这个属性进行布局,即按照码源的顺序来放置元素。

relative:相对定位是相对于static的位置进行偏移。比如left:20

absolute:绝对定位,一般是相对于其父级的元素进行偏移

fixed:固定定位,相对于浏览器窗口,用了这个属性,在页面滚动的时候,对应的元素不会随着页面滚动

static
元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。
relative
元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。
absolute
元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。
fixed
元素框的表现类似于将 position 设置为 absolute,不过其包含块是视窗本身。
提示:相对定位实际上被看作普通流定位模型的一部分,因为元素的位置相对于它在普通流中的位置。

这里要注意一点,设置position:relative的时候,原来的dom空间还保留着,相当于滑动一段距离。

relative 是相对于父级原始点进行定位,如果父级没有,则往上走,最终和body定位。

absolute 是跳出文档流,相对于父级定位,若父级没有position , 则往上级找有position属性的元素,若都没有,则和body定位。

10.AMD和CMD的区别

最明显的区别就是在模块定义时对依赖的处理不同

1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
2、CMD推崇就近依赖,只有在用到某个模块的时候再去require
这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同

很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略

为什么我们说两个的区别是依赖模块执行时机不同,为什么很多人认为ADM是异步的,CMD是同步的(除了名字的原因。。。)

**同样都是异步加载模块,**AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行

CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的

这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因

11.事件触发的模式

触发方式一(行内绑定):标签内 οnclick=“func()” 没有event

触发方式二(事件监听):添加事件监听 addEventListener() 有event

兼容性不好,ie是attachEvent()

触发方式三(动态绑定):obj.οnclick=func; 有event

一、入侵式触发方式


二、非入侵式触发方式

    






    

三、区别

1.非入侵式触发方式如果JS在标签里时要先写Window.οnlοad=function(){},因为HTML代码是顺序代码,由上往下读取,如果不写。在代码读取时如果没有获取到ID,它将自动忽略掉,JS写在是有标签后面时可以不写。

2.入侵式触发方式则不论JS写在那儿都不需要写Window.οnlοad=function(){},因为它不是由ID来确认谁执行事件,而是由标签自己去调方法。

12.为什么link用href获取资源 script和img用src

我们都知道,内联的JavaScript是在页面的 标签内添加,内联的样式是在 标签内添加;而外部共享的JavaScript文件,则是通过 来引入,共享的样式文件不是通过 的形式引入,而是通过 形式引入,这是为什么呢?

w3c最初的设计中

href是引用和页面关联,是在当前元素和引用资源之间建立联系,src表示引用资源,表示替换当前元素,用在img,script,iframe上,src是页面内容不可缺少的一部分。

当浏览器解析到这一句的时候会暂停其他资源的下载和处理,直至将该资源加载,编译,执行完毕,图片和框架等元素也是如此,类似于该元素所指向的资源嵌套如当前标签内,这也是为什么要把放在底部而不是头部。 当浏览器解析到这一句的时候会识别该文档为css文件,会下载并且不会停止对当前文档的处理,这也是为什么建议使用link方式来加载css而不是使用@import。

src 的内bai容,是页面必不可少的一部分,是引入。href 的内容,是与该页面有关联,是引用。区别就是,引入和引用。

13.js数据类型,区别

JS中分为两个数据类型,分别为基本数据类型和引用数据类型

基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象。

当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值。

Number、String 、Boolean、Null和Undefined。基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值。示例:

var a = 10;

var b = a;

b = 20;

console.log(a); // 10值

上面,b获取的是a值得一份拷贝,虽然,两个变量的值相等,但是两个变量保存了两个不同的基本数据类型值。

b只是保存了a复制的一个副本。所以,b的改变,对a没有影响。

前端面试基础问题_第4张图片

a 声明变量时不同的内存分配:

1)原始值:存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置

这是因为这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 – 栈中。这样存储便于迅速查寻变量的值。

2)引用值:存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存地址。

这是因为:引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。

地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。

b 不同的内存分配机制也带来了不同的访问机制

1)在javascript中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,

首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,这就是传说中的按引用访问

2)而原始类型的值则是可以直接访问到的。

c 复制变量时的不同

1)原始值:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。

2)引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,

也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。

(这里要理解的一点就是,复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量罢了)。多了一个指针

d 参数传递的不同(*把实参复制给形参的过程*

首先我们应该明确一点:ECMAScript中所有函数的参数都是按值来传递的。

但是为什么涉及到原始类型与引用类型的值时仍然有区别呢?还不就是因为内存分配时的差别。

1)原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。

2)引用值:对象变量它里面的值是这个对象在堆内存中的内存地址,这一点你要时刻铭记在心!

因此它传递的值也就是这个内存地址,这也就是为什么函数内部对这个参数的修改会体现在外部的原因了,因为它们都指向同一个对象。

14.事件循环

首先,事件循环从宏任务 (macrotask) 队列开始,最初始,宏任务队列中,只有一个 scrip t(整体代码)任务;当遇到任务源 (task source) 时,则会先分发任务到对应的任务队列中去。所以,就和上面例子类似,首先遇到了console.log,输出 script start; 接着往下走,遇到 setTimeout 任务源,将其分发到任务队列中去,记为 timeout1; 接着遇到 promise,new promise 中的代码立即执行,输出 promise1, 然后执行 resolve ,遇到 setTimeout ,将其分发到任务队列中去,记为 timemout2, 将其 then 分发到微任务队列中去,记为 then1; 接着遇到 console.log 代码,直接输出 script end 接着检查微任务队列,发现有个 then1 微任务,执行,输出then1 再检查微任务队列,发现已经清空,则开始检查宏任务队列,执行 timeout1,输出 timeout1; 接着执行 timeout2,输出 timeout2 至此,所有的都队列都已清空,执行完毕。其输出的顺序依次是:script start, promise1, script end, then1, timeout1, timeout2

前端面试基础问题_第5张图片

JS引擎是单线程,负责执行JS代码的。

  1. JS分为同步任务和异步任务

  2. 同步任务都在主线程上执行,形成一个执行栈

  3. 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。

  4. 一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

    前端面试基础问题_第6张图片

在进程启动时,便会创建一个类似于while(true)的循环,每执行一次循环体的过程我们称为Tick。每个Tick的过程就是查看是否有事件待处理,如果有,就取出事件及其相关的回调函数。如果存在关联的回调函数,就执行它们。

前端面试基础问题_第7张图片

上图大致描述就是:

  1. 主线程运行时会产生执行栈,

栈中的代码调用某些api时,它们会在事件队列中添加各种事件(当满足触发条件后,如ajax请求完毕)

  1. 而栈中的代码执行完毕,就会读取事件队列中的事件,去执行那些回调
  2. 如此循环
  3. 注意,总是要等待栈中的代码执行完毕后才会去读取事件队列中的事件

再根据线程来理解下:

宏任务都是放在一个事件队列中的,而这个队列由事件触发线程维护

微任务都是添加到微任务队列(Job Queues)中,等待当前宏任务执行完毕后执行,而这个队列由JS引擎线程维护

所以,总结下运行机制:

  1. 执行一个宏任务(栈中没有就从事件队列中获取)
  2. 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  3. 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  4. 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  5. 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

前端面试基础问题_第8张图片

JS哪些API是宏任务,哪些是微任务?

宏任务(macrotask)::

setTimeout、setInterval、postMessage、 MessageChannel、setImmediate

微任务(microtask):

Promise().then()、 MutaionObserver、process.nextTick(Node.js环境)

15.call appy bind的作用和区别

同:三者都是改变函数执行时的上下文,说人话就是改变this的指向。

异:

1、bind()返回的其实是一个函数,并不会立即执行。

2、call()、apply()第二个参数有区别,call()的是一个值作为第二个参数,apply()的第二个参数则是一个数组:

1. call方法
  • 作用:专门用于修改方法内部的 this 指向
  • 格式:xxx.call( 对象名, 参数1, 参数2 , ...);。即:将 xxx 方法的 this 指向为 对象名
  • 实例:
    function test(a,b){
     
        console.log(this);
        console.log(a + b);
    }
    test(1,2);  //  window  3
    var obj = {
     name:'zjy'};
    window.test.call(obj,3,5);  //  {name:'zjy'} 8

解析:没有使用 call 方法时,test方法的this指向全局对象window,而当使用了call方法后,将test的this指向从window变成了obj对象,而后面的参数则是对应方法的形参顺序


2. apply方法
  • 作用:和call方法一样也是修改方法内部的 this指向的,它们的区别在于apply的第二个参数必须为一个数组(部署了Iterator接口的类数组对象也可以)
  • 格式:xxx.apply( 对象名, [数组]);。即:将 xxx 方法的 this 指向为 对象名,数组中的元素依次与方法的形参对应
  • 实例:
    function test(a,b){
     
        console.log(this);
        console.log(a + b);
    }
    test(1,2);  //  window  3
    var obj = {
     name:'zjy'};
    window.test.apply(obj,[3,5]);  //  {name:'zjy'} 8

解析:没有使用 apply 方法时,test方法的this指向全局对象window,而当使用了apply方法后,将test的this指向从window变成了obj对象,而后面的数组参数则是将数组中元素依次对应到test方法形参的位置


3. bind方法
  • 作用:也是改变this的指向问题
  • 格式:xxx.bind( 对象名 , 参数1, 参数2 , ...);。即:将 xxx 方法的 this 指向为 对象名
  • 实例:
    var obj = {
     key:"value"}
    var foo = function(){
     
        console.log(this)
    }
    foo.bind(obj)()  //  obj

解析:在没有使用bind方法时,foo()中的this指向的是全局对象window,而使用了bind方法之后则指向的是obj对象

16. 前后端跨域(CSP,CORS)

1.CORS & CSP

浏览器跨域相关的安全策略主要存在于两个方面:

  1. 浏览器是否发送ajax
  2. 浏览器是否加载返回数据

假设从a.com 向b.com发送ajax请求。此时浏览器当前页面为a.com,浏览器发送ajax,去获取b.com的资源。具体请求过程如下:

  1. a.com通过添加 Content-Security-Policy头设置CSP策略来限制请求是否发出。浏览器发送获取资源请求之前,先读取当前页面的Content-Security-Policy参数,检查请求目的地址b.com是否符合CSP策略,如果符合则发出该ajax请求,如果不符合,则丢弃该请求并报CSP 错误。

     * Content-Security-Policy: default-src 'self' 仅仅允许访问当前域名,无法发送
     * Content-Security-Policy: *.b.com 允许发送
    
  2. b.com通过设置跨域资源共享CORS策略来限制浏览器是否加载b.com返回的数据。 浏览器成功发送ajax给b.com后,b.com收到请求并返回带有Access-Control-Allow-Origin头的数据包,浏览器先检查a.com是否在Access-Control-Allow-Origin允许范围之内,如果不在,则报CORS错误并不在当前页面加载这次返回的数据。实际上,不管b.com是否配置CORS头,浏览器此时都收到了完整的数据包,浏览器只是通过CORS策略来决定是否呈现返回的数据。

     * Access-Control-Allow-Origin * 允许加载任意来源请求,请求成功
     * Access-Control-Allow-Origin http://c.com 只允许来自c.com的请求,请求失败
    

Origin header注意点:
Origin header是浏览器添加的。如果一个request中,有origin header,并不一定是一次跨域请求,但是所有跨域请求都 会包含origin header.
Refer: https://stackoverflow.com/questions/15988323/cors-and-origin-header

IE10以下不支持CORS

17.http1.x 和http2.x区别

(1).HTTP2使用的是二进制传送,HTTP1.X是文本(字符串)传送。

二进制传送的单位是帧和流。帧组成了流,同时流还有流ID标示

(2).HTTP2支持多路复用

因为有流ID,所以通过同一个http请求实现多个http请求传输变成了可能,可以通过流ID来标示究竟是哪个流从而定位到是哪个http请求

(3).HTTP2头部压缩

HTTP2通过gzip和compress压缩头部然后再发送,同时客户端和服务器端同时维护一张头信息表,所有字段都记录在这张表中,这样后面每次传输只需要传输表里面的索引Id就行,通过索引ID查询表头的值

(4).HTTP2支持服务器推送

HTTP2支持在未经客户端许可的情况下,主动向客户端推送内容

18.http和https

一、HTTP和HTTPS的基本概念

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

二、HTTP与HTTPS有什么区别?

HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

HTTPS和HTTP的区别主要如下:

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议

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

4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

19.url输入到渲染的过程

域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

20.强缓存,协商缓存

HTTP Cache 是我们开发中接触最多的缓存,它分为强缓存和协商缓存。

  1. 强缓存:直接从本地副本比对读取,不去请求服务器,返回的状态码是 200
  2. 协商缓存:会去服务器比对,若没改变才直接读取本地缓存,返回的状态码是 304

21.http常见的状态码

2开头 (请求成功)表示成功处理了请求的状态代码。

200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。

3开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

4开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。

400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。

5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

22.VUE生命周期,哪个阶段可以操作DOM?

什么阶段才能调用DOM

在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。

什么阶段能发起请求

  • 可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
  • 但是推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
    • 能更快获取到服务端数据,减少页面loading 时间;
    • ssr不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;

23.讲讲hash模式与history模式区别?

vue-router有两种模式,hash模式和history模式

1.首先router有两种模式:hash模式(默认)、history模式(需配置mode: ‘history’)

​ hash和history的区别?

hash history
url显示 有# 无#
回车刷新 可以加载到hash值对应页面 一般就是404掉了
支持版本 支持低版本和IE浏览器 HTML5新推出的API

正确回答:hash模式url里面永远带着#号,我们在开发中默认使用这个模式。那么在声明时候要用history模式呢?

如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或者react做的,咋们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人员配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就可以了。

24.keep-alive 缓存已渲染过的组件

是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似, 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

prop:

  • include: 字符串或正则表达式。只有匹配的组件会被缓存。
  • exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。

25.如何获取hash变化?

步骤: 1、获取iframe节点 2、获取iframe中的变量 示例 a.htmlb.html var y=‘1’;在a.html中获取y,则可以通过以下方式document.frames[‘x’].y //先获取frame,在获取y

项目中使用AntdUI组件+react 里面使用了menu组件管理目录结构,不同目录组件页面之中有点击按钮进行不同目录的跳转,因为是各种组件的关系,点击各组件后准确跳转到目标页面没有问题,但是左侧目录结构不能进行有效的收缩和展开的动作,故使用js来监听URL的hash变化的方式进行接下来的逻辑行为

原理:监视hash的变化 onhashchange事件

兼容:

Gecko 1.9.2 (Firefox 3.6/Thunderbird 3.1/Fennec 1.0)

IE 8

WebKit 528+ (Safari/Google Chrome)

Opera 10.70

备用方法:定时器(频繁的定时器,隐患很大)

秉承不应基于浏览器检测,而应基于对象和方法检测的 原则,可用 if(‘onhashchange’ in window) { } 检测浏览器是否支持onhashchange。这里不能用 typeof window.onhashchange === ‘undefined’ 来检测,因为很多支持onhashchange的浏览器下,其初始值就是undefined。

需要注意的是,在IE8以ie7的模式运行时,window下存在onhashchange这个方法,但是永远不会触发这个事件,因此需要先检测IE的document.documentMode。

综上所述,采取比较完善方式的代码片段:

if( ("onhashchange" in window) && ((typeof document.documentMode==="undefined") || document.documentMode==8)) {
    // 浏览器支持onhashchange事件
    window.onhashchange = hashChangeFire;  // TODO,对应新的hash执行的操作函数
} else {
    // 不支持则用定时器检测的办法
    setInterval(function() {
        var ischanged = isHashChanged();  // TODO,检测hash值或其中某一段是否更改的函数
        if(ischanged) {
            hashChangeFire();  // TODO,对应新的hash执行的操作函数
        }
    }, 150);
}functionhashChangeFire(){ alert("URL产生了变化") } 

26.webpack常见的配置项

使用vue init webpack test(项目文件夹名)命令初始化一个vue项目,cd test,然后安装依赖npm install之后会生成一些默认的文件夹和文件,这些文件和文件夹中有些和配置有关的。如果去专门的了解webpack一定会云里雾里,这里简单说明一下常用的配置。

1.babelrc文件

这个文件放在根目录下面设置转码规则的。
例如要想在代码中使用es6,就要在这个文件中配置"presets": [“es2015”]。
在项目代码中要使用jsx语法除了安装babel-plugin-transform-vue-jsx插件之外,还要配置"plugins": [“transform-runtime”, “transform-vue-jsx”]。

2…editorconfig文件

这个文件配置编辑器的编码风格,目前本人还没有修改过。

3…eslintrc.js文件

这个文件放在根目录下面是负责代码规范,引入插件的。例如:

[复制代码](javascript:void(0)

"globals": {
  "plus": true,
  "alert": true,
  "xhook": true,
  "sessionStorage": true,
  "AlloyFingerVue": true,
  "FastClick": true,
  "_": true,  "IScroll": true,  'Swiper': true}

[复制代码](javascript:void(0)

这一段是用来允许使用第三方插件中的函数,如下举例
比如我们使用HBuilder打包程序,用到一些扩展,使用plus.downloader.createDownload下载,plus.runtime.version获取app当前版本等,所以配置"plus": true,然后在在代码中可以直接使用plus.xxxx。
在项目调试的时候有时候用到alert,所以配置"alert": true,然后在代码中可以直接使用alert()语句。
使用xhook拦截器,所以配置"xhook": true,在index.html中引入xhook插件,然后可以在代码中直接使用并使用new IScroll语句。
在项目中想使用Swiper,所以配置,在msite.vue中引入js和css文件,import ‘./…/…/…/static/swiper/swiper.min.css’,import ‘./…/…/…/static/swiper/swiper.min’,然后可以在代码中直接使用this.swiper = new Swiper语句

如果在项目中js语句后面不加分号可以这样配置:“semi”: 0,当时webstorm有警告提醒:Unterminated statement,这是可以修改webstorm配置,如下图:,如果必须加则是:‘semi’:[‘error’,‘always’]

4…eslintignore文件

想要引入三方js库,但是这些库不符合eslint规范,可以在这个文件里忽略掉,例如:

build/*.js
config/*.js
static

5…gitignore文件

这个文件用于配置不需要加入版本管理的文件,例如:

[复制代码](javascript:void(0)

.DS_Store
node_modules/
npm-debug.log
test/unit/coverage
test/e2e/reports
selenium-debug.log
.idea
/clear
/src/modules/cache.js

[复制代码](javascript:void(0)

6.package.json文件

这个文件主要用来配置项目要用到的依赖插件,这个文件一般不会手动更改,而是使用npm install xxxx 来安装插件,然后这个文件自动被修改。scripts节点配置命令的执行文件。运行npm run dev执行build/dev-server.js,运行npm run build的时候执行待是build/build.js文件。如下:

[复制代码](javascript:void(0)

{
  "name": "test",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "xxx",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js",
    "unit": "karma start test/unit/karma.conf.js --single-run",
    "e2e": "node test/e2e/runner.js",
    "test": "npm run unit && npm run e2e",
    "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
  },
  "dependencies": {
    "date-fns": "^1.22.0",
    "echarts": "^3.4.0",
    "element-ui": "^1.1.2",  ......
  },
  "devDependencies": {
    "autoprefixer": "^6.6.1",
    "babel-core": "^6.21.0",
    "babel-eslint": "^7.1.1",  ... ...
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  }
}

[复制代码](javascript:void(0)

7.build/build.js文件

执行打包命令的时候会执行这个文件,然后不知所云

8.build/check-versions.js文件

检查版本?不知所云

9.build/dev-client.js文件

不知所云

10.build/dev-server.js文件

app.use(staticPath, express.static(’./static’))这句是指向static目录。执行npm run dev的时候最先执行build/dev-server.js文件,这个文件主要完成下面几个事情:

  1. 检查node的npm待版本,引入插件和配置
  2. webpack对源码进行编译打包并返回compiler对象

11.build/utils.js文件

不知所云

12.build/vue-loader.conf.js文件

不知所云

13.build/webpack.base.conf.js文件

1.配置项目入口文件,如下:

  entry: {
    app: './src/main.js',
    global: './src/window-global.js'
  }

这样就有两个入口,在window-global.js中可以定义全局变量,在整个项目中都可以使用,比如ajaxBaseUrl: ‘http://192.168.1.36:8080/’,在后在接口文件中使用,很方便

var instance = axios.create({
  baseURL: window.global.ajaxBaseUrl + 'api/system/subSystem',
  timeout: window.global.timeout
  // headers: {'X-Custom-Header': 'foobar'}
})

14.build/webpack.dev.conf.js文件

配置devtool选项更改打包方式。

15.build/webpack.prod.conf.js文件

(1)打包的时候报错:FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory,说内存不够,可以修改打包配置,就是npm run build生成静态文件时候用到的配置,减少内存消耗。
修改sourceMap配置成false可以在打包后不再生成map文件,如下:

[复制代码](javascript:void(0)

    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: false
    })

[复制代码](javascript:void(0)

dist/static/js目录下没有map文件了

(2)还可以修改node_modules.bin\webpack.cmd文件添加内存配置项

16.build/webpack.test.conf.js文件

不知所云。

17.config/dev.env.js文件

不知所云。

18.config/index.js文件

\1. 打包目录

配置打包目录,index文件,打包后的js文件路径等,如下,打包后的文件放在dist目录下面,入口文件是index.html

27.css3的动画有哪几种

css实现动画主要有3种方式,第一种是:transition实现渐变动画,第二种是:transform转变动画,第三种是:animation实现自定义动画,下面具体讲一下3种动画的实现方式。

Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息 [1] 。

28.理解HTTPS及其加密原理

https的请求过程
客户端向服务器发起连接请求;
服务端接收到请求之后,向客户端返回公有秘钥以及证书;
客户端在收到公有秘钥之后会随机的生成一个数串,并以此作为共享秘钥;
客户端用公有秘钥对共享秘钥进行加密,并发送给服务端;
服务端接收到之后,用私钥对接收到了内容进行解密,得到一个随机的数串,并此次生成共享秘钥。此时,客户端和服务端就拥有了共同的共享秘钥,那么就可以使用共享秘钥进行安全的通信了;
服务端对响应进行加密,客户端对报文进行解密。
加密算法
对称加密算法:加密和解密使用相同的秘钥。相对于非对称加密具有更高的加密解密速度,但秘钥在传输过程中可能会被窃取,因此安全性相对于非对称加密就比较低;
非对称加密算法:接收方在发送消息之前,会提前生成公钥和私钥,把公钥发送给发送方。发送方收到公钥之后,将带发送的数据用共钥加密发送给接收方。接收到接收到数据之后,用私钥对其进行解密。在这个过程中,公钥负责加密,私钥负责解密,数据在传输过程中即使被拦截,攻击者也没有私钥,因此无法破解。它的加解密速度低于对称加密算法,但是安全性更高。

29.Git 常用命令

命令

简要说明

git add添加至暂存区

git add–interactive交互式添加

git apply应用补丁

git am应用邮件格式补丁

git annotate同义词,等同于 git blame

git archive文件归档打包

git bisect二分查找

git blame文件逐行追溯

git branch分支管理

git cat-file版本库对象研究工具

git checkout检出到工作区、切换或创建分支

git cherry-pick提交拣选

git citool图形化提交,相当于 git gui 命令

git clean清除工作区未跟踪文件

git clone克隆版本库

git commit提交

git config查询和修改配置

git describe通过里程碑直观地显示提交ID

git diff差异比较

git difftool调用图形化差异比较工具

git fetch获取远程版本库的提交

git format-patch创建邮件格式的补丁文件。参见 git am 命令

git grep文件内容搜索定位工具

git gui基于Tcl/Tk的图形化工具,侧重提交等操作

git help帮助

git init版本库初始化

git init-db*同义词,等同于 git init

git log显示提交日志

git merge分支合并

git mergetool图形化冲突解决

git mv重命名

git pull拉回远程版本库的提交

git push推送至远程版本库

git rebase分支变基

git rebase–interactive交互式分支变基

git reflog分支等引用变更记录管理

git remote远程版本库管理

git repo-config*同义词,等同于 git config

git reset重置改变分支“游标”指向

git rev-parse将各种引用表示法转换为哈希值等

git revert反转提交

git rm删除文件

git show显示各种类型的对象

git stage*同义词,等同于 git add

git stash保存和恢复进度

git status显示工作区文件状态

git tag里程碑管理

30.css样式冲突问题(vue中scoped的原理)

vue中scoped的作用:

实现组件的私有化, 当前style属性只属于当前模块.

但是当我们使用公共组件的时候会造成很多困难.

scoped的实现原理:

在DOM结构中可以发现,vue通过在DOM结构以及css样式上加了唯一标记,达到样式私有化,不污染全局的作用,

img

img

可以看出,加上scoped后的组件里的会多 data-v-5db9451a 属性, css样式中可以看出;

1. 给DOM节点加一个不重复属性 data-v-5db9451a 标志唯一性.

2. 使每个样式选择器后添加类似于"不重复属性"的字段, 类似于作用域的作用,不影响全局.

3. 如果组件内部还有组件,只会给最外层的组件里的标签加上唯一属性字段,不影响组件内部引用的组件.

谨慎使用:

1. 父组件无scoped属性,子组件带有scoped,父组件是无法操作子组件的.

2. 父组件有scoped属性,子组件无scoped.父组件也无法设置子组件样式.因为父组件的所有标签都会带有data-v-5db9451a唯一标志,但子组件不会带有这个唯一标志属性.

3. 父子组建都有,同理也无法设置样式,更改起来增加代码量.

31.为什么js中0.1+0.2不等于0.3,怎样处理使之相等?(转载)

console.log(0.1+0.2===0.3)// true or false??
在正常的数学逻辑思维中,0.1+0.2=0.3这个逻辑是正确的,但是在JavaScript中0.1+0.2!==0.3,这是为什么呢?这个问题也会偶尔被用来当做面试题来考查面试者对JavaScript的数值的理解程度。

  在JavaScript中的二进制的浮点数0.1和0.2并不是十分精确,在他们相加的结果并非正好等于0.3,而是一个比较接近的数字 0.30000000000000004 ,所以条件判断结果为false。

那么应该怎样来解决0.1+0.2等于0.3呢? 最好的方法是设置一个误差范围值,通常称为”机器精度“,而对于Javascript来说,这个值通常是2^-52,而在ES6中,已经为我们提供了这样一个

属性:Number.EPSILON,而这个值正等于2^-52。这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近0,但不等于0,。这个时候我们只要判断(0.1+0.2)-0.3小于

Number.EPSILON,在这个误差的范围内就可以判定0.1+0.2===0.3为true。

32.useMemo与useCallback的区别

useMemouseCallback 接收的参数都是一样,第一个参数为回调 第二个参数为要依赖的数据

共同作用:
1.仅仅 依赖数据 发生变化, 才会重新计算结果,也就是起到缓存的作用。

两者区别:
1.useMemo 计算结果是 return 回来的值, 主要用于 缓存计算结果的值 ,应用场景如: 需要 计算的状态
2.useCallback 计算结果是 函数, 主要用于 缓存函数,应用场景如: 需要缓存的函数,因为函数式组件每次任何一个 state 的变化 整个组件 都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,提高性能,和减少资源浪费。

注意: 不要滥用会造成性能浪费,react中减少render就能提高性能,所以这个仅仅只针对缓存能减少重复渲染时使用和缓存计算结果。

33.浏览器事件机制中,事件触发的三个阶段

捕获阶段 目标阶段 冒泡阶段
捕获阶段 概念:

事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。

目标阶段 概念:

事件到达目标节点时,就到了目标阶段,事件在目标节点上被触发

冒泡阶段 概念:

事件在目标节点上触发后,不会终止,一层层向上冒,回溯到根节点

前端面试基础问题_第9张图片前端面试基础问题_第10张图片

34.promise的状态以及API介绍

  1. Promise构造函数:Promise(excutor){}
    excutor函数:同步执行 (resolve, reject) => {}
    resolve函数:内部定义成功时我们调用的函数 value =>{}
    reject函数:内部定义失败时我们调用的函数 reason => {}
    说明:excutor会在Promise内部立即同步回调,异步操作在执行器中执行

  2. Promise.prototype.then方法:(onResolved, onRejected) => {}
    onResolved函数:成功的回调函数 (value)=> {}
    onRejected函数:失败的回调函数(reason) => {}
    说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调
    返回一个新的promise对象

  3. Promise.prototype.catch方法:(onRejected) => {}
    onRejected函数:失败的回调函数(reason)=>{}
    说明:then()的语法糖,相当于:then(undefined,onRejected)

  4. Promise.resolve方法:(value)=> {}
    value:成功的数据或promise对象
    说明:返回一个成功/失败的promise对象

  5. Promise.reject方法:(reason) => {}
    reason:失败的原因
    说明:返回一个失败的promise对象

  6. Promise.all(iterable)方法:(promises) =>{}
    promises:包含n个promise的数组
    说明:这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。

  7. Promise.race方法:(promises)=> {}
    promises:包含n个promise的数组
    说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

35.css选择器

选择器 示例 示例说明 CSS
.class .intro 选择所有class="intro"的元素 1
#id #firstname 选择所有id="firstname"的元素 1
* * 选择所有元素 2
element p 选择所有

元素

1
element,element div,p 选择所有
元素和

元素

1
element element div p 选择
元素内的所有

元素

1
element>element div>p 选择所有父级是
元素的

元素

2
element+element div+p 选择所有紧接着
元素之后的

元素

2
[attribute] [target] 选择所有带有target属性元素 2
[attribute=value] [target=-blank] 选择所有使用target="-blank"的元素 2
[attribute~=value] [title~=flower] 选择标题属性包含单词"flower"的所有元素 2
[attribute|=language] [lang|=en] 选择 lang 属性以 en 为开头的所有元素 2
:link a:link 选择所有未访问链接 1
:visited a:visited 选择所有访问过的链接 1
:active a:active 选择活动链接 1
:hover a:hover 选择鼠标在链接上面时 1
:focus input:focus 选择具有焦点的输入元素 2
:first-letter p:first-letter 选择每一个

元素的第一个字母

1
:first-line p:first-line 选择每一个

元素的第一行

1
:first-child p:first-child 指定只有当

元素是其父级的第一个子级的样式。

2
:before p:before 在每个

元素之前插入内容

2
:after p:after 在每个

元素之后插入内容

2
:lang(language) p:lang(it) 选择一个lang属性的起始值="it"的所有

元素

2
element1~element2 p~ul 选择p元素之后的每一个ul元素 3
[attribute^=value] a[src^=“https”] 选择每一个src属性的值以"https"开头的元素 3
[attribute$=value] a[src$=".pdf"] 选择每一个src属性的值以".pdf"结尾的元素 3
[attribute*=value] a[src*=“runoob”] 选择每一个src属性的值包含子字符串"runoob"的元素 3
:first-of-type p:first-of-type 选择每个p元素是其父级的第一个p元素 3
:last-of-type p:last-of-type 选择每个p元素是其父级的最后一个p元素 3
:only-of-type p:only-of-type 选择每个p元素是其父级的唯一p元素 3
:only-child p:only-child 选择每个p元素是其父级的唯一子元素 3
:nth-child(n) p:nth-child(2) 选择每个p元素是其父级的第二个子元素 3
:nth-last-child(n) p:nth-last-child(2) 选择每个p元素的是其父级的第二个子元素,从最后一个子项计数 3
:nth-of-type(n) p:nth-of-type(2) 选择每个p元素是其父级的第二个p元素 3
:nth-last-of-type(n) p:nth-last-of-type(2) 选择每个p元素的是其父级的第二个p元素,从最后一个子项计数 3
:last-child p:last-child 选择每个p元素是其父级的最后一个子级。 3
:root :root 选择文档的根元素 3
:empty p:empty 选择每个没有任何子级的p元素(包括文本节点) 3
:target #news:target 选择当前活动的#news元素(包含该锚名称的点击的URL) 3
:enabled input:enabled 选择每一个已启用的输入元素 3
:disabled input:disabled 选择每一个禁用的输入元素 3
:checked input:checked 选择每个选中的输入元素 3
:not(selector) :not§ 选择每个并非p元素的元素 3
::selection ::selection 匹配元素中被用户选中或处于高亮状态的部分 3
:out-of-range :out-of-range 匹配值在指定区间之外的input元素 3
:in-range :in-range 匹配值在指定区间之内的input元素 3
:read-write :read-write 用于匹配可读及可写的元素 3
:read-only :read-only 用于匹配设置 “readonly”(只读) 属性的元素 3
:optional :optional 用于匹配可选的输入元素 3
:required :required 用于匹配设置了 “required” 属性的元素 3
:valid :valid 用于匹配输入值为合法的元素 3
:invalid :invalid 用于匹配输入值为非法的元素 3

36.rem与em的使用和区别详解

在自适应制作稿中,我们经常会看到rem和em这两个单位的冒泡,rem是基于html元素的字体大小来决定,而em则根据使用它的元素的大小决定(很多人错误以为是根据父类元素,实际上是使用它的元素继承了父类的属性才会产生的错觉) 原文:综合指南: 何时使用 Em 与 Rem 你可能已经很熟练使用这两个灵活的单位,但你可能不完全了解何时使用 rem ,何时使用 em。 本教程将帮你弄清楚! Em 和 rem都是灵活、 可扩展的单位,由浏览器转换为像素值,具体取决于您的设计中的字体大小设置。 如果你使用值 1em 或 1rem,它可以被浏览器翻译成 从16px到 160px 或其他任意值。

最大的问题是

使用 em 和 rem 单位可以让我们的设计更加灵活,能够控制元素整体放大缩小,而不是固定大小。 我们可以使用这种灵活性,使我们在开发期间,能更加快速灵活的调整,允许浏览器用户调整浏览器大小来达到最佳体验。 Em 和 rem 单位提供的这种灵活性和工作方式都很相似,所以最大的问题是,我们何时应使用 em 值,何时应使用 rem 值呢?

主要区别

Em 和 rem 单位之间的区别是浏览器根据谁来转化成px值 理解这种差异是决定何时使用哪个单元的关键。 我们要通过复习 rem 和 em 单位如何工作,来确保你知道每一个细节。 然后我会讲到为什么你应该使用 em 或 rem 的单位。 最后,我们会看看到底哪些典型元素的设计,你应该在实际应用中使用哪种类型的单位。

canvas画布

globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有的)的图像上

vuex

vuex就是一个专门用来管理vue组件之间进行通信的一个管理工具,也就是一个全局管理工具,比如你在state中定义了一个属性,那么你就可以在所用的组件中来获取和修改这个值并且你的修改可以被全局响应变更

vuex几大核心属性:
1.state
用来管理和存储vue中的属性,Vuex通过store选项,提供了一种机制将状态从根组件“注入”到每一个子组件中

通过在根实例中注册store选项,该store实例会注入到根组件下的所有子组件中,且子组件能通过this.$store访问到。更新Counter的实现:

2.getters(相当于State的计算属性)
Getters 可以认为是 store 的计算属性, getters 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

3.mutations(提交更改数据的方法,同步!必须是同步函数)
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

4.actions(像一个装饰器,包裹mutations,使之可以异步。)
action的功能和mutation是类似的,都是去变更store里的state,不过action和mutation有两点不同:
1
1)action主要处理的是异步的操作,mutation必须同步执行,而action就不受这样的限制,也就是说 action中我们既可以处理同步,也可以处理异步的操作

2)action改变状态,最后是通过提交mutation

5.modules ( 模块化Vuex)
在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。
modules:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理

辅助函数
为什么要使用辅助函数?
在使用vuex的时候,仅仅了解State、Getters、Mutations、Actions、Modules等概念,在使用过程中,业务功能逐渐增加,会出现很多个状态。当一个组件需要多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。

1.mapState
mapState函数返回的是一个对象。如果需要将它与局部计算属性混合使用,通常我们需要一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给computed属性。

2.mapGetters
mapGetters将store中的getter映射到局部计算属性

3.mapMutations
使用mapMutations辅助函数将组件中的methods映射为store.commit调用。

4.mapAction
使用mapActions辅助函数将组件的methods映射成store.dispatch调用

命名空间

当modules中导入的组件过多,并且有相同的方法名,当你想调用这个方法的时候系统默认的调取的是最后导入组件中的那个方法,而不是你想调用的那个组件,这时候你就可以用namespaced:true来给那个组件命名

你可能感兴趣的:(javascript,html,css)