前端理论知识必备

263 阅读22分钟

1、css样式优先级

1) 样式的引用方式对css优先级的影响

1.行内样式,直接写在标签的style属性中。

<p class="in" style="background: indigo;"></p>
  1. 内部样式,写在头部的style标签中
  2. 外链样式, 通过link标签来引用css文件。
<link rel="stylesheet" type="text/css" href="index.css"/>。


行内样式>内部样式>外联样式
但是有!important的样式除外

2) 选择器对css样式优先级的影响

image.png

2、flex属性

1、常用的父级属性
flex-direction :设置主轴的方向
justify-content :设置主轴上的子元素排列方式
flex-wrap :设置子元素是否换行
align-content :设置侧轴上的子元素排列方式(多行)
align-items :设置侧轴上的子元素排列方式(单行)
flex-flow :复合属性,相当于同时设置了flex-direction和flex-wrap
1.1、flex-direction 设置主轴的方向
属性值 说明
row 默认值从左到右
row-reverse 从左到右
column 从上到下
column-reverse 从上到下
1.2、justify-content 设置主轴的子元素排列方式
justify-content 属性定义了项目在主轴上的对齐方式

注意:使用这个属性之前一定要确定好主轴是那个

3、强缓存和协商缓存

什么是浏览器缓存?
浏览器缓存(Brower Caching)是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。

浏览器缓存主要有两类:协商缓存和强缓存。

1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,状态码是200;

2.协商缓存:向服务器发送请求,服务器会根据这个请求的Request headers的一些参数来判断是否命中协商缓存,如果命中,从缓存中读取数据,返回304状态码

两者共同点:都是从客户端缓存中读取资源;

区别:强缓存不会发请求,协商缓存会发请求。

4、js解析

javascript是一种描述型的脚本语言,是一种解析语言,由浏览器动态解析,不同种类的浏览器不同版本的浏览器对于js的解析有着微小的差别,不同浏览器的js解析引擎效率也有高低。

js的执行过程分为两大部分

第一部分,解析过程,也称预编译期 。主要工作就是对于js的代码中声明的所有变量和函数进行预处理。需要注意的是,再此进行处理的仅是声明函数,而对于变量的处理仅是声明,并开辟出一块内存空间,不进行复制操作。

第二部分,执行过程,在执行过程中,浏览器的js引擎对于每个代码块进行顺序执行,如果有外部引用的js,且js有相互关联,此时就要注意,不同js的引入顺序,如果声明代码块在调用代码块后调用则将不会达到预期的效果。

总结来说,js的执行分为两部分,解析过程和执行过程。

  1. 解析时按照代码块,一段一段进行解析,
  2. 执行时按照代码块顺序逐行执行,
  3. 解析一个代码块,执行一个代码块。 因为是解释性语言,所以js如果在解析过程有错误,则不会提示,也可以理解为js不会出现编译错误,但如果出现了运行时错误,出现错误一下的所有js代码将不会继续执行。

5、div+css布局与table布局比较

一、背景介绍

table布局是网页早期布局实现的主要手段,当时的网页构成,相对也比较简单,多是以文本

以及静态图片等组成的,类似于报纸的形式,分区分块显示,table标签的结构表现恰好可以

满足这样的要求。但是随着网页要求的提高和技术的不断探索更迭,尤其是W3C(万维网联

盟)及其他标准组织制定的标准出台后,明确了table标签不是布局工具,使table标签重新回

到其原有的作用上(即仅作为呈现表格化数据的作用),而提倡使用div+css的布局组合。

二、知识剖析

1)使用table布局的特点

优点:

1、对于新手而言,容易上手,尤其对于一些布局中规中矩的网页,更让人首先想到excel,进而通过使用table去实现它。

2、表现上更加“严谨”,在不同浏览器中都能得到很好的兼容

3、通过复杂的表格套表格的形式,也可以实现比较复杂的布局需求。布置好表格,然后将内容放进去就可以了。

4、它可以不用顾及垂直居中的问题。

5、数据化的存放更合理。

缺点:

