1、css样式优先级
1) 样式的引用方式对css优先级的影响
1.行内样式,直接写在标签的style属性中。
<p class="in" style="background: indigo;"></p>
- 内部样式,写在头部的style标签中
- 外链样式, 通过link标签来引用css文件。
<link rel="stylesheet" type="text/css" href="index.css"/>。
行内样式>内部样式>外联样式
但是有!important的样式除外
2) 选择器对css样式优先级的影响
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的执行分为两部分,解析过程和执行过程。
- 解析时按照代码块,一段一段进行解析,
- 执行时按照代码块顺序逐行执行,
- 解析一个代码块,执行一个代码块。 因为是解释性语言,所以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 时
第三种:数据改变后获取焦点
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的区别
- let和var是声明变量的,const是声明常量的
- let和const不存在变量提升
- let 和const不允许重复声明
- let和const存在暂时性死区 初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
9、闭包和它解决的问题
闭包说的通俗一点就是可以在函数外部访问到函数内部的变量。因为正常 情况下函数外部是访问不到函数内部作用域变量的,作用域分为了全局.函数级.块级作用域.
表象判断是不是闭包:函数嵌套函数,内部函数被 return 内部函数调用外层 函数的局部变量
优点:可以隔离作用域,不造成全局污染
缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露
如何解决内存泄露:将暴露外部的闭包变量置为 null 适用场景:我在性能优化的过程中,使用节流防抖函数就是闭包的原理,导 航栏获取下标的使用
10、常见的js数据类型
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
11、常见的获取dom的方法
- 通过ID获取(getElementById)
- 通过name属性(getElementsByName)
- 通过标签名(getElementsByTagName)
- 通过类名(getElementsByClassName)
- 获取html的方法(document.documentElement)
- 获取body的方法(document.body)
- 通过选择器获取一个元素(querySelector)(开发常用)
- 通过选择器获取一组元素(querySelectorAll)(开发常用)
12、rem和em的区别
- rem是相对于根元素进行计算,而em是相对于当前元素或父元素的字体大小。
- rem不仅可以设置字体的大小,还支持元素宽、高等属性。
- em是相对于当前元素或父元素进行换算,层级越深,换算越复杂。而rem是相对于根元素计算,避免层级关系。
13、activated和deactivated
vue生命周期钩子函数新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销
大)
actived 实例激活
deactived 实例失效
详情
14、vue路由钩子
1)路由钩子分为三种
- 全局钩子: beforeEach、 afterEach、beforeResolve
- 单个路由里面的钩子: beforeEnter
- 组件路由:beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave
2)全局钩子
- beforeEach: 全局前置守卫 进入路由之前
- beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
- 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信息访问目标主机,完成解析过程
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、页面性能优化
一、资源压缩与合并
- html压缩
- css代码压缩
- js的压缩和混乱
- 文件合并 二、非核心代码异步加载的方式
- async方式
- defer方式
- 动态创建script标签 三、利用浏览器缓存
- 强缓存
- 协商缓存 四、使用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指令的作用:设置元素的innerHTMLv-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"));
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的指向,一般用于继承
apply() 它也可以调用函数,也可以修改this指向,但它传递的参数必须在数组中呈现
bind() 它不会主动调用函数,但是可以修改this指向,它返还的是原函数this指向改变之后的新函数
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图片上传.等等最后.直接提交到后端返回的接口中,更新数据库