面经
Webpack
webpack是一个用于现代js应用程序的静态模块打包工具,当webpack处理应用程序时,它会在内部从一个或者多个入口点构建一个依赖图(dependency graph),然后将你的项目中所需的每一个模块组合成一个或者多个bundles,它们均为静态资源,用于展示你的内容
安装
基于node.js 使用npm包管理器来安装webpack:本地安装
1、新建一个工程目录,并执行npm的初始化命令
mkdir webpack_init && cd webpack_init
pm init
2、命令行输入项目的基本信息,如:名称、版本、描述、仓库地址等信息,成功后工程目录中会出现package.json文件
3、安装webpack的命令
npm install webpack webpack-cli –save-dev
全局安装webpack-cli:
npm i -g webpack-cli
查看安装是否成功执行
D:\webpack_init>webpack-cli -v
System:
OS: Windows 10 10.0.19044
CPU: (16) x64 AMD Ryzen 7 5800H with Radeon Graphics
Memory: 7.13 GB / 13.86 GB
Binaries:
Node: 16.16.0 - D:\Program Files(x86)\nodejs\node.EXE
Yarn: No HADOOP_CONF_DIR set.
Please specify it either in yarn-env.cmd or in the environment. - D:\hadoop-3.1.0\bin\yarn.CMD
npm: 8.11.0 - D:\Program Files(x86)\nodejs\npm.CMD
Browsers:
Edge: Spartan (44.19041.1266.0), Chromium (111.0.1661.44)
Internet Explorer: 11.0.19041.1566
Packages:
webpack: ^5.76.2 => 5.76.2
webpack-cli: ^5.0.1 => 5.0.1
4、打包的第一个应用
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>practice</title>
</head>
<body>
<script src="./dist/main.js"></script>
</body>
</html>
src/index.js
import helloWorld from './hello.js';
function component() {
const element = document.createElement('div');
element.innerHTML = helloWorld();
return element;
}
document.body.appendChild(component());
src/hello.js
export default function() {
return 'hello world!!!'
}
核心概念-入口
资源处理流程
webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图会映射项目所需的每个模块,并生成一个或多个 bundle。
bundle
代码分离是webpack的特性之一,使用entry配置入口起点,会将代码分成源代码和分发代码,其中源代码是开发编辑的代码,分发代码是经过webpack构建,可能经过转义、压缩或者优化后的代码,这些代码存放于bundle中,可以被浏览器等环境直接运行。
依赖图 dependency graph
打包步骤总结
1、我们工程的依赖路径index.js -> hello.js -> message.js
2、根据 webpack.config.js 中定义的 entry 解析入口(index.js)文件,找到他的依赖
3、递归的构建依赖关系图
4、将所有内容打包到 webpack.config.js 定义的 output 文件
plugin
插件:用户对某个现有的架构进行扩展
webpack中的插件就是对webpack现有功能的各种扩展,比如打包优化、文件压缩等等
loader和plugin的区别
loader:主要用户转换某些类型的模块,它是一个转换器
plugin的使用:
1、通过npm安装需要使用的plugin(某些webpack已经内置的插件不需要安装)
2、在webpack.config.js中的plugins中配置插件
Vue
(95条消息) vue学习笔记(超详细)_vue笔记_fmk1023的博客-CSDN博客
Vue是一个渐进式的框架
引入
1、直接CDN引入
开发环境版本/生产环境版本
2、下载和引入
3、NPM安装
通过webpack和cli的使用
Vue的MVVM
M:model 数据模型 数据层 数据可能是一些固定的数据,更多的是来自服务器,从网络上请求下来的数据
V:view 视觉层 前端开发中,通常是DOM层 给用户展示各种信息
VM:View-model 视图模型层 view和model沟通的桥梁 作用:1、data binding数据绑定 2、DOM listener 当DOM发生一些事件(滚动、点击、touch等等),可以进行监听,并在需要的情况下改变对应的data
语法
v-once
v-html
v-bind 动态绑定属性 简写 :
v-if v-else-if v-else
v-show: 元素显示 dom增加一个行内样式display:none
v-on:绑定事件监听 简写@
v-for遍历数组
v-model表单绑定:实现表单元素和数据的双向绑定 radio checkbox select
修饰符
lazy:可以让数据只有在失去焦点或者回车的时候才会更新
number:在默认情况下,(前景:输入框中无论输入字母还是数字,都会被当作字符串类型进行处理)作用:当作数字类型进行处理
trim:可以过滤掉内容左右两边的空格
检测数组更新:
Vue是响应式,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新
计算属性
computed
computed/methods的区别
methods:每次都会调用
computed:计算机会缓存,不变的情况下只调用一次
fulters过滤器 ???
组件化开发
基本步骤
1、调用Vue.extend()方法-构建组件构造器
2、调用Vue.component()方法-注册组件
3、在Vue实例的作用范围内-使用组件
组件分类
全局组件
局部组件
父组件/子组件
1、当子组件注册到父组件的components时,Vue会编译好父组件的模块
2、该模块的内容已经决定了父组件将要渲染的HTML (相当于父组件中已经有子组件中的内容了)
vue为了简化注册组件的过程,提供了注册的语法糖,省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
eg
组件模板抽离写法
放入标签
组件不能访问vue实例数据
组件是一个单独功能模块的封装,这个模块有自己的html模板,也应该有属于自己的data
Vue.component(‘cpn’, {
template: ‘#cpn’,
data() {
return {
title: ‘哈哈哈’
}
}
})
// data属性必须是一个函数, 返回必须是一个对象
组件通信
父子组件的通信
1、通过props向子组件传递数据
父组件访问子组件方式
$children: this.$children 是一个数组类型,它包含所有子组件对象
$refs:拿指定的子组件
子组件访问父组件方式
$parent: 上一级父组件
$root: 根组件
插槽slot
作用:组件的插槽是为了让我们封装的组件更加具有扩展性,让使用者可以决定组件内部的一些内容到底是什么
基本使用
具名插槽
作用域插槽
Vue Cli
cli:Command-Line Interface命令行界面,俗称脚手架
Vue Cli是官方发布的vue.js项目脚手架,可以快速搭建vue开发环境以及webpack配置
Vue cli使用前提 -安装node 安装webpack
vue cli3
基于webpack 4 打造 移除了static文件夹,增加了public文件夹,并且index.html移动到了public中
vue-router
routing路由:通过互联网把信息从源地址传输到目的地址的活动
路由表:本质上就是一个映射表,决定了数据包的指向
后端路由阶段
早期的网站开发整个HTML页面是由服务器来渲染
服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示
一个页面有自己对应的网址, 也就是URL.
URL会发送到服务器,
服务器会通过正则对该URL进行匹配,并且最后交给一个Controller进行处理.
Controller进行各种处理, 最终生成HTML或者数据, 返回给前端.
这就完成了一个IO操作.
上述的操作就是后端路由
当我们页面中需要请求不同的路径内容时, 交给服务器来进行处理, 服务器渲染好整个页面, 并且将页面返回给客户端
这种情况下渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示, 这样也有利于SEO的优化
缺点
一种情况是整个页面的模块由后端人员来编写和维护的
另一种情况是前端开发人员如果要开发页面,需要通过PHP和Java等语言来编写页面代码
而且通常情况下HTML代码和数据以及对应的逻辑会混在一起, 编写和维护都是非常糟糕的事情
前端路由阶段
前后端分离阶段
随着ajax的出现,有了前后端分离的开发模式
后端只提供API来返回数据,前端通过ajax获取数据,并且可以通过js将数据渲染到页面中
前后端责任清晰,后端专注于数据处理,前端专注于交互和可视化上
移动端(android/IOS)出现之后,后端不需要进行任何处理,依然使用之前的一套API即可
前端渲染
浏览器中显示的网页中大部分内容, 都是由前端写的JS代码在浏览器中执行,最终渲染出来
前端路由核心:改变URL,但是页面不进行整体的刷新
如何实现:
1、URL的hash
URL的hash也就是#,本质上是改变window.location的href属性
通过直接赋值location.hash来改变href, 但页面不刷新
2、html5的history模式
history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面
①. history.pushState() –> 入栈
②. history.replaceState()
③. history.go()
④. history.back() 等价于 history.go(-1) –> 后退
⑤. history.forward() 等价于 history.go(1) –> 前进
- 什么是前端渲染, 什么是后端渲染?
前端渲染:
指的是后端返回JSON数据,前端利用预先写的html模板,循环读取JSON数据,拼接字符串(es6的模板字符串特性大大减少了拼接字符串的的成本),并插入页面。
好处:网络传输数据量小。不占用服务端运算资源(解析模板),模板在前端(很有可能仅部分在前端),改结构变交互都前端自己来了,改完自己调就行。
坏处:前端耗时较多,对前端工作人员水平要求相对较高。前端代码较多,因为部分以前在后台处理的交互逻辑交给了前端处理。占用少部分客户端运算资源用于解析模板。
后端渲染:
前端请求,后端用后台模板引擎直接生成html,前端接受到数据之后,直接插入页面。
好处:前端耗时少,即减少了首屏时间,模板统一在后端。前端(相对)省事,不占用客户端运算资源(解析模板)
坏处:占用服务器资源。
前端渲染与后端渲染对比:
后端渲染:
页面呈现速度:快,受限于用户的带宽
流量消耗:少一点点(可以省去前端框架部分的代码)
可维护性:差(前后端东西放一起,掐架多年,早就在闹分手啦)
seo友好度:好
编码效率:低(这个跟不同的团队不同,可能不对)
前端渲染:
页面呈现速度:主要受限于带宽和客户端机器的好坏,优化的好,可以逐步动态展开内容,感觉上会更快一点
流量消耗:多一点点(一个前端框架大概50KB)当然,有的用后端渲染的项目前端部分也有在用框架
可维护性:好,前后端分离,各施其职,代码一目明了。
SEO友好度:差,大量使用ajax,多数浏览器不能抓取ajax数据。
编码效率:高,前后端各自只做自己擅长的东西,后端最后只输出接口,不用管页面呈现,只要前后端人员能力不错,效率不会低
2、前后端分离
前端人员和后端人员约定好接口后,前端人员彻底不用再关心业务处理是怎么回事,他只需要把界面做好就可以了,后端人员也不用再关系前端界面是什么样的,他只需要做好业务逻辑处理即可。服务的切离,代码管理,服务部署也都独立出来分别管理,系统的灵活性也获得了极大的提升。总结,任何系统架构设计,实际上是对组织结构在系统上进行映射,前后端分离,就是在对前端开发人员和后端开发人员的工作进行解耦,尽量减少他她们之间的交流成本,帮助他她们更能专注于自己擅长的工作。
- 什么是前端路由, 什么是后端路由?
A. 什么是前端路由?
很重要的一点是页面不刷新,前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,每跳转到不同的URL都是使用前端的锚点路由. 随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载
B. 什么是后端路由?
浏览器在地址栏中切换不同的url时,每次都向后台服务器发出请求,服务器响应请求,在后台拼接html文件传给前端显示, 返回不同的页面, 意味着浏览器会刷新页面,网速慢的话说不定屏幕全白再有新内容。后端路由的另外一个极大的问题就是 前后端不分离。
优点:分担了前端的压力,html和数据的拼接都是由服务器完成。
缺点:当项目十分庞大时,加大了服务器端的压力,同时在浏览器端不能输入制定的url路径进行指定模块的访问。另外一个就是如果当前网速过慢,那将会延迟页面的加载,对用户体验不是很友好。
C. 什么时候使用前端路由?
在单页面应用,大部分页面结构不变,只改变部分内容的使用
D. 前端路由有什么优点和缺点?
优点:
用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,快速展现给用户
可以再浏览器中输入指定想要访问的url路径地址。
实现了前后端的分离,方便开发。有很多框架都带有路由功能模块
缺点:
使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
目前前端流行的三大框架,都有自己的路由实现
vue:vue-router
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用
我们可以访问其官方网站对其进行学习: https://router.vuejs.org/zh/
vue-router是基于路由和组件的
路由用于设定访问路径, 将路径和组件映射起来.
在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.
for in和for of的区别
都可以进行遍历
for in
遍历数组的索引index
更适合遍历对象,遍历数组会存在一些问题 例如:index索引为字符串类型的数字,不能直接进行几何运算
遍历数组所有的可枚举属性,包括原型,使用hasOwnProperty()方法可以判断某属性是不是该对象的实例属性
for of (ES6)
遍历数组的元素值(value,不包括原型
适合遍历数、数组对象、字符串、map、set等拥有迭代器对象iterator的集合,但是不能遍历对象,想要遍历对象可以使用for in 或者内建的Object.keys()方法
// for in
var obj = {a:1, b:2, c:3}
for (let key in obj) {
console.log(key)
}
// a b c
//for of
const array1 = [‘a’, ‘b’, ‘c’]
for (const val of array1) {
console.log(val)
}
// a b c
浮动
是网页属性中一个非常重要的属性(可以实现元素并排),一开始设计的初衷是为了网页的文字环绕效果
css样式表中使用float表示,它有
属性值:none (不浮动) left(左浮动) right(右浮动) inherit(继承父元素的浮动属性)
浮动的元素脱离了标准文档流(元素排版布局过程中,元素会默认从左到右,从上到下的流式排列方式),即脱标
浮动的元素互相贴靠
清除浮动的方式
1、父盒子设置固定高度
对于不知道高度的盒子不适合
2、内墙法
在浮动元素后面加一个空的块级元素(div)且该元素设置clear:both属性(清除浮动元素对我左右两边的影响)
3、伪元素清除法
.clearfix:after{
content:’.’; //给.clearfix
元素内部最后添加一个内容,该内容为行内元素
display: block; //设置该元素为块级元素,符合内墙法的需求
clear: both; //清除浮动的方法。必须要写
overflow: hidden; //如果用display:none;
,那么就不能满足该元素是块级元素了。overflow:hidden;
表示隐藏元素,与display:none;
不同的是,前者隐藏元素,该元素占位置,而后者不占位置。
height: 0;
}
BFC
块级格式化上下文
浮动不会影响其它BFC中元素的布局,而清除只能清除同一BFC中在它前面的元素的浮动
只要让父盒子形成了BFC区域,那么它就只会清除区域中浮动元素带来的影响
Box 盒子,页面的基本构成元素,分为inline、block、inline-block三种类型的BOX
FC:Formatting Context 是W3C的规范中的一种概念,它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其它元素的关系和相互作用,分类BFC和IFC
BFC(Block formatting context)直译为”块级格式化上下文”。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
BFC布局规则
1.内部的Box会在垂直方向,一个接一个地放置。
2.Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
3.每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
4.BFC的区域不会与float 元素重叠。
5.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
6.计算BFC的高度时,浮动元素也参与计算
哪些元素会生成BFC
1.根元素
2.float属性不为none
3.position为absolute或fixed
4.display为inline-block
5.overflow不为visible
定位
用于指定一个元素在文档中的定位方式
static
relative 并未脱离文档流
absolute 脱离了文档流 以最近的非静态定位的父元素进行定位,如果没有的话,则以页面左上角进行定位
fixed 脱离了文档流,以浏览器视口本身进行定位
flex布局
1、设置父元素display:flex;
2、设置justify-content: center;水平居中
3、align-items:center; 垂直居中
轴
在 flex 布局中,flex-direction
属性决定主轴的方向(row,column,row-reverse,column-reverse),交叉轴的方向由主轴确定。
主轴:main axis
主轴的起始端由 flex-start
表示,末尾段由 flex-end
表示。不同的主轴方向对应的起始端、末尾段的位置也不相同。
交叉轴:cross axis
容器
父容器可以统一设置子容器的排列方式,子容器也可以单独设置自身的排列方式,如果两者同时设置,以子容器的设置为准。justify-content
属性决定子容器沿主轴的排列方式,align-items
属性决定子容器沿着交叉轴的排列方式。
父容器
设置子容器沿主轴排列:justify-content
flex-start:起始端对齐
flex-end:末尾段对齐
center:居中对齐
space-around:子容器沿主轴均匀分布,位于首尾两端的子容器到父容器的距离是子容器间距的一半。
space-between:子容器沿主轴均匀分布,位于首尾两端的子容器与父容器相切。
设置子容器如何沿交叉轴排列:align-items
flex-start
flex-end
center
baseline 基线对齐,这里的baseline默认是指首行文字,所有子容器向基线对齐
stretch:子容器沿交叉轴方向的尺寸拉伸至与父容器一致。
设置换行方式:flex-wrap
轴向与换行组合设置:flex-flow (flex-direction 与 flex-wrap 的组合)
flex-flow: row wrap
多行沿交叉轴对齐:align-content
当子容器多行排列时,设置行与行之间的对齐方式。
flex-start:起始端对齐
flex-end:末尾段对齐
center:居中对齐
space-around:等边距均匀分布
space-between:等间距均匀分布
stretch:拉伸对齐
子容器
在主轴上如何伸缩:flex
子容器是有弹性的(flex 即弹性),它们会自动填充剩余空间,子容器的伸缩比例由
flex
属性确定。flex
的值可以是无单位数字(如:1, 2, 3),也可以是有单位数字(如:15px,30px,60px),还可以是none
关键字。子容器会按照flex
定义的尺寸比例自动伸缩,如果取值为none
则不伸缩flex
是多个属性的缩写,允许 1 - 3 个值连用,但通常用 1 个值就可以满足需求,它的全部写法可参考下图。
设置基准大小:flex-basis
表示在不伸缩的情况下子容器的原始尺寸,主轴为横向时代表宽度,主轴为纵向时代表高度。
设置扩展比例:**flex-grow **子容器弹性伸展的比例
如图,剩余空间按 1:2 的比例分配给子容器。
设置收缩比例:flex-shrink
子容器弹性收缩的比例。如图,超出的部分按 1:2 的比例从给子容器中减去。
设置排列顺序:order
改变子容器的排列顺序,覆盖 HTML 代码中的顺序,默认值为 0,可以为负值,数值越小排列越靠前。
单独设置子容器如何沿交叉轴排列:align-self
flex-start:起始端对齐
flex-end:末尾段对齐
center:居中对齐
baseline:基线对齐
stretch:拉伸对齐
grid布局
grid布局即网格布局,是一种新的css布局模型,比较擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系,是目前唯一一种css二维布局
声明:
display:grid(块级元素)/inline-grid(行内元素)
网格轨道:
grid-template-columns 列宽
grid-template-rows 行高
网格单元:
一个网格单元是在一个网格元素中最小的单位, 从概念上来讲其实它和表格的一个单元格很像。
网格线:
划分网格的线,称为”网格线”。应该注意的是,当我们定义网格时,我们定义的是网格轨道,而不是网格线。Grid 会为我们创建编号的网格线来让我们来定位每一个网格元素。m 列有 m + 1 根垂直的网格线,n 行有 n + 1 跟水平网格线。
repeat(次数,数值)
auto-fill关键字:表示自动填充,让一行(或者一列)中尽可能容纳更多的单元格
fr关键字:
fr单位代表网格容器中可用空间的一等份,grid-template-columns: 200px 1fr 2fr
表示第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/3 和 2/3。
minmax()函数:
我们有时候想给网格元素一个最小和最大的尺寸,minmax()
函数产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。它接受两个参数,分别为最小值和最大值。grid-template-columns: 1fr 1fr minmax(300px, 2fr)
的意思是,第三个列宽最少也是要 300px,但是最大不能大于第一第二列宽的两倍。
auto关键字:
由浏览器决定长度。通过 auto
关键字,我们可以轻易实现三列或者两列布局。grid-template-columns: 100px auto 100px
表示第一第三列为 100px,中间由浏览器决定长度。
grid-row-gap
属性、grid-column-gap
属性分别设置行间距和列间距。grid-gap
属性是两者的简写形式。grid-row-gap: 10px
表示行间距是 10px,grid-column-gap: 20px
表示列间距是 20px。grid-gap: 10px 20px
实现的效果是一样的。
grid-template-areas:
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: 120px 120px 120px;
grid-template-areas:
". header header"
"sidebar content content";
background-color: #fff;
color: #444;
}
上面代码表示划分出 6 个单元格,.
符号代表空的单元格,也就是没有用到该单元格
用于定义区域,一个区域由一个或者多个单元格组成,一般这个属性跟网格元素的 grid-area
一起使用,我们在这里一起介绍。 grid-area
属性指定项目放在哪一个区域。
.sidebar {
grid-area: sidebar;
}
.content {
grid-area: content;
}
.header {
grid-area: header;
}
以上代码表示将类 .sidebar
.content
.header
所在的元素放在上面 grid-template-areas
中定义的 sidebar
content
header
区域中.
grid-auto-flow:
控制自动布局算法怎样运作,精确指定在网格中被自动布局的元素怎样排列。默认的放置顺序是”先行后列”,即先填满第一行,再开始放入第二行,即下图英文数字的顺序 one
,two
,three
…。这个顺序由 grid-auto-flow
属性决定,默认值是 row
。
grid-auto-flow: row dense
,表示尽可能填满表格
justify-items
属性设置单元格内容的水平位置(左中右),align-items
属性设置单元格的垂直位置(上中下)
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}
- start:对齐单元格的起始边缘
- end:对齐单元格的结束边缘
center:单元格内部居中
stretch:拉伸,占满单元格的整个宽度(默认值)
justify-content
属性是整个内容区域在容器里面的水平位置(左中右),align-content
属性是整个内容区域的垂直位置(上中下)。它们都有如下的属性值。
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
函数柯里化
使用多个参数的函数转化为一系列使用一个参数的函数的技术,它返回一个新的函数,这个新函数去处理剩余的参数
bind、apply、call的用法
相同点:改变this的指向,接收的第一个参数都是this要指向的对象
不同点:bind和call传参相同,多个参数依次传入,apply传入数组,call和apply都是对函数进行直接调用,bind不会立即调用函数,而是立即返回一个修改this后的函数,需要调用这个函数才会执行
let obj = {
name: "xiaoming",
age: 24,
sayHello:function (job,hobby) {
console.log(`我叫${this.name},今年${this.age}岁,我的工作是${job},我的爱好是${hobby}.`)
}
}
obj.sayHello('程序员','看美女');
let obj2 = {
name: 'lihua',
age: 30
}
// 开始调用call
obj.sayHello.call(obj2,'设计师','画画');
// 开始调用apply
obj.sayHello.apply(obj2,['设计师','画画']);
// 开始调用bind
var hh = obj.sayHello.bind(obj2,'设计师','画画');
hh();
// 手撕call
// 1、改变this指向
// 2、执行函数fn
Function.prototype.myCall = function(_this,...args) {
if(!_this) _this = Object.create(null)
// 改变this指向 通过原型我们知道调用call的肯定是函数,this本来是指向调用call的那个函数的
// 现在使用_this.fn来接收原来的this,就是改变了this的指向
_this.fn = this
const res = this.fn(...args)
// 调用完就删除拓展属性
delete _this.fn
return res
}
// 调用
function sum(a,b) {
return this.v + a + b;
}
sum.myCall({v:1},2,3) // 6
// 手撕apply
Function.prototype.myApply = function(_this,args = []) {
if(!_this) _this = Object.create(null)
_this.fn = this
const res = this.fn(...args)
delete _this.fn
return res
}
// 手撕bind
Function.prototype.myBind = function(_this,...args) {
// 将原函数的this传递给fn
const fn = this
// 返回一个新函数 返回的新函数也是可以继续传递参数的
return function F(...args2) {
return this instanceof F? new fn(...args,...args2):fn.apply(_this,args.concat(args2))
}
}
promise的用法
回调函数:将一个方法func2作为参数传入到另一个方法func1中,当func1执行到某一步或者满足某种条件的时候才执行传入的参数func2
Promise是ES6引入的异步编程的新解决方案
Promise对象的三种状态:初始化、成功、失败pending-进行中、resolved-已完成、rejected-已失败
解决
回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
promise 可以支持多个并发的请求,获取并发请求中的数据
这个 promise 可以解决异步的问题,本身不能说 promise 是异步的
基本用法
构造 promise 实例,然后调用 .then.then.then 的编写代码方式,就是 promise。
// 调用Promise构造函数
let p = new Promise((resolve,reject) => {
// 做一些事情
if( ) {
resolve()
} else {
reject()
}
})
p.then(() => {
// 如果p的状态被resolve了,就进入这里
}, () => {
// 如果p的状态被reject
})
// 调用 Promise 对象的then方法,两个参数为函数
p.then(function(value){ // 成功
console.log(value);
}, function(season){ // 失败
console.log(season);
});
声明一个Promise对象
new Promise((resolve, reject) => { // 这两个方法主要是用来修改状态的
console.log("开始求婚。")
console.log("。。。。。")
console.log("考虑一下。")
setTimeout(() => {
if (isHandsome || isRich) { // 当我们调用 resolve 函数的时候,Promise 的状态就变成 resolved
resolve('我同意!')
} else { // 当我们调用 reject 函数的时候,Promise 的状态就变成 reject
reject("拒绝:我们八字不合")
}
}, 2000)
})
// 如果一个 promise 已经被兑现(resolved)或被拒绝(rejected),那么我们也可以说它处于已敲定(settled)状态。
Promise.prototype.catch()方法 用来捕获Promise的错误
和then的第二个参数一样,用来指定reject的回调,用法:
在执行resolve的回调时,也就是then的第一个参数时,如果抛出异常了(出错了),那么并不会报错卡死js,而是会进到这个catch方法中
promise.then(
() => { console.log('this is success callback!')}
).catch (
(err) => {console.log(err)}
)
Promise.all()方法:可以并行的执行异步操作,并且在一个回调中处理所有的返回数据,在所有异步操作执行完后才执行回调。
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
手撕promise.all代码题
Promise.race()
OSI七层模型