1、标签结构多,复杂,在表格布局中,主要是用到表格的相互嵌套使用,这样就会造成代码的复杂度更高!

2、表格布局,不利于搜索引擎抓取信息,直接影响到网站的排名

2)使用div+css布局的特点

优点

1、符合W3C标准的,W3C标准提出网页由三部分组成:结构(Structure)、表现(Presentation)和行为(Behavior)。结构清晰明了,结构、样式和行为分离,带来足够好的可维护性。

2、布局更加灵活多样,能够通过样式选择来实现界面设计方面的更多要求。

3、布局改版方便,不需要过多地变动页面内容,通常只要更换相应的css样式就可以将网页变成另外一种风格展现出来。

4、布局可以让一些重要的链接和文字信息等优先让搜索引擎抓取,内容更便于搜索。

5、增加网页打开速度,增强用户体验。

缺点

1、开发技术高,要考虑兼容版本浏览器。目前来看,DIV+CSS还没有实现所有浏览器的统一兼容。

2、CSS网站制作的设计元素通常放在1个外部文件中,或几个文件,

有可能相当复杂,甚至比较庞大,如果CSS文件调用出现异常,那么整个网站将变得惨不忍睹。

3) div+css的布局较table布局的明显优势

1,其实也是div+css布局的第一个特点,table标签被严格地定义为存放数据的一个区域,而不是布局工具,它的布局形式不符合W3C标准,没有实现结构和表现的分离,它既有css的表现功能,也有html的结构功能。

2,table布局加载网页时,必须整体加载完,降低了网页的呈现速度,而div+css布局是边加载边显示的。

3,table布局在网页代码编写时,有时需要嵌套多重表格才能实现,但使用div+css布局,相对而言会减少许多嵌套时的代码,更容易检查和维护。

4,table布局不方便表现的更换,使用div+css布局,大多只要更改css样式表就能变化表现形式。

5、易于维护和改版。

6、nextTick 的作用和使用场景?

vue 中的 nextTick 主要用于处理数据动态变化后,DOM 还未及时更新的问题,用 nextTick 就可以获取数据更新后最新 DOM 的变化。

作用场景:
第一种:有时需要根据数据动态的为页面某些 dom 元素添加事件,这就要求 在 dom 元素渲染完毕时去设置,但是 created 与 mounted 函数执行时一般 dom 并没有渲染 完毕,所以就会出现获取不到,添加不了事件的问题,这回就要用到 nextTick 处理

第二种:在使用某个第三方插件时 ,希望在 vue 生成的某些 dom 动态发生变 化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重 新应用插件的方法,例如:应用滚动插件 better-scroll 时

image.png

image.png 第三种:数据改变后获取焦点

7、div上下左右居中

1)定位

第一种思路:通过给 div 设置绝对定位,并且 left , right,top,bottom 设置为 0,margin:auto 即可以水平垂直居中

第二种思路:通过给 div 设置绝对定位,left 为 50%,top 为 50%,再给 div 设置距左是自身的一半即:margin-left:自身宽度/2,margin-top:自身高 度/2。

第三种思路:通过给 div 设置绝对定位,left 为 50%,top 为 50%,再给 div 设置跨左和跟上是自身的一半:transform:translate3d(-50%,-50%,0)

2)flex 布局

思路:有两个div,父级div和子级div,给父级div设置display:flex, 并且设置父级 div 的水平居中 justify-content:center,并且给父级 div 设置 垂直居中 align-items:center 即可

8、let、const、var的区别

  1. let和var是声明变量的,const是声明常量的
  2. let和const不存在变量提升
  3. let 和const不允许重复声明
  4. let和const存在暂时性死区 初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。

9、闭包和它解决的问题

闭包说的通俗一点就是可以在函数外部访问到函数内部的变量。因为正常 情况下函数外部是访问不到函数内部作用域变量的,作用域分为了全局.函数级.块级作用域.

表象判断是不是闭包:函数嵌套函数,内部函数被 return 内部函数调用外层 函数的局部变量

优点:可以隔离作用域,不造成全局污染

缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露

如何解决内存泄露:将暴露外部的闭包变量置为 null 适用场景:我在性能优化的过程中,使用节流防抖函数就是闭包的原理,导 航栏获取下标的使用

10、常见的js数据类型

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

引用数据类型:对象(Object)、数组(Array)、函数(Function)。

注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。

11、常见的获取dom的方法

  1. 通过ID获取(getElementById)
  2. 通过name属性(getElementsByName)
  3. 通过标签名(getElementsByTagName)
  4. 通过类名(getElementsByClassName)
  5. 获取html的方法(document.documentElement)
  6. 获取body的方法(document.body)
  7. 通过选择器获取一个元素(querySelector)(开发常用)
  8. 通过选择器获取一组元素(querySelectorAll)(开发常用)

12、rem和em的区别

  1. rem是相对于根元素进行计算,而em是相对于当前元素或父元素的字体大小。
  2. rem不仅可以设置字体的大小,还支持元素宽、高等属性。
  3. em是相对于当前元素或父元素进行换算,层级越深,换算越复杂。而rem是相对于根元素计算,避免层级关系。

13、activated和deactivated

vue生命周期钩子函数新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销 大)

actived 实例激活
deactived 实例失效 详情

14、vue路由钩子

1)路由钩子分为三种

  • 全局钩子: beforeEach、 afterEach、beforeResolve
  • 单个路由里面的钩子:  beforeEnter
  • 组件路由:beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave

2)全局钩子

  1. beforeEach: 全局前置守卫 进入路由之前
  2. beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
  3. afterEach 全局后置钩子 进入路由之后

3)路由的三个参数

  • to: 将要进入的路由对象
  • from:将要离开的路由对象
  • next: 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)
    // main.js 入口文件
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全局后置钩子');
    });

4)路由独享守卫

为某些路由单独配置守卫

const router = new VueRouter({
 routes: [
   {
      path: '/test',
      component: Test,
      beforeEnter: (to, from, next) => { 
      // 参数用法与全局的钩子都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
    }
   }
 ]
})

5)路由组件内的守卫

  • beforeRouteEnter 进入路由前
  • beforeRouteUpdate (2.2) 路由复用同一个组件时
  • beforeRouteLeave 离开当前路由时

15、vue父子组件传值

父传子

主要通过 props 来实现的 具体实现:父组件通过 import 引入子组件,并注册,在子组件标签 上添加要传递的属性,子组件通过 props 接收,接收有两种形式一是通过数组 形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置 要传递的数据类型和默认值,而数组只是简单的接收

子传父
主要通$emit 来实现具体实现:子组件通过通过绑定事件触发函数,在其中设置 this.$emit(‘要派发的自定义事件’,要传递的值),$emit 中有两个参数一 是要派发的自定义事件,第二个参数是要传递的值 然后父组件中,在这个子组件身上@派发的自定义事件,绑定事件触发的 methods 中的方法接受的默认值,就是传递过来的参数

16、XMLHttprequest对象的使用

XMLHttpRequest 对象用于在后台与服务器交换数据

1)创建新请求的⽅法

open()⽅法⽤于设置进⾏异步请求⽬标的URL、请求⽅法以及其他参数信息,具体语法如下:

open("method","URL"[,asyncFlag[,"userName"[, "password"]]]) open()⽅法的参数说明。

2)向服务器发送请求的⽅法

send()⽅法⽤于向服务器发送请求。如果请求声明为异步,该⽅法将⽴即返回,否则将等到接收到响应为⽌。send()⽅法的语法格式如下: send(content) content:⽤于指定发送的数据,可以是DOM对象的实例、输⼊流或字符串。如果没有参数需要传递可以设置为null。 例如,向服务器发送⼀个不包含任何参数的请求,可以使⽤下⾯的代码: http_request.send(null);

3)设置请求的HTTP头的⽅法

setRequestHeader()⽅法⽤于为请求的HTTP头设置值。setRequestHeader()⽅法的具体语法格式如下: setRequestHeader("header", "value")
header:⽤于指定HTTP头。
value:⽤于为指定的HTTP头设置值。
setRequestHeader()⽅法必须在调⽤open()⽅法之后才能调⽤。
例如,在发送POST请求时,需要设置Content-Type请求头的值为“application/x-www-form-urlencoded”,这时就可以通过 setRequestHeader()⽅法进⾏设置,具体代码如下: http_request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

4)停⽌或放弃当前异步请求的⽅法

abort()⽅法⽤于停⽌或放弃当前异步请求。其语法格式如下: abort() 例如,要停⽌当前异步请求可以使⽤下⾯的语句: http_request.abort()

5)返回HTTP头信息的⽅法

XMLHttpRequest对象提供了两种返回HTTP头信息的⽅法,分别是getResponseHeader()和getAllResponseHeaders()⽅法。下⾯分别进⾏介绍。

1.getResponseHeader()⽅法

getResponseHeader()⽅法⽤于以字符串形式返回指定的HTTP头信息。其语法格式如下:
getResponseHeader("headerLabel") headerLabel:⽤于指定HTTP头,包括Server、Content-Type和Date等。
例如,要获取HTTP头Content-Type的值,可以使⽤以下代码: http_request.getResponseHeader("Content-Type") 上⾯的代码将获取到以下内容: text/html;charset=GBK

2.getAllResponseHeaders()⽅法

getAllResponseHeaders()⽅法⽤于以字符串形式返回完整的HTTP头信息,其中,包括Server、Date、Content-Type和Content-Length

17、简述DNS解析过程

1、客户机发出查询请求,在本地计算机缓存查找,若没有找到,就会将请求发送给dns服务器

2、本地dns服务器会在自己的区域里面查找,找到即根据此记录进行解析,若没有找到,就会在本地的缓存里面查找

3、本地服务器没有找到客户机查询的信息,就会将此请求发送到根域名dns服务器(如www.baidu.com/)

4、根域名服务器解析客户机请求的根域部分,它把包含的下一级的dns服务器的地址返回到客户机的dns服务器地址

5、客户机的dns服务器根据返回的信息接着访问下一级的dns服务器

6、这样递归的方法一级一级接近查询的目标,最后在有目标域名的服务器上面得到相应的IP信息

7、客户机的本地的dns服务器会将查询结果返回给我们的客户机

8、客户机根据得到的ip信息访问目标主机,完成解析过程 image.png

18、js的原型链

原型链是理解 JS 面向对象很重要的一点,这里主要涉及到两个点,一是 __proto__ ,二是 prototype,
举个例子吧,这样还好说点,例如:我用 function 创建一个 Person 类,然后用 new Person 创建一个对象的实例假如叫 p1 吧,在 Person 类的原型 prototype 添加一个方法,例如:play 方法,那对象实例 p1 如何查找到 play 这个方法呢,有一个查找过程,具体流程是这样的: 首先在 p1 对象实例上查找是否有 play 方法,如果有则调用执行,如果没 有则用 p1.__proto__(_proto_是一个指向的作用,指向上一层的原型)往创建 p1 的类的原型上查找,也就是说往 Person.prototype 上查找,如果在 Person.prototype 找 到 play 方 法 则 执 行 , 否 则 继 续 往 上 查 找 , 则用 Person.prototye.__proto__ 继续往上查找,找到 Object.prototype,如果 Object.prototype有play方法则执行之,否则用Object.prototype.__proto__ 继续再往上查找,但 Object.prototpye.__proto__上一级是 null,也就是原型链的顶级,结束原型链的查找,这是我对原型链的理解

Tips 附加分.你像我最近做的项目里面有些公共常用的方法.我放到了 utils 里 面.然后在 vue 的 main.js 里面导入进来.然后通过 Vue.prototype.方法名绑定 到原型上,就利用了这种原型链的原理

19、页面性能优化

一、资源压缩与合并

  1. html压缩
  2. css代码压缩
  3. js的压缩和混乱
  4. 文件合并 二、非核心代码异步加载的方式
  5. async方式
  6. defer方式
  7. 动态创建script标签 三、利用浏览器缓存
  8. 强缓存
  9. 协商缓存 四、使用CDN

五、预解析CDN

详情

20、table布局的弊端

总结

Table布局的缺点是比其它html标记占更多的字节,会阻挡浏览器渲染引擎的渲染顺序,会影响其内部的某些布局属性的生效,优点就是用table做表格是完全正确的

 

Tables的缺点

1、Table要比其它html标记占更多的字节。(延迟下载时间,占用服务器更多的流量资源。)

2、Tablle会阻挡浏览器渲染引擎的渲染顺序。(会延迟页面的生成速度,让用户等待更久的时间。)

3、Table里显示图片时需要你把单个、有逻辑性的图片切成多个图。(增加设计的复杂度,增加页面加载时间,增加HTTP会话数。)

4、在某些浏览器中Table里的文字的拷贝会出现问题。(这会让用户不悦。)

5、Table会影响其内部的某些布局属性的生效(比如里的元素的height:100%)(这会限制你页面设计的自由性。)

6、一旦学了CSS知识,你会发现使用table做页面布局会变得更麻烦。(先花时间学一些CSS知识,会省去你以后大量的时间。)

7、table对对于页面布局来说,从语义上看是不正确的。(它描述的是表现,而不是内容。)

8、table代码会让阅读者抓狂。(不但无法利用CSS,而且会你不知所云)

9、table一旦设计完成就变成死的,很难通过CSS让它展现新的面貌。

Tables的优点

在某些场合,使用Table是100%的适合、恰当和正确。比如,用table做表格是完全正确的。

21、Vue.js v-html指令

  • v-html 指令的作用:设置元素的innerHTML v-html 指令类似于 v-text 指令;
  • 它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。
  • v-html 指令应尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击),一般只在可信任内容上使用 v-html,永不用在用户提交的内容上;

22、地址栏参数详解

URL即:统一资源定位符 (Uniform Resource Locator, URL) 完整的URL由这几个部分构成:scheme://host:port/path?query#fragment

  • scheme:- /skiːm/-通信协议常用的http,ftp,maito等
  • host:主机服务器(计算机)域名系统 (DNS) 主机名或 IP 地址。
  • port:端口号整数,可选,省略时使用方案的默认端口,如http的默认端口为80。
  • path:路径由零或多个"/"符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。
  • query:查询可选,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技术制作的网页)传递参数,可有多个参数,用"&"符号隔开,每个参数的名和值用"="符号隔开。
  • fragment:信息片断字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。(也称为锚点.)

对于这样一个URL www.maidq.com/index.html?…
我们可以用javascript获得其中的各个部分

  • window.location.href整个URl字符串(在浏览器中就是完整的地址栏)本例返回值: www.maidq.com/index.html?…

  • window.location.protocolURL 的协议部分本例返回值:http:

  • window.location.hostURL 的主机部分本例返回值:www.maidq.com

  • window.location.portURL 的端口部分如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符本例返回值:""

  • window.location.pathnameURL 的路径部分(就是文件地址)本例返回值:/fisker/post/0703/window.location.html

  • window.location.search查询(参数)部分除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值本例返回值:?ver=1.0&id=6

  • window.location.hash锚点本例返回值:#imhere

采用正则表达式获取地址栏参数

function GetQueryString(name)
{
    var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
    var r = window.location.search.substr(1).match(reg);
    if(r!=null)return  unescape(r[2]); return null;
}
 
// 调用方法
alert(GetQueryString("参数名1"));
alert(GetQueryString("参数名2"));
alert(GetQueryString("参数名3"));

js解析url地址栏参数

23、axios做过哪些封装

  • 环境切换
  • 设置请求超时
  • 请求头设置
  • 请求拦截
  • 响应拦截 详情了解

24、JavaScript垃圾回收机制。

  • 标记清理
  • 引用计数 释放内存 把声明的对象赋值为 null
let obj = {} // 开辟内存

obj.name = 'haha' // 标记内存

obj = null // 释放内存

1)标记清理

JavaScript 最常用的垃圾回收策略是标记清理(mark-and-sweep)。当变量进入上下文,比如在函数 内部声明一个变量时,这个变量会被加上存在于上下文中的标记。而在上下文中的变量,逻辑上讲,永 远不应该释放它们的内存,因为只要上下文中的代码在运行,就有可能用到它们。当变量离开上下文时, 也会被加上离开上下文的标记。 给变量加标记的方式有很多种。比如,当变量进入上下文时,反转某一位;或者可以维护“在上下 文中”和“不在上下文中”两个变量列表,可以把变量从一个列表转移到另一个列表。标记过程的实现 并不重要,关键是策略。 垃圾回收程序运行的时候,会标记内存中存储的所有变量(记住,标记方法有很多种)。然后,它 会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记 的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内 存清理,销毁带标记的所有值并收回它们的内存。 到了 2008 年,IE、Firefox、Opera、Chrome 和 Safari 都在自己的 JavaScript 实现中采用标记清理(或 其变体),只是在运行垃圾回收的频率上有所差异。

2)引用计数

对每个值都记录它被 引用的次数。声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变 量,那么引用数加 1。类似地,如果保存对该值引用的变量被其他值给覆盖了,那么引用数减 1。当一 个值的引用数为 0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序 下次运行的时候就会释放引用数为 0 的值的内存。

25、闭包

闭包说的通俗一点就是可以在函数外部访问到函数内部的变量

因为正常情况下函数外部是访问不到函数内部作用域变量的,作用域分为了全局.函数级.块级作用域. 表象判断是不是闭包:函数嵌套函数,内部函数被 return 内部函数调用外层函数的局部变量

let obj = {
    name:'下雨啦',
    fn:function(){
        return this.name
    }
}
obj.fn();
// 释放obj的内存
obj = null;

优点:可以隔离作用域,不造成全局污染,可以让垃圾回收机制不会回收这个变量,让他能一直被标记为被引用。

缺点:由于闭包长期驻留内存,则会导致大量内存永远不会被释放,内存泄露.

如何释放内存:将暴露外部的闭包变量置为 null。

26、this指向

1、普通函数调用,此时 this 指向 window
function fn1(){
    console.log(this)
}
fn1(); // window
 // window.fn1();
--------------------------
2、对象方法调用, 此时 this 指向 该方法所属的对象
let obj = {
    name:'哈哈哈',
    fn:function(){
        return this.name  //this指向obj
    }
}
obj.fn() // 哈哈哈
----------------------------
3、通过事件绑定的方法, 此时 this 指向 绑定事件的对象
<div id="dom">你好</div>
let dom = document.getElementById('dom')

dom.addEventListener('click'function(){
    console.log(this) // dom
   }
)
---------------------------
4、构造函数调用, 此时 this 指向 实例对象
function Person(age, name) {
         this.age = age;
         this.name = name
         console.log(this)  // 此处 this 分别指向 Person 的实例对象 p1 p2
     }
    var p1 = new Person(18, 'zs')
    var p2 = new Person(18, 'ww')
---------------------------
5、定时器函数, 此时 this 指向 window
setTimeout(()=>{
    console.log(this) // window
})

setInterval(()=>{
    console.log(this) // window
})
---------------------------
// 6、如果是箭头函数,那么会把this指向他的父级作用域
{
    var num = 2
    var obj = {
        num:1,
        fn:() => {
            console.log(this.num); // 2
        }
    }
}
---------------------------
var num = 2
var obj = {
    num:1,
    fn:function(){
        console.log(this.num); // 1
    }
}

1)修改this指向

修改this指向一共有三种方法,它们分别是call()  apply()  bind()

call() 它可以调用函数也可以改变函数this的指向,一般用于继承 image.png

apply() 它也可以调用函数,也可以修改this指向,但它传递的参数必须在数组中呈现 image.png

bind() 它不会主动调用函数,但是可以修改this指向,它返还的是原函数this指向改变之后的新函数

image.png

27、箭头函数的特点

1、没有构造函数,不能new实例对象
2、本身没有this指向,this指向父级
3、不能使用argumetns
4、没有原型

// 箭头函数使表达更加简洁,隐式返回值
// 正常的写法
const isEven = function(n){
    return n % 2 === 0;
}
const square = function(n){
    return n * n;
}

const isEven = n => n % 2 === 0;
const square = n => n * n;

// 箭头函数的一个用处是简化回调函数
// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});
 
// 箭头函数写法
[1,2,3].map(x => x * x); //[1,4,9]

28、var let 和 const 区别

//  var 的变量会挂载到 window上
var a = 1 // window.a
console.log(a); // 1
console.log(window.a); // 1

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

const c = 3; // 
console.log(b); // 3
console.log(window.b); // undefined

// var 可以被重复声明,let const 不可以,如果重复声明会报错
var a = 1;
var a = 100;
console.log(a) // 100 

let b = 2 ;
let b = 200 ;
// Uncaught SyntaxError: Identifier 'b' has already been declared

let const = 3 ;
let const = 300 ;
// Uncaught SyntaxError: Identifier 'c' has already been declared

// var有变量提升, let 和 const 没有
console.log(a) // undefined
var a = 10;

console.log(b)
let b = 20;
//Uncaught ReferenceError: can't access lexical declaration 'b' before initialization

console.log(c)
let c = 20;
//Uncaught ReferenceError: can't access lexical declaration 'c' before initialization

// let const 生成块级作用域
if(1){
    var a = 100;
    let b = 10
    console.log(b)
}
function fn(){
return {
    a:100
}
}
fn()
console.log(a);
console.log(b)

// let const 会形成一个暂时性死区
var a = 100
function fn(){
    console.log(a);
}
fn();
// 
var a = 100
function fn(){
    console.log(a);
    let a = 10;
}
fn(); // 暂时性死区

const:
// 1、一旦声明必须赋值。
// 2、声明后不能再修改
// 3、如果声明的是复合类型数据,可以修改其属性
const a = 10;
a = 100; // 报错
const arr = [];
arr = [1,2] // 报错,改变了内存指针的指向
arr.push(1); // [1],只是修改指针指向的内存地址里的属性
let obj = {}
obj = {name:'tan'} // 报错
obj.name = 'tan' // 不报错,内存指针未变,只改变了内存里的属性

29、js内存存储机制

基本数据类型:string、number、boolean、null、undefined、symbol、bigInt

引用数据类型:Object、Function、Array

基本数据类型放在栈内存里面

引用数据类型有一个占位牌在栈内存里,真实的数据在堆内存中,并且占位牌有一个指针指向对应的内存空间。

这是为什么const 可以对原引用数据类型进行修改,而不能直接重新赋值一个新对象的原因,第一种指针未发生改变,第二种指针指向新的内存地址所以会报错。

30、js的值传递和引用传递

var a = 10;
function fn(){
   var a = 20;
}
console.log(a);
------------------------
var a = 10;
function fn(){
    console.log(a) // undefined
    var a = 20;
}
fn();
console.log(a); // 10
------------------------
var a = 10;
function fn(){
// Uncaught ReferenceError: can't access lexical declaration 'a' before initialization
console.log(a)
let a = 20;
}
fn();
console.log(a);
------------------------
var a = 10;
function fn(){
   a = 20;
}
fn();
console.log(a); // 20
-----------------------
var a = 10;
function fn(a){
a = 20;
}
fn();
console.log(a); // 10

31、动态form表单的封装

对于一些新增修改模态框,在点击创建的时候,后端会返回展示列以及以及对应列的一些参数比方说.验证规则,提示信息,表单类型以及预渲染的值等等.还有当前模块要提交的url地址,请求方式等参数.我直接封装了一个baseForm组件.里面根据后端返回的表单项进行v-if判断.渲染哪些类型.你像.输入框下拉框.radio/checkbox.switch图片上传.等等最后.直接提交到后端返回的接口中,更新数据库