1.登陆注册要做成受控组件,组件定义state,和表单绑定
2.redux-saga调用数据请求,发送action修改数据,useEffect中发送数据请求,后端比对用户名是否重复,返回state
3.前端根据返回的信息成功跳转登陆页
4.登陆发送数据请求,数据库对比用户名密码是否正确, 根据后端返回的结果进入首页
5.setCookie将用户登录名密码token存cookie中,通过JWT(Json web token)
6.免密登陆,getCookie获取token发给后端对比,根据返回结果决定是否自动登陆
7.注册通过Ant Design组件进行表单正则的验证
8.用户体验,注册的时候跳转其他页面的时候给用户提示是否需要跳转,避免因为跳转后导致注册信息没有了,用组件内后置守卫做
如果输入框都没有填信息,不拦截跳转,如果用户输入信息,弹窗提示,点确定,跳转,点取消,不跳转
1.react中配置二级路由 地址变化 但是界面不更新
使用dva/router中的withRouter高阶组件解决的
2.图表联动怎么实现
我们只需要把当前被选中图表的事件,直接发给其他图表即可,然后判断被选中的图表是哪个作为区分
onTouchEvent(event)普通事件传递
3.产品经理要求智能匹配产品
找网上类似功能的网站 查看源码 和主管讨论
需要一个设计一个投资习惯和风险承受能力测试,
从后端获取这个客户测试的结果 以及客户平常投资的习惯 生成不同的关键字
根据关键字从数据库中匹配产品 展示界面
4.后台管理系统遇到遇到什么奇葩的需求
后台管理系统权限比较细
App高并发比较多,需要做性能优化
\d 匹配数字——\D 匹配非数字
\w 匹配数字字母下划线——\W 匹配非数字字母下划线
\n 匹配一个换行符
\s 匹配任何不可见字符包括空格、制表符、换页符等等——\S 匹配任何可见字符
^ 匹配行首
$匹配输入行尾
*(0到多次)匹配前面的子表达式零次或多次
+匹配前面的子表达式一次或多次
?前面的子表达式零次或一次
{ n } n 是一个非负整数,匹配确定的n次
{ n , } n 是一个非负整数,至少匹配n次
Ajax是一种异步通信的方法,直接由 js 脚本向服务器发起 http 通信,然后根据服务器返回的数据,更新网页的相应部分,而不用刷新整个页面
创建步骤:创建xhr对象 -> 通过open方法配置Ajax请求地址 -> 通过send方法发送请求 -> 监听请求,接收响应
//1:创建Ajax对象
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本
//2:配置 Ajax请求地址
xhr.open('get','index.xml',true);
//3:发送请求
xhr.send(null); // 严谨写法
//4:监听请求,接受响应
xhr.onreadysatechange=function(){
if(xhr.readySate==4&&xhr.status==200 || xhr.status==304)
console.log(xhr.responseXML)
}
JS的加载、解析和执行会阻塞页面的渲染过程,因此JS脚本需要尽可能的延迟加载,提高页面的渲染速度
延迟加载的方式有:
所谓的模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块实现某一特定的功能,模块化开发的基础就是函数
在ES6之前,JavaScript一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍。对此社区制定了一些模块加载方案,如CommonJS、AMD和CMD等
现在ES6已经在语言层面上规定了模块系统,可以取代现有的CommonJS和AMD规范,而且使用起来相当简洁,并且有静态加载的特性
为什么要使用模块化:
JS中现在比较成熟的有四种模块加载方案:
第一种是CommonJS 方案,它通过 require 来引入模块,通过 module.exports 定义模块的输出接口。这种模块加载方案是服务器端的解决方案,它是以同步的方式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题。但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适
第二种是 AMD 方案,这种方案采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。require.js 实现了 AMD 规范
第三种是 CMD 方案,这种方案和 AMD 方案都是为了解决异步模块加载的问题,sea.js 实现了 CMD 规范。它和require.js的区别在于模块定义时对依赖的处理不同和对依赖模块的执行时机的处理不同
第四种方案是 ES6 提出的方案,使用 import 和 export 的形式来导入导出模块
主要区别有两个方面
1.CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
2.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
require.js 的核心原理是通过动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数
首先js是单线程运行的,在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行
在执行同步代码的时候,如果遇到了异步事件,js引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务,当同步事件执行完毕后,再将异步事件对应的回调加入到与当前执行栈中不同的另一个任务队列中等待执行
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)
任务队列可以分为宏任务对列和微任务对列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务对列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行,当微任务对列中的任务都执行完成后再去判断宏任务对列中的任务
异步运行机制如下:
arguments对象是函数中传递的参数值的集合。它是一个类似数组的对象,因为它有一个length属性,我们可以使用数组索引表示法来访问单个值,但它没有数组中的内置方法,如:forEach、reduce、filter和map等,可以使用Array.prototype.slice将arguments对象转换成一个数组
Array.prototype.slice.call(arguments)
由语言提供自动内存管理方式,被称为"垃圾回收机制"。垃圾回收机制会定期(周期性)找出那些不再用到的内存(变量),然后释放其内存
现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除、引用计数
1、标记清除
这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间
2、引用计数
另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存
1.意外的全局变量
2.被遗忘的计时器或回调函数
3.脱离 DOM 的引用
4.闭包
ECMAScript 是编写脚本语言的标准,ECMA(European Computer Manufacturers Association)
JavaScript = ECMAScript + DOM + BOM
块作用域
类
箭头函数
模板字符串
对象解构
Promise
模块
Symbol
代理(proxy)Set
函数默认参数
rest
扩展运算符
数组和对象的扩展
求幂运算符(**)
(因颗录此)
Array.prototype.includes()方法
数组原型的方法,查找一个数值是否在数组中,只能判断一些简单类型的数据,对于复杂类型的数据无法判断。
该方法接受两个参数,分别是查询的数据和初始的查询索引值。
async await
函数参数列表结尾允许逗号
es2017允许函数对象的定义调用时参数可以加入尾逗号,以及json对象array对象都允许
Object.values()
values: [obj],返回obj自身可枚举属性的属性值的集合
(安吹斯)
Object.entries()
entries:[obj], 与values类似,返回的一个2元素的数组
Object.getOwnPropertyDescriptors()
getOwnpropertyDescriptors: [obj],返回obj对象的属性描述符
(get 哦 泼破踢 迪斯亏不踢斯)
String padding:
padStart()和padEnd(),填充字符串达到当前长度
在字符串首位开始添加string直到满足length为止并返回新的字符串
ShareArrayBuffer和Atomics对象,用于从共享内存位置读取和写入
(夏尔 啊锐 八法儿) (啊偷没此)
异步迭代
Promise.finally()
(饭的嘞)
Rest/Spread 属性
(锐斯特)(斯破锐的)
正则表达式命名捕获组(Regular Expression Named Capture Groups)
正则表达式反向断言(lookbehind)
正则表达式dotAll模式
正则表达式 Unicode 转义
(右内扣的)
非转义序列的模板字符串
行分隔符(U + 2028)和段分隔符(U + 2029)符号现在允许在字符串文字中,与JSON匹配
更加友好的JSON.stringify
新增了Array的flat()方法和flatMap()方法
新增了String的trimStart()方法和trimEnd()方法
Object.fromEntries()
Symbol.prototype.description
String.prototype.matchAll
Function.prototype.toString()现在返回精确字符,包括空格和注释
简化try{} catch{},修改catch绑定
新的基本数据类型BigInt
globalThis
import()
Legacy RegEx
私有的实例方法和访问器
私有变量
ES11在类中新增私有变量控制符#,在内部变量或者函数前添加一个hash符号#,
可以将它们设置为私有属性,只能在类的内部可以使用。
空值合并运算符
空值合并操作符就是 ?? :如果左侧的值为null或者undefined就返回左侧的值,如果没有就返回右侧的值
可选链操作符
可选链操作符 (?.) :如果左侧表达式有值,就会继续访问右侧的字段
BigInt
使用BigInt的方式有两种:
1.在数字后面加n
2.使用BigInt函数
动态导入
globalThis
提供一种标准化的方式去访问全局对象,可以在任意上下文中获取全局对象自身,并且不用担心环境的问题
Promise.all缺陷与Promise.allSettled
promise.all可以并发执行异步任务,如果其中某个任务执行出现了异常,所有任务都会over,Promise会直接进入reject状态
使用Promise.allSettled,它会创建一个新的promise,在所有promise完成后返回一个包含每个promise结果的数组
1.var声明的变量会挂载在window上,而let和const声明的变量不会
2.var声明变量存在变量提升,let和const不存在变量提升
3.let和const声明形成块作用域
4.同一作用域下let和const不能声明同名变量,而var可以
5.const 一旦声明必须赋值,不能使用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改其属性
暂存性死区是相对于某一个变量来说的,就是在定义该变量之前的区域就是暂存性死区
const i = 1
{
//死区开始
console.log(i) //死区里边拿不到外边的i,也拿不到本代码块内的i
//死区结束
const i = 2
console.log(i) //直到这里才能正常使用 i
}
在var中执行的时候:
在let中执行的时候:
箭头函数表达式的语法比函数表达式更简洁
箭头函数没有自己的this值,箭头函数里的this指向的是父级的this.
箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数
在箭头函数中,当只有一个表达式或值需要返回,可以省略return语句,箭头函数有一个隐式的返回
箭头函数不能访问arguments对象,我们可以使用rest参数来获得在箭头函数中传递的所有参数
模板字符串是在 JS 中创建字符串的一种新方法,可以通过使用反引号使模板字符串化,可以使用${expr}嵌入一个表达式,这比ES5版本更方便
对象解构是从对象或数组中获取或提取值的一种新的、更简洁的方法
可以在解构时为属性取别名
let { firstName: fName, position } = employee;
如果解构的属性值为 undefined,还可以指定默认值
let { firstName = “Mark” } = employee;
一、创建Set对象实例
Set 对象可以存储任何类型的唯一值,无论是原始值或者是对象引用
1.构造函数
语法:new Set([iterable])
参数:iterable 如果传递一个可迭代对象,它的所有元素将被添加到新的Set中,如果不指定此参数或其值为null,则新的 Set为空
二、Set实例属性
size属性将会返回Set对象中元素的个数
三、Set实例方法
1.add( ) 方法用来向一个 Set 对象的末尾添加一个指定的值
语法:mySet.add(value)
参数:value 必需,需要添加到 Set 对象的元素的值
2.delete( ) 方法可以从一个 Set 对象中删除指定的元素
语法:mySet.delete(value)
参数:value 将要删除的元素
返回值:成功删除返回 true,否则返回 false
3.clear( ) 方法用来清空一个 Set 对象中的所有元素
语法:mySet.clear( )
4.has( ) 方法返回一个布尔值来指示对应的值value是否存在Set对象中
语法:mySet.has(value)
参数:value 必须,是否存在于Set的值
返回值:如果指定的值(value)存在于Set对象当中,返回true; 否则返回 false
5.entries( )
语法:mySet.entries( )
返回值:一个新的包含 [value, value] 形式的数组迭代器对象,value 是给定集合中的每个元素,迭代器 对象元素的顺序即集合对象中元素插入的顺序
6.values( )
语法:mySet.values( ) 或者 mySet.keys( )
返回值:返回一个 Iterator(因特瑞特) 对象,这个对象以插入Set对象的顺序包含了原 Set 对象里的每个元素
7.forEach()
语法:mySet.forEach(callback[, thisArg])
参数:callback 每个元素都会执行的函数,thisArg 当执行callback函数时候,可以当作this来使用
应用场景:
1、简单数组去重
2、JSON数组去重
JSON数组是比较常见的一种数据结构,形如[{…},…{…}],假如需要统计某个属性中不同的值
step1:先使用.map将JSON数组变成简单数组,然后用set执行去重
step2: 由于生成的Set属于可迭代对象,所以可以使用数组解构符进行解构
3、二维数组去重
4、数组之间的对比
WeakSet和Set结构类似,也是不重复的值的集合,但WeakSet的成员只能是对象(null 除外)。而且 WeakMap 的键名所指向的对象,不计入垃圾回收机制
WeakSet的API:
为什么WeakSet不可遍历
因为WeakSet的成员都是弱引用,随时可能消失,成员是不稳定的
WeakSet的用处:
使用ws储存DOM节点,就不用担心节点从文档移除时,会引发内存泄漏(即在被移除的节点上绑定的click等事件
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
函数式编程(通常缩写为FP)是通过编写纯函数,避免共享状态、可变数据、副作用来构建软件的过程。函数式编程是声明式的而不是命令式的,应用程序的状态是通过纯函数流动的,函数式编程是一种编程范式 ,函数式的代码比面向对象的代码更简洁,更可预测,更容易测试
高阶函数也是函数,不同的是输入的参数和返回的值这两项中的一项必须是函数才能叫高阶函数。常用的的高阶函数,比如:map、filter、reduce等
在编程语言中,一等公民可以作为函数参数,可以作为函数返回值,也可以赋值给变量
在JavaScript中,函数不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样:
赋值——(var func = function( ){ })
传参——(function func(x,callback){callback( );})
返回——(function( ){return function( ){ }}),
这样的函数也称之为第一级函数(First-class Function)。JavaScript中的函数还充当了类的构造函数的作用,同时又是一个Function类的实例(instance)。所以JavaScript的函数变得非常重要
回调函数是一个匿名函数,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码。可以让异步代码同步执行
缺点:
回调函数有一个致命的弱点,就是容易写出回调地狱(Callback hell)由多层嵌套的回调函数组成的代码称为回调地狱,多数在写阻塞执行代码的时候会产生。回调地狱的代码可读性差,很难让人弄清楚业务逻辑
回调可能会发生控制反转的影响,因为回调把控制权交给第三方(而第三方工具通常不是受我们控制的)来调用你的代码。这种控制反转导致一系列的麻烦的信任问题,使得回调的结果可能和我们的预期不一样
instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
实现 instanceof:
function myInstanceof(left, right) {
let prototype = right.prototype
left = left.__proto__
while (true) {
if (left === null || left === undefined)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性
单例模式(Singleton Pattern)
单例模式中Class的实例个数最多为1。当需要一个对象去贯穿整个系统执行某些任务时,单例模式就派上了用场。而除此之外的场景尽量避免单例模式的使用,因为单例模式会引入全局状态,而一个健康的系统应该避免引入过多的全局状态
工厂模式
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型
使用场景:如果你不想让某个子系统与较大的那个对象之间形成强耦合,而是想运行时从许多子系统中进行挑选的话,那么工厂模式是一个理想的选择
JavaScript一共有8种数据类型
JavaScript不支持任何创建自定义类型的机制,而所有值最终都将是上述 8 种数据类型之一
&& 叫逻辑与,在其操作数中找到第一个虚值表达式并返回它,如果没有找到任何虚值表达式,则返回最后一个真值表达式。它采用短路来防止不必要的工作
|| 叫逻辑或,在其操作数中找到第一个真值表达式并返回它。这也使用了短路来防止不必要的工作。在支持 ES6 默认函数参数之前,它用于初始化函数中的默认参数值
!! 运算符可以将右侧的值强制转换为布尔值
在 JS 中类型转换只有三种情况,分别是:
转换为布尔值——调用Boolean( )方法
转换为数字——调用Number( )、parseInt( )和parseFloat( )方法
转换为字符串——调用.toString( )或者String( )方法
js 中的内置对象主要指的是在程序执行前存在全局作用域里的由 js定义的一些全局属性、函数和用来实例化其他对象的构造函数对象。一般如全局变量值 NaN、undefined,全局函数如 parseInt( )、parseFloat( ) ,用来实例化对象的构造函数如 Date、Object 等,还有提供数学计算的单例内置对象如 Math 对象
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化
当我们对两种类型使用 typeof 进行判断的时候,Null 类型化会返回 “object”,这是一个历史遗留的问题。当我们使用双等号对两种类型的值进行比较时会返回 true,使用全等时会返回 false
{} 的 valueOf 结果为 {} ,toString 的结果为 "[object Object]"
[] 的 valueOf 结果为 [] ,toString 的结果为 ""
作用域:
作用域链:
使用字面量的形式直接创建对象,但是这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码
工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系
构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。执行构造函数首先会创建一个对象,然后将对象的原型指向构造函数的 prototype 属性,然后将执行上下文中的 this 指向这个对象,最后再执行整个函数,如果返回值不是对象,则返回新建的对象。因为 this 的值指向了新建的对象,因此我们可以使用 this 给对象赋值。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此我们可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建,因为在 js 中函数也是一个对象,因此如果对象属性中如果包含函数的话,那么每次我们都会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有的实例都可以通用的
原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此我们可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例
组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此我们可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,因为使用了两种不同的模式,所以对于代码的封装性不够好
动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。这一种方式很好地对上面的混合模式进行了封装
1、在浏览器里,在全局范围内this 指向window对象
2、在函数中,this永远指向最后调用他的那个对象
3、构造函数中,this指向new出来的那个新的对象
4、call、apply、bind中的this被强绑定在指定的那个对象上,apply、call、bind都是js给函数内置的一些API,调用他们可以为函数指定this的执行,同时也可以传参
5、箭头函数中this比较特殊,箭头函数this为父作用域的this,不是调用时的this,要知道前四种方式都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来
DOM指的是文档对象模型,它指的是把文档当做一个对象来对待,这个对象主要定义了处理网页内容的方法和接口
BOM指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的方法和接口,BOM的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器的一个接口,又是一个 Global对象,这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window 对象含有 location 对象、navigator对象、screen对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象
事件是用户操作网页时发生的交互动作或者网页本身的一些操作,现代浏览器一共有三种事件模型
IE 事件模型:
DOM0级模型:
DOM2 级事件模型:
本质上是利用了事件冒泡的机制,并且父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件委托
事件传播有三个阶段:
什么是事件捕获
document
往事件触发对象,从外向内捕获事件对象什么是事件冒泡
(1)创建新节点
createDocumentFragment() //创建一个DOM片段 (科瑞A特)(法歌们特)
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
(2)添加、移除、替换、插入
appendChild(node)
removeChild(node)
replaceChild(new,old)
insertBefore(new,old)
(3)获取、查找
getElementById();
getElementsByName();
getElementsByTagName();
getElementsByClassName();
querySelector();
querySelectorAll();
(4)属性操作
getAttribute(key);
setAttribute(key, value);
hasAttribute(key);
removeAttribute(key);
1、Object.prototype.toString.call( )
2、constructor
3、instanceOf
4、typeOf
原型:
Javascript规定,每一个函数都有一个prototype对象属性,指向另一个对象
prototype就是调用构造函数所创建的那个实例对象的原型
原型链:
实例对象与原型之间的连接,叫做原型链。
JS在创建对象的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。
获取原型的方法
p.proto
p.constructor.prototype
Object.getPrototypeOf(p)
1、prototype:
每一个函数都有一个prototype这个属性,而这个属性指向一个对象,这个对象我们叫做原型对象
作用:节约内存扩展属性和方法可以实现类之间的继承
2、__proto__:
每一个对象都有一个__proto__属性,__proto__指向创建自己的那个构造函数的原型对象对象可以直接访问__proto__里面的属性和方法
3、constructor:
指向创建自己的那个构造函数 ,是原型上的方法
总结:
当我们创建一个构造函数的时候这个构造函数自带了一个prototype属性,而这个属性指向一个对象,也就是原型对象。 这个原型对象里面有一个constructor构造器,它的作用是指向创建自己的构造函数。
除此之外 prototype还可以存放公共的属性和方法。
当我们实例化一个对象的时候(被new调用的时候),这个对象自带了一个 proto 属性,
这个proto 指向创建自己的构造函数的原型对象。可以使用这个原型对象里面的属性和方法
constructor( )方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的 constructor( )方法会被默认添加
1、构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
2、构造函数和普通函数的区别在于:调用方式不一样,作用也不一样(构造函数用来新建实例对象)
3、调用方式不一样。
a.普通函数的调用方式:直接调用 person();
b.构造函数的调用方式:需要使用new关键字来调用 new Person();
4、构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数名,也是这个对象的类名
5、构造函数内部使用this 来构造属性和方法
6、普通函数:如果没有返回值,返回值为undefined
7、构造函数:构造函数会马上创建一个新对象,并将该新对象作为返回值返回
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
原因:由于浏览器的同源策略,即属于不同域的⻚面之间不能相互访问各自的⻚面内容
解决方法
1、后端代理
2、jsonp
3、反向代理
// proxy webpack配置
"proxy": {
"/index.php": {
"target": "http://qinqin.net",
"changeOrigin": true
}
}
4、CORS解决跨域(xhr2)(后端)
什么是闭包
函数嵌套函数,能够读取其他函数内部变量的函数
优缺点
优点:
使用闭包是不会污染全局环境
方便进行模块化开发
延长形参的生命周期
缺点:
就是不恰当使用会造成内存泄漏 【解决方式:清除变量】
不适用与返回函数是一个特别大的函数
闭包的应用场景
函数防抖
函数节流
模块化开发
Promise是es6新增的,异步编程的一种解决方案,用来取代回调函数和事件,比传统的解决方案——回调函数和事件——更合理和更强大。
Promise 对象用于延迟(deferred) 计算和异步(asynchronous)计算。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。Promise 对象是一个返回值的代理,异步方法会返回一个包含了原返回值的 promise 对象来替代原返回值
有三种状态:pending(进行中)、resolve(已成功)、rejected(已失败)
promise的特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作
(2)一旦状态设定,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为resolve和从pending变为rejected,只要这两种情况发生,状态就凝固了
promise的基本使用:
通过new promise创建一个promise对象,里面有一个参数,参数是一个回调函数,回调函数中有2个参数:resolve(将Promise对象的状态从“未完成”变为“成功”)、reject(将Promise对象的状态从“未完成”变为“失败”) ,resolve( )当异步执行成功的时候调用的方法,reject( )当异步失败的时候调用的方法
除此之外promise有一个then方法,当成功的时候执行第一个回调函数,当失败的时候执行第二个回调函数。第二个回调函数也可以使用catch方法代替
三:Promise.prototype.finally
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作,该方法是 ES2018 引入标准的
promise的静态方法
Promise.all( ):用于将多个 Promise 实例,包装成一个新的 Promise 实例,接受一个数组作为参数,只有数组里面的每个状态都变成resolve,则新的 Promise 实例状态才会变成resolve
Promise.race( ):将Promise对象数组中最先执行完成的内容通过后面then传出
async异步能干什么
用来修饰函数,使该函数异步执行,不阻碍后续函数的执行
await只能放在async中,且只能修饰promise对象,await会阻塞后续的执行,直到异步操作完成
1. promise的诞生是为了简化函数嵌套调用流程,也便于后续维护
2. async/await定义了异步函数,并在其内部可通过await等待promise对象,阻塞后续的执行
async与Promise的主要区别是:
Promise代码完全都是Promise的API(then、catch等等),操作本身的语义反而不容易看出来
async / await函数的实现最简洁,最符合语义,几乎没有语义不相关的代码,async / await 函数就是 Generator 函数的语法糖
async/await函数的优势
Pomise.all的使用
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
Promise.race的使用
Promise.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
Generator 的中文名称是生成器,它是ECMAScript6中提供的新特性。
在过去,封装一段运算逻辑的单元是函数。函数只存在“没有被调用”或者“被调用”的情况,
不存在一个函数被执行之后还能暂停的情况,而Generator的出现让这种情况成为可能。
通过 function* 来定义的函数称之为“生成器函数”(generator function),它的特点是可以中断函数的执行,
每次执行yield语句之后,函数即暂停执行,直到调用返回的生成器对象的next()函数它才会继续执行。
也就是说 Generator 函数是一个状态机,封装了多个内部状态。
执行 Generator 函数返回一个遍历器对象(一个指向内部状态的指针对象),
调用遍历器对象的next方法,使得指针移向下一个状态。每次调用next方法,
内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
yield关键字
真正让Generator具有价值的是yield关键字,这个yield关键字让 Generator内部的逻辑能够切割成多个部分。
发现函数执行到第一个yield关键字的时候就停止了。要让业务逻辑继续执行完,需要反复调用.next()
可以简单地理解为yield关键字将程序逻辑划分成几部分,每次.next()执行时执行一部分。
这使得程序的执行单元再也不是函数,复杂的逻辑可以通过yield来暂停。
.next()调用时,返回一个对象,这个对象具备两个属性。
其中一个属性是布尔型的done。它表示这个Generator对象的逻辑块是否执行完成。
另一个属性是value,它来自于yield语句后的表达式的结果。
通过.next()传递参数,可以赋值给yield关键字前面的变量声明。
深/浅拷贝针对的是引用类型
浅拷贝
深拷贝
3、工具实现【第三方封装库】——lodash
Set:它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构,数组作为参数。
不说set 数据结构Set new set()存储数据 set.size得到存储的数据长度
has()判断某个值是否存在set中 foreach遍历set
不说map : new map map.set map.get map.delete
都是用来存储数据用的,但是存储的数据格式不同
set 直接存储 任意类型数据
map 存储数据的时候,必须以key,value的形式,
set 使用forEach 遍历的时候,key和value值是一样的
而map 遍历的时候,key就是存进去的对象的key,value就是存在的值
for循环这种写法比较麻烦,因此数组提供内置的forEach方法。
forEach没有返回值,无法中途跳出forEach循环,break命令或return命令都不能奏效。
for...in循环主要是为遍历对象而设计的,不适用于遍历数组**
for...of循环相比上面几种做法,有一些显著的优点。
有着同for...in一样的简洁语法,但是没有for...in那些缺点。
不同于forEach方法,它可以与break、continue和return配合使用。
提供了遍历所有数据结构的统一操作接口。
js 是单线程执行的,js中的任务按顺序一个一个的执行,但是一个任务耗时太长,那么后面的任务就需要等待,为了解决这种情况,将任务分为了同步任务和异步任务,而异步任务又可以分为微任务和宏任务
概念
运行机制
微任务:process.nextTick、MutationObserver、Promise.then catch finally
宏任务:I/O、setTimeout、setInterval、setImmediate、requestAnimationFrame
js执行顺序,先同步再异步,在此基础上先宏任务再微任务
流程
同步和异步任务分别进入不同的执行“场所”,同步进入主线程,异步进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,回去了Event Queue读取对应的函数,进入主线程
上述过程会不断重复,也就是常说的Event Loop(事件循环)
但是,JS异步还有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入event queue,然后再执行微任务,将微任务放入event queue,但是,这两个queue不是一个queue。当你往外拿的时候先从微任务里拿这个回调函数,然后再从宏任务的queue拿宏任务的回调函数
1、定时器都是异步操作
2、事件绑定都是异步操作
3、AJAX中一般我们都采取异步操作(也可以同步)
4、回调函数可以理解为异步(不是严谨的异步操作)
5、promise
6、generator(ES6) 通过yield关键字可以让任务在需要的地方暂停,每一步的值可以通过next获取
7、async/await(ES7) await得到的就是async异步返回值,底层原理还是promise中的resolve方法
8、设计模式-发布订阅模式
9、事件监听
使用正则去限定或者将输入框的type设置为number
Proxy用于修改某些操作的默认行为,即对编程语言层面进行修改,属于“元编程”,Proxy意思为“代理”,即在访问对象之前建立一道“拦截”,任何访问该对象的操作之前都会通过这道“拦截”,即执行Proxy里面定义的方法
let pro = new Proxy(target,handler)
其中 new Proxy相当于创建了一个Proxy实例,target为所要拦截的目标对象,handler也是一个对象,里面定义的是对拦截对象所要进行的拦截方法
Proxy也可以作为其他对象的原型对象使用
上述实例将pro作为obj的原型对象使用,虽然obj本身没有name这个属性,但是根据原型链,会在pro上读取到name属性,之后会执行相对应的拦截操作。
let pro = new Proxy(target,handler);
let obj = Object.create(pro);
get(target,name,property)方法
用于拦截某个读取属性的操作,第一个参数为目标对象,第二个参数为属性名称,第三个属性为操作所针对的对象(可选参数)
set(target,name,value,property)
用于拦截某个属性的赋值操作,第一个参数为目标对象,第二个参数为属性名,第三个参数为属性值,第四个参数为操作行为所针对的对象(可选参数)
has(target,key)
用来拦截对象是否具有某个属性值的操作,第一个参数为目标对象,第二个参数为属性名
Reflect(锐付莱克特)对象:
Reflect设计的目的是为了优化Object的一些操作方法以及合理的返回Object操作返回的结果,对于一些命令式的Object行为,Reflect对象可以将其变为函数式的行为
Reflect(target,name,property) Reflect.has(obj,"name") Reflect.get(target,name,property)
减少请求数量
图片处理
雪碧图
gulp
Base64
使用字体图标来代替图片 - 自定义字体 @font-face{}
在安卓下可以使用webp格式的图片
减小资源大小 - webpack优化
HTML压缩
CSS压缩
JS压缩与混乱
图片压缩
优化网络连接
cdnCDN即内容分发网络,它能够实时地根据网络流量和各节点的连接、负载状
用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度
优化资源加载
资源加载位置
1、CSS文件放在head中,先外链,后本页
2、JS文件放在body底部,先外链,后本页
3、body中间尽量不写style标签和script标签
资源加载时机
1、异步script标签
2、模块按需加载需要根据路由来加载当前页面需要的业务模块
3、资源懒加载与资源预加载
减少重绘回流
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color。则就叫称为重绘。
回流必将引起重绘,而重绘不一定会引起回流。
css3硬件加速(GPU加速)
六.【DOM优化】
1、缓存DOM
2、减少DOM深度及DOM数量
3、批量操作DOM
4、批量操作CSS样式
5、在内存中操作DOM
6、DOM元素离线更新
7、DOM读写分离
8、事件代理
9、防抖和节流
10、及时清理环境
new出来一个实例对象是否带有static属性 static用ES5怎么写
没有创建对象,也能使用属性和调用方法
用来形成静态代码块以优化程序性能。因为只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次
被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。
类第一次加载初始化的时候就去加载static部分,后面可以重新赋值
static用ES5怎么写: 静态是通过类名直接调用 class A staticB
直接用A.B 将B绑定在A上
同步还是异步
await同步
async异步
async和await有两个关键字,一个写在函数外面,一个写在函数里面,函数外面是异步的,函数里面是同步的,调用函数的那一行其实是异步的,下一行
函数里面转成阻塞的
async await => promise 改写
async函数中
let a=await promise 的a函数
let b=await promise 的b函数
promise.all改写
Promise.allSettled Promise.any
promise实现promise.all的方法
async使用的时候报错,如何捕获try...catch
var test3 = async function () {
try {
await p1();
await p2();
p3();
} catch (e) {
console.log('p1失败了', e)
}
}
await后面有个接口
接口要2S才能完成 接口2S才会执行
没区别
设置请求头 请求头中携带cookie
为什么在react中要使用浅拷贝
redux中要求:状态是只读的,唯一且不可修改的,reducer必须是一个纯函数
因为redux中数据不可更改,所以redux中的数据应该要拷贝 返回一个新值
1:jQuery ajax
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
headers: {userToken:token},
success: function() {},
error: function() {},
})
优缺点:
2:axios
axios({
method: 'POST',
url: url,
data: {},
headers: {},
})
.then(functon (response) {
console.log(response)
})
.catch(function(error)) {
consol.log(error)
}
优缺点:
3:fetch
fetch api 是基于promise的设计,是为了取代传统的xhr不合理的写法而产生的
fetch(url).then(function(response){
return response.json();
}).then(function(data) {
console.log(data);
}).catch(function(e) {
console.log('Oops,error')
})
优缺点:
注意:
fetch( )返回的是一个Promise对象 fetch使用的promise对象使用同步的方式写异步函数
fetch API是可以结合async和await来使用的
fetch是基于promise实现的,但是使用promise的写法,还是能看到callback的影子,结合async和await后效果非常好
fetch API可以跨域
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:
回流必将引起重绘,而重绘不一定会引起回流
回流:
重绘:
防抖:
节流:
CSS
JavaScript
Event Loop 即事件循环是指浏览器或者Node的一种解决JavaScript单线程运行时不阻塞的一种机制,单线程指的是所有任务都在主线程上完成,任务太多的时候,页面卡死,eventLoop可以解决单线程阻塞问题,程序中会有两个线程,一个主线程,一个eventLoop线程,负责主线程和其他进程之间的通信,遇到I/O的时候,主线程会让eventLoop线程通知对应的程序,主线程的任务会继续往后执行,等I/O程序执行完了,eventLoop线程会把结果返回给主线程,主线程利用回调函数调用结果,完成任务
在js中,所有任务都分为同步任务和异步任务两大类。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
宏任务和微任务的执行顺序
有时候 setTimeout明明写的延时3秒,实际却5,6秒才执行函数,这又是因为什么?
答:setTimeout 并不能保证执行的时间,是否及时执行取决于 JavaScript 线程是拥挤还是空闲。浏览器的JS引擎遇到setTimeout,拿走之后不会立即放入异步队列,同步任务执行之后,timer模块会到设置时间之后放到异步队列中。js引擎发现同步队列中没有要执行的东西了,即运行栈空了就从异步队列中读取,然后放到运行栈中执行。所以setTimeout可能会多了等待线程的时间
1.浏览器默认的 application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
2.multipart/form-data
这也是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,就要让 form 的 enctype 等于这个值
3.application/json
除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify
4.text/xml
相比于JSON,不能更好的适用于数据交换,它包含了太多的包装, 而且它跟大多数编程语言的数据模型不匹配,让大多数程序员感到诧异,XML是面向数据的,JSON是面向对象和结构的,JSON会给程序员一种更加亲切的感觉
1. reduce
遍历数组每一项,若值为数组则递归遍历,否则concat。
function flatten(arr) {
return arr.reduce((result, item)=> {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
reduce是数组的一种方法,它接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduce包含两个参数:回调函数,传给total的初始值
// 求数组的各项值相加的和:
arr.reduce((total, item)=> { // total为之前的计算结果,item为数组的各项值
return total + item;
}, 0);
2. toString & split
调用数组的toString方法,将数组变为字符串然后再用split分割还原为数组
function flatten(arr) {
return arr.toString().split(',').map(function(item) {
return Number(item);
})
}
因为split分割后形成的数组的每一项值为字符串,所以需要用一个map方法遍历数组将其每一项转换为数值型
3. join & split
和上面的toString一样,join也可以将数组转换为字符串
function flatten(arr) {
return arr.join(',').split(',').map(function(item) {
return parseInt(item);
})
}
4. 递归
递归的遍历每一项,若为数组则继续遍历,否则concat
function flatten(arr) {
var res = [];
arr.map(item => {
if(Array.isArray(item)) {
res = res.concat(flatten(item));
} else {
res.push(item);
}
});
return res;
}
5. 扩展运算符
es6的扩展运算符能将二维数组变为一维
[].concat(...[1, 2, 3, [4, 5]]); // [1, 2, 3, 4, 5]
根据这个结果我们可以做一个遍历,若arr中含有数组则使用一次扩展运算符,直至没有为止。
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
Array.prototype.push.apply(a,b)
es5 的继承是先创建子类的this,然后将父类的方法添加到子类的this上去;
es6 的继承是创建父类的this对象,然后再对this对象添加方法/属性。
而super方法就是用来创建父类this对象的。
实际上执行的是 super.sport.call(this);
1、CSRF(Cross-site request forgery):跨站请求伪造。
(1)登录受信任网站A,并在本地生成Cookie。
(如果用户没有登录网站A,那么网站B在诱导的时候,请求网站A的api 接口时,会提示你登录)
(2)在不登出A的情况下,访问危险网站B(其实是利用了网站A的漏洞)
CSRF如何防御
方法一: Token 验证:(用的最多)
(1)服务器发送给客户端一个token;
(2)客户端提交的表单中带着这个token。
(3)如果这个 token 不合法,那么服务器拒绝这个请求。
方法二: 隐藏令牌:
把 token 隐藏在 http 的 head头中。
方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。
方法三: Referer(锐服尔) 验证:
Referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截。
2、XSS(Cross Site Scripting):跨域脚本攻击。
XSS攻击的核心原理是:
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),
向你的页面注入脚本(可能是js、hmtl代码块等)。
最后导致的结果可能是:
盗用Cookie破坏页面的正常结构,插入广告等恶意内容D-doss攻击
XSS的攻击方式
1、反射型
发出请求时,XSS代码出现在url中,作为输入提交到服务器端,服务器端解析后响应,
XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型XSS。
2、存储型存
储型XSS和反射型XSS的差别在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),
下次请求时目标页面时不用再提交XSS代码。
XSS的防范措施(encode + 过滤)主要有三个:
1、编码:
对用户输入的数据进行HTML Entity(安特踢) 编码。
2、过滤:
移除用户输入的和事件相关的属性。如onerror可以自动触发攻击,还有onclick等。
(总而言是,过滤掉一些不安全的内容)移除用户输入的Style节点、Script节点、Iframe节点。
(尤其是Script节点,它可是支持跨域的呀,一定要移除)。
3、校正
避免直接对HTML Entity进行解码。
使用DOM Parse转换,校正不配对的DOM标签。
这个概念,它的作用是把文本解析成DOM结构。
比较常用的做法是,通过第一步的编码转成文本,然后第三步转成DOM对象,然后经过第二步的过滤。
还有一种简洁的答案:
首先是encode,如果是富文本,就白名单。
3、CSRF 和 XSS 的区别:
区别一:
CSRF:需要用户先登录网站A,获取 cookie。
XSS:不需要登录。
区别二:(原理的区别)
CSRF:是利用网站A本身的漏洞,去请求网站A的api。
XSS:是向网站 A 注入 JS代码,然后执行 JS 里的代码,篡改网站A的内容。
首先,微信小程序已经提供了一套 view, data, model, router 层的开发工具,
对于开发简单应用,小程序是可以比 webapp 更加快速的。
但是实际上微信小程序提供的这一套开发框架,要开发一些复杂应用,是很困难的,
因为:小程序不支持 npm 等 package manager(麦呢橘)无法复用社区中已经很成熟的 web 框架和工具组件只能封装 view 和 style,无法封装行为(handler),行为只能定义在 page 上小程序有 1mb 的限制,所以我们只能将图片之类的静态资源事先放在服务器上
其次,微信小程序是由微信自己来 host,开发者只需要上传就好,
而微信 webapp 需要开发者自己 host,还需要注册域名甚至备案才可以调用微信接口以及跟公众号集成。
所以微信小程序降低了开发者的门槛。
综上,对于简单的工具型应用,微信小程序可以让开发者加快开发速度,降低发布门槛,
这种类型的应用比较适合微信小程序。对于复杂的应用,webapp 是更适合的形式。
优点:
缺点:
17版本:相对于16版本 少3多2
少了componentWillMount,componentWillReceiveProps,componentWillUpdate 3个钩子函数
多了static getDerivedStateFromProps钩子函数,是一个静态方法,所以不能在这个函数里面使用this,这个函数有两个参数nextProps和prevState,这个函数会返回一个对象用来更新当前的state对象,如果不需要更新可以返回null,简单说就是,可以增加一次state状态
多了getSnapshotBeforeUpdate钩子函数,这个函数有一个返回值,会作为第三个参数传递给componentDidUpdate钩子
view用actionCreator(酷睿A特)创建一个action,里面可能包含一些数据
使用store的dispatch方法将action传入store
store将action与旧的state转发给reducer
reducer深拷贝state,并返回一个新的state给store
store接收并更新state
使用store.subscribe(萨布斯快不)订阅更新,重新render组件
redux组成
state :用来存储数据和数据管理的、更新视图
reducer:是一个纯函数,接收旧 state 和 action,根据不同的 Action 做出不同的操作并返回新的 state
actions:发送动作给reducer,reducer接收动作,判断动作类型修改数据,修改事件后,组件重新做redux事件的订阅
Redux三大原则
单一数据源:
整个应用的 state 被存储在一个 Object tree 中,且只存在于唯一的Store中
state 是只读的:
唯一改变 state 的方法就是触发 action,action 是一个用于描述发生事件的普通对象,视图部分只需要表达想要修改的意图,所有修改都会被集中化处理。
状态的改变通过纯函数来完成:
Redux使用纯函数方式来执行状态的修改,Action表明了修改状态值的意图,而真正执行状态修改的则是Reducer。且Reducer必须是一个纯函数,当Reducer接收到Action时,Action并不能直接修改State的值,而是通过创建一个新的状态对象来返回修改的状态。
在action 和 store 之间执行中间件
Redux中间件机制
Redux本身就提供了非常强大的数据流管理功能,但这并不是它唯一的强大之处,它还提供了利用中间件来扩展自身功能,以满足用户的开发需求
(米的为尔)
applyMiddlewares():它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。
applyMiddleware顾名思义,用于调用各种中间件;
applyMiddleware执行后,将所有入参中间件存入一个数组,并且返回一个闭包(闭包的概念不做累述)
闭包接受一个createStore作为入参并且执行后返回下一个闭包。
首先检查参数 action 的类型,如果是函数的话,就执行这个 action 函数,
并把 dispatch, getState, extraArgument(哎克斯拽埃歌门特) 作为参数传递进去,
否则就调用 next 让下一个中间件继续处理 action
好处
可以进行前后端数据交互
缺点
将带有数据请求的action和没有带有数据请求的action混在一起了
缺点解决: 弃用redux-thunk,使用redux-saga
redux-saga可以将异步action和普通action区别开来
redux-saga可以将异步action和普通action区别开来,控制器与更优雅的异步处理
redux-saga就是用Generator(杰呢瑞特)来处理异步。
redux-saga文档并没有说自己是处理异步的工具,而是说用来处理边际效应(side effects),这里的边际效应你可以理解为程序对外部的操作,比如请求后端,比如操作文件。
redux-saga相当于在Redux原有数据流中多了一层,通过对Action进行监听,从而捕获到监听的Action,然后可以派生一个新的任务对state进行维护(这个看项目本身的需求),通过更改的state驱动View的变更。
redux-saga同样是一个redux中间件,它的定位就是通过集中控制action,起到一个类似于MVC中控制器的效果。
同时它的语法使得复杂异步操作不会像promise那样出现很多then的情况,更容易进行各类测试。
redux是独立的应用状态管理工具。它是可以独立于react之外的。如果我们需要在react当中运用它,那么我们需要手动订阅store的状态变化,来对我们的react组件进行更新。react-reudx这个工具,就帮我们实现了这个功能,我们只需对store进行处理,react组件就会有相应的变化。
Redux的核心由三部分组成:Store, Action, Reducer。
Store: 是个对象,贯穿你整个应用的数据都应该存储在这里。
Action: 是个对象,必须包含type这个属性,reducer将根据这个属性值来对store进行相应的处理。除此之外的属性,就是进行这个操作需要的数据。
Reducer: 是个函数。接受两个参数:要修改的数据(state) 和 action对象。根据action.type来决定采用的操作,对state进行修改,最后返回新的state。
总结
Redux: store, action, reducer
store: getState, dispatch, subscribe
combineReducers (克木拜恩)
createStore
store ️ dispatch ️ action ️ reducer
react-redux:
connect : 将store作为props注入
provider(破外的): 使store在子孙组件的connect中能够获取到
1. UI组件|显示页面?? (破森特逊弄)
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件
2. 容器组件|负责管理数据/复杂逻辑?
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
3. Provider组件|容器组件获取state??
所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它。
4. connect()|UI组件+容器组件
React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。
dva:
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。--- 来自官方。
相比于cra只是多了内置的redux和redux-saga,帮我们处理了数据流这方面的需求而已。如果只是想要达到这个效果的话,直接在cra中增加dva-core的依赖也是可以做到的。
umi:
是一个可插拔的企业级 react 应用框架。umi和cra都是应用框架,可能相比cra来说umi的功能点更多一些,只能说是功能性的话umi要相对来说更胜一筹
flux 是 react 中的类似于 vuex 的公共状态管理方案,它是 Facebook 官方给出的应用架构,利用数据的单向流动的形式对公共状态进行管理。现已不推荐使用。
flux的组成
View:视图层
Action:视图发出的消息
Dispatcher:派发者,用来接收Action,执行回调函数
Store:数据层,存放状态,一旦发生改动
flux 在进行数据更新时,会经历以下几步:
用户与 View 层交互,触发 Action
Action 使用 dispatcher.dispatch 将Action自己的状态发送给dispatcher
dispatcher 通过register注册事件,再通过Action传入的类型来触发对应的 Store 回调进行更新
Store 里进行相应的数据更新,并触发 View 层事件使试图也同步更新
View层 收到信号进行更新
redux和flux的区别
1)redux是flux中的一个实现
2)在redux中我们只能定义一个store,在flux中我们可以定义多个
3)在redux中,store和dispatch都放到了store,结构更加清晰
4)在redux中本身就内置State对象,对仓库的管理更加明确
key是react用于追踪哪些列表被修改、被添加或者被移出的辅助标识
在开发过程中,需要保证某些元素在同级的元素中key具有唯一性的特性,在react Diff算法中React会借助元素的key值来判断该元素是新创建的还是移动而来的元素,从而减少元素的不必要的重复渲染。此外,还需要借助key值来判断元素与本地状态的关联关系
react根据key来决定是销毁重新创建组件还是更新组件,原则是:
render
支持返回这五类:
React elements, 数组, Fragments, Portal, String/numbers, boolean/null, 基础数据类型
Fiber
React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
新的生命周期函数
由于异步渲染的改动,componentWillMount, componentWillReceiveProps,componentWillUpdate 三个函数将被废弃。
由于这是一个很大的改变会影响很多现有的组件,所以需要慢慢的去改。
目前react 16 只是会报warning,在react 17就只能在前面加UNSAFE_的前缀来使用
diff算法
作用: 计算出Virtual DOM中真 正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面
getDerivedStateFromProps
static getDerivedStateFromProps(props, state)在调用render方法之前调用,
无论是在初始安装还是后续更新。它应返回一个对象来更新状态,或者返回null以不更新任何内容。
根据props更新state
这个生命周期可用于替代componentWillReceiveProps
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)在最近呈现的输出被提交到例如DOM之前调用。它使组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。
hooks
lazy、suspense
lazy需要跟Suspence配合使用。
lazy实际上是帮助我们实现代码分割的功能。
由于有些内容,并不一定要在首屏展示,所以这些资源没有必要一开始就要去获取,那么这些资源就可以动态获取。
这样的话,相当于把不需要首屏展示的代码分割出来,减少首屏代码的体积,提升性能。
Suspence 很像Error Boundary,不同的是Error Boundary是用来捕获错误,显示相应的callback组件。而Suspence是用来捕获还没有加载好的组件,并暂停渲染,显示相应的callback。
两个参数及用法
同步/异步原理
setState 的异步并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果
setState 的批量更新优化也是建立在异步(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在异步中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。
合成事件原理
与原生事件的区别
1.params
xxx
this.props.history.push({pathname:'/path/'+name);
读取参数用:this.props.match.params.name
优势:刷新地址栏,参数依然存在
缺点:只能传字符串,并且,如果传的值太多的话,url会变得长而丑陋
2.query
xxx
this.props.history.push(
{
pathname:"/query",
query: { name : 'sunny' }
}
);
读取参数用: this.props.location.query.name
优势: 传参优雅,传递参数可传对象
缺点: 刷新地址栏,参数丢失
3.state
xxx
this.props.history.push(
{
pathname:"/sort ",
state : { name : 'sunny' }
}
);
读取参数用: this.props.location.state.name
优缺点同query
4.search
xxx
this.props.history.push(
{
pathname:"/web/departManange"
search:'?tenantId=12121212'
}
);
读取参数用: this.props.location.search
优缺点同params
1. 组成部分
actions->state->computed values->Reactions
2. 工作流
在mobx中, 数据是通过加 @observable 作为可监测的被观察者, 在view层中, 你可以通过添加@observer 将view作为观察者,对数据进行监测, 如果要触发改变数据,则使用@action, 事实上,你可以直接在view层改变数据, 但这种方式不便监控数据,因此不推荐直接改变数据。 而@computed可以用来计算数据, 也可以是计算多个数据之后返回新的数据, 如果其中数据改变, @computed也会触发改变
3. 优点
不同于redux的单一数据流, mobx中,你可以同时在各个地方使用同一份state, 也可以在一个页面中使用多个store文件
1.父组件向子组件通信
2.子组件向父组件通,
3.非嵌套组件间通信
4.跨组件通信
5.redux
vue异步组件技术
import( )
webpack提供的require.ensure( )
第三方库比如react-loadable
lazyload-loader(懒加载)
可以用三目或者短路原则&&控制组件的显示隐藏,然后使用componentWillUnmount钩子函数去清除组件身上的定时器、订阅、第三方组件等
onChange输入框内容改变时候回调 value输入的内容 defaultValue输入框默认值
input默认值在input中绑定value 定义一个state 和input双向数据绑定 做成受控组件 定义一个事件 改变的时候获取e.target.value
为什么使用hook
不必写class组件就可以用state和其他的React特性;
自定义hook 实现组件的复用 用useEffects代替生命周期方法 代码更加简洁
出现原因3点
为了让函数组件拥有类组件的功能。
原因
比如useState、useReducer 状态定义
比如useEffect、useLayoutEffect 生命周期功能
比如useRef useImperativeHandle 替代了类组件的 Ref
为了优化函数组件,比如useMemo、useCallback
函数组件添加新的方法,如
useDebugValue显示自定义hook,自己添加hook类名
自定义hooks来复用状态
优点4点
1.让函数组件可以定义状态
让函数组件可以使用生命周期、监听数据
让函数组件可以有Ref的功能(父组件获取子组件)
优化函数组件 useMemo、useCallback
自定义hooks来复用状态,
代码量比类组件更少,更清爽。
2.使用规则2点
不要在循环,条件或嵌套函数中调用 Hook
只在函数组件中使用 Hooks
3.常用Hook
useState:
定义状态 修改状态
返回一个数组,其中第一项是状态值,第二项是一个更新状态的函数。
状态一旦改变,React 就会重新渲染组件,变量获取新的状态值。
useEffect:
相当于componentDidMount,componentDidUpdate,componentWillUnmount三个钩子的组合
参数一:执行的回调函数;
参数二:该useEffect在哪些state发生变化时,才重新执行;
第二个参数是空数组的时候执行一次,相当于componentDidMount,不加的时候执行多次
第二个参数的作用就是 仅在更改时更新,实现性能的优化
DOM操作 第三方实例化可以做 清除无用实例和事件
useEffect传入的回调函数本身可以有一个返回值,
这个返回值是另外一个回调函数,来模拟componentWillUnmount
useLayoutEffect:
布局副作用
useEffect 在浏览器渲染完成后执行
useLayoutEffect 在浏览器渲染前执行
useLayoutEffect 里的任务最好影响了 Layout
为了用户体验,优先使用 useEffect (优先渲染)
useContext:
跨组件通信 createContext创建一个组件
useDebugValue:
自定义 hook 的标签 方便调试台查看
useMemo:
记忆组件 动态缓存 新值和旧值一样,不重新渲染页面,优化作用,类似于shouldComponentUpdate useCallBack:
作用和 useMemo 一样
useMemo和useCallback都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行
并且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。
useCallback(x => console.log(x), [m]) 等价于
useMemo( () => x => console.log(x), [m])
useRef:
返回一个可变的ref对象
useImperativeHandle:
将组件中的方法放到外面使用
搭配React.forwardRef
5.自定义hook
类似于高阶组件
高阶组件返回的一个类组件,而自定义Hook可以返回任何东西
高阶组件必须传递一个组件作为参数,而自定义Hook不需要
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// 在开发者工具中的这个 Hook 旁边显示标签
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
可以理解为数据的操作都在hook里进行,而外部只关心自己想要的。我只要数据列表,获取产品钩子(可能并不需要,可通过参数变更从而触发重新获取数据)、删除产品钩子
为了封装方法:节流;
1.使用 useState() 进行状态管理
调用useState() Hook 来启用函数组件中的状态。
useState(initialValue)的第一个参数initialValue是状态的初始值。
[state, setState] = useState(initialValue)返回一个包含2个元素的数组:状态值和状态更新函数。
使用新值调用状态更新器函数setState(newState)更新状态。或者,可以使用一个回调setState(prev => next)来调用状态更新器,该回调将返回基于先前状态的新状态。
调用状态更新器后,React 确保重新渲染组件,以使新状态变为当前状态。
2.多种状态
通过多次调用useState(),一个函数组件可以拥有多个状态。
需要注意的,要确保对useState()的多次调用在渲染之间始终保持相同的顺序。
3.状态的延迟初始化
每当 React 重新渲染组件时,都会执行useState(initialState)。如果初始状态是原始值(数字,布尔值等),则不会有性能问题。
当初始状态需要昂贵的性能方面的操作时,可以通过为useState(computeInitialState)提供一个函数来使用状态的延迟初始化,该函数仅在初始渲染时执行一次,以获得初始状态。在以后的组件渲染中,不会再调用该函数,从而跳过昂贵的操作。
4.调用 useState()
在使用useState() Hook 时,必须遵循 Hook 的规则:
1.仅顶层调用Hook:不能在循环,条件,嵌套函数等中调用useState()。在多个useState()调用中,渲染之间的调用顺序必须相同。
2.仅从React 函数调用 Hook:必须仅在函数组件或自定义钩子内部调用useState()。
1.名词解释/作用
使函数复用,可以通过给组件传递方法来复用高阶组件中的函数方法。
高阶组件特点
高阶组件是一个函数
高阶组件接收一个组件作为参数进行使用,且需要在render函数中return返回这个组件
高阶组件的目的是为了: 复用组件,将多个组件都要使用的类似逻辑放在同一个地方进行处理,类似于在Vue中封装cookie以供重复使用
2.常用高阶组件4个
React.memo()
connect()
provider()
withRouter() // 可以使用
3.有自己封装过吗
拖拽封装,给组件里面的标签添加方法就可以实现拖拽,并返回标签的x与y坐标。
深对比,深复制封装、正则封装、页面路由跳转、路由数据接收解析。
重点:
1、一定要绝对定位,脱离文档流才可以移动。
2、绑定拖拽的元素,移动和鼠标松开后是对document的绑定,因为移动的是整个div。
3、点击:a= 获取当前鼠标坐标、b =div距浏览器距离、c = 鼠标在div内部距离=a-b。
移动:通过 a - c 建立鼠标与div的关系,防止鼠标超出div。
拖拽状态 = 0鼠标在元素上按下的时候{
拖拽状态 = 1
记录下鼠标的x和y坐标
记录下元素的x和y坐标
}
鼠标在元素上移动的时候{
如果拖拽状态是0就什么也不做。
如果拖拽状态是1,那么
元素y = 现在鼠标y - 原来鼠标y + 原来元素y
元素x = 现在鼠标x - 原来鼠标x + 原来元素x
}
鼠标在任何时候放开的时候{
拖拽状态 = 0
}
1.将Hello组件和App组件中共用的逻辑放在统一的自定义hook中写
2.自定义hook,hook名以use开头
3.其他组件通过import引入自定义hook,就可以使用了
相同点:
不同点:
在ES6之前使用React.createClass来构建一个组件“类”,它接受一个对象为参数,对象中必须声明一个render方法,render返回一个组件实例
protoType.componentDidMount
所谓的虚拟 dom,也就是虚拟节点。它通过JS的Object对象模拟DOM中的节点,然后再通过特定的render方法将其渲染成真实的DOM节点
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用diff算法,避免了没有必要的 dom 操作,从而提高性能
虚拟dom的使用基本流程(前四步骤)
优点:
缺点:
1.diff算法是什么
2.diff算法运行结束后,返回是什么
React Native能在手机上创建原生应用,React在这方面处于领先位置。使用JavaScript, CSS和HTML创建原生移动应用,这是一个重要的革新。Vue社区与阿里合作开发Vue版的React Native——Weex也很不错,但仍处于开发状态且并没经过实际项目的验证。
既拥有Native的用户体验、又保留React的开发效率
React Native与React.js的主要区别还是JSX,它使用XML标记的方式去直接声明界面,将HTML直接嵌入到JavaScript代码中
react-router依赖基础 - history
history是一个独立的第三方js库,可以用来兼容在不同浏览器、不同环境下对历史记录的管理
老浏览器的history:
主要通过hash来实现,对应createHashHistory
高版本浏览器:
通过html5里面的history,对应createBrowserHistory
node环境下: (不弱惹)
主要存储在历史记录memeory里面,对应createMemoryHistory
抽象了一个公共的文件createHistory:
此时的location跟浏览器原生的location是不相同的,最大的区别就在于里面多了key字段,
history内部通过key来进行location的操作
原理:
1.执行URL前进
createBrowserHistory: pushState、replaceState
createHashHistory: location.hash=*** location.replace()
createMemoryHistory: 在内存中进行历史记录的存储
1.检测URL回退
createBrowserHistory: popstate
createHashHistory: hashchange
createMemoryHistory: 因为是在内存中操作,跟浏览器没有关系,不涉及UI层面的事情,所以可以直接进行历史信息的回退
1.state的存储
为了维护state的状态,将其存储在sessionStorage里面:
基本原理:实现URL与UI可视化界面的同步。其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成location与components之间的同步问题。
在react-router中最主要的component是Router、RouterContext、Link,history库起到了中间桥梁的作用
安装react-router-dom
Link组件用于点击链接跳转其他页面,没有路由激活
NavLink 用于有路由激活效果的
写法上的区别:
import {Swtich, Route, Router, HashHistory, Link} from 'react-router-dom';
import {Switch, Route, Router} from 'react-router';
import {HashHistory, Link} from 'react-router-dom';
react-router-dom:
加入了在浏览器运行环境下的一些功能:
BrowserRouter和HashRouter组件,
前者使用pushState和popState事件构建路由,
后者使用window.location.hash和hashchange事件构建路由。
react-router-dom是依赖于react-router的,其中Switch、Route、Router、Redirect等组件是直接引入react-router中的
react-router-dom还另外新增了Link、BrowserRouter、HashRouter组件。
在引入react-router-dom后不需要显性引入react-router,
react-router-dom依赖react-router,npm都会将他们安装。
react-router3.x与react-router-dom区别
react-router3.x版本下路由采用集中式配置,UI组件和路由是分开的。
react-router4.x版本下路由路由采用分散式配置,路由嵌套在UI组件当中,
更加契合组件化思想(组件中的路由也应该包含在组件之中)。
我们一直在使用的路由方式是BrowserRouter,也就是浏览器的路由方式,其实React还有几种路由方式:
(不弱惹)
1、BrowserRouter:浏览器的路由方式,也就是在开发中最常使用的路由方式
2、HashRouter:在路径前加入#号成为一个哈希值,Hash模式的好处是,再也不会因为我们刷新而找不到我们的对应路径
3、MemoryRouter:不存储history,所有路由过程保存在内存里,不能进行前进后退,因为地址栏没有发生任何变化
4、NativeRouter:经常配合ReactNative使用,多用于移动端
5、StaticRouter:设置静态路由,需要和后台服务器配合设置,比如设置服务端渲染时使用
(斯大推克)
1、引入路由包
npm install --save react-router
npm install --save react-router-dom
react-router:是基本的router包,里边函的内容较多,
但是在网页开发中有很多用不到,现在的市面上的课程讲的基本都是这个包的教程。
react-router-dom:随着react生态环境的壮大,后出现的包,
这个包比react-router包轻巧了很多。
2、设置路由配置文件
在src目录下新建一个Router/index.js文件用于管理路由,这里需要引入一些对应的组件和路由包文件。
Router的history是必需的props
Switch表示只渲染第一个与当前地址匹配的
Route的props path为路径,component为路径对应的页面
exact属性表示精确匹配,比如我们有多层路由进行嵌套时,exact可以帮助我们精确匹配到你想跳转的路由。 exact的值为bool型,为true是表示严格匹配,为false时为正常匹配
3、在入口文件引入路由配置文件
import RouterConfig from './router/index.js';
ReactDOM.render( , document.getElementById('root'));
4、在各组件中使用路由
第一个页面
第二个页面
1.Switch:表示一次只渲染一个组件
2.Route:路由组件,用于展示一个组件 同router-view
3.Redirect:重定向(锐得埃克特)
4.lazy + Suspense(色斯盘丝):实现路由懒加载
5.exact:路径完全匹配
6.fallback:组件切换时候的转场组件
react-router,官网文档给出的是用webpack的bundle-loader
require.ensure。这是webpack的旧式写法,现在已不推荐
import()
符合ECMAScript提议的import()语法,该提案与普通 import 语句或 require 函数的类似,
但返回一个 Promise 对象。这意味着模块时异步加载的
1. setState
setState在合成事件和钩子函数中是异步的
在原生事件和setTimeout中是同步的
setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,
只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,
形式了所谓的“异步”,
第一个参数可以是对象或者函数 是更新state
第二个参数获取最新的state,副作用操作 dom操作事件触发声明 数据获取
2. JSX语法的转化
JSX 仅仅是 createElement() 方法的语法糖(简化语法)
JSX 语法被 @babel/preset-react 插件编译为 createElement() 方法
react.createElement()
React 元素:是一个对象,用来描述你希望在屏幕上看到的内容
3. 组件更新机制
setState() 的两个作用: 1. 修改 state 2. 更新组件(UI)
过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)
4. 组件性能优化
减轻 state:只存储跟组件渲染相关的数据
避免不必要的重新渲染 : shouldComponentUpdate(nextProps, nextState)
通过返回值决定该组件是否重新渲染,返回 true 表示重新渲染,false 表示不重新渲染 起到优化作用
5. 纯组件 PureComponent
PureComponent 内部自动实现了 shouldComponentUpdate 钩子,不需要手动比较
纯组件内部通过分别 对比 前后两次 props 和 state 的值,来决定是否重新渲染组件
纯组件内部的对比是 shallow compare(浅层对比)
6. 虚拟 DOM 和 Diff 算法
数据改变视图更新
初次渲染时,React 会根据初始state(Model),创建一个虚拟 DOM 对象(树)。
根据虚拟 DOM 生成真正的 DOM,渲染到页面中。
当数据变化后(setState(),重新根据新的数据,创建新的虚拟DOM对象(树)。
与上一次得到的虚拟 DOM 对象,使用 Diff 算法 对比(找不同),生成patch补丁对象,得到需要更新的内容。
最终,React 只将变化的内容更新(patch)到 DOM 中,重新渲染到页面。
连接React组件与 Redux store。
connect:connect函数的返回值是一个高阶组件,通过高阶组件来获取store中的数据
connect底层原理:是闭包
mapStateFromProps:从countReducer中解构出num数据,用来获取数据
mapDispatchFromProps:将ActionCreators中的方法绑定到组件上,并且发送action
connect调用的结果是返回一个高阶组件
connect方法利用了合并分发的原理来帮助我们完成store内容的获取
合并: 将store中的所有数据拿到手
分发: 将我们UI需要的数据派发出去
原理
合并分发 :合并的意思是:(我们项目中)redux的数据是集中在一处的
分发的意思是:给的是所有数据中的分块的数据
首先connect之所以会成功,是因为Provider组件:
在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子孙组件上的connect
那connect做了些什么呢?
它真正连接 Redux 和 React,它包在我们的容器组件的外一层,
它接收上面 Provider 提供的 store 里面的 state 和 dispatch,
传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
关于它的源码
connect是一个高阶函数,首先传入mapStateFromProps、mapDispatchFromProps,
然后返回一个生产Component的函数(wrapWithConnect),
然后再将真正的Component作为参数传入wrapWithConnect,
这样就生产出一个经过包裹的Connect组件,该组件具有如下特点:
通过props.store获取祖先Component的store
props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
componentWillUnmount时移除注册的事件this.handleChange
一、V3或者说V早期版本是把router 和 layout components 分开
在V4中是:
集中式 router
通过 嵌套,实现 Layout 和 page 嵌套
Layout 和 page 组件 是作为 router 的一部分
二、在V3中,我们是将整个庞大的router直接丢给Dom
在V4中,除了BrowserRouter,我们丢给DOM的我们的程序本身
另外,V4 中,我们不再使用 {props.children} 来嵌套组件了,
替代的 ,当 route 匹配时,子组件会被渲染到 书写的地方
三、在V3 中的 routing 规则是 exclusive,意思就是最终只获取一个 route
而 V4 中的 routes 默认是 inclusive 的,这就意味着多个 可以同时匹配和呈现
如果只想匹配一个路由,可以使用Switch,在 中只有一个 会被渲染,
同时可以再在每个路由添加exact,做到精准匹配
Redirect,浏览器重定向,当多有都不匹配的时候,进行匹配
使用ref属性获取Dom元素后,再使用原生javascript获取内容
React框架本身和我们常用的JavaScript MVC框架,如:AngularJS,Backbone,Ember等,没有直接的可比性。React的官方博客中明确阐述了React不是一个MVC框架,而是一个用于构建组件化UI的库,是一个前端界面开发工具。所以顶多算是MVC中的V(view视图层)
React遵循从上到下的数据流向,即单向数据流
单向数据流并非单向绑定,甚至单向数据流与绑定没有任何关系。对于React来说,单向数据流(从上到下)与单一数据源这两个原则,限定了在React中要想在一个组件中更新另一个组件的状态(类似于Vue的平行组件传参,或者是子组件向父组件传递参数)需要进行状态提升——将状态提升到他们最近的祖先组件中
子组件中改变了状态,触发父组件状态的变更,父组件状态的变更,影响到了另一个组件的显示(因为传递给另一个组件的状态变化了,这一点与Vue子组件的$emit( )方法很相似)
componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。在这方法中调用setState方法,会触发重渲染。这个方法就是用来加载外部数据用的,或处理其他的副作用代码。componentDidMount确保已经render过一次。提醒我们正确地设置初始状态,这样就不会得到导致错误的"undefined"状态
如果在constructor中更新数据的话,如果时间太长,或者出错,组件就渲染不出来,整个页面都没法渲染了,constructor是作组件state初绐化工作,并不是设计来作加载数据的。
如果在componentWillMount中更新数据的话,如果使用SSR(服务端渲染),componentWillMount会执行2次,一次在服务端,一次在客户端,而componentDidMount不会
constructor可以完成state初始化,而componentWillMount使用的很少,目前新版本已经不在使用componentWillMount,新的生命周期static getDerivedStateFromProps也会替代它
React16之后采用了Fiber架构,只有componentDidMount声明周期函数是确定被执行一次的,类似ComponentWillMount的生命周期钩子都有可能执行多次,所以不在这些生命周期中做有副作用的操作,比如请求数据
如果在render中更新数据,则会造成死循环
受控组件
非受控组件
方式1: string类型绑定(已弃用)
方式2: react.CreateRef( )
方式3: 函数形式
当在子组件中调用onRef函数时,正在调用从父组件传递的函数。this.props.onRef(this)这里的参数指向子组件本身,父组件接收该引用作为第一个参数:onRef = {ref =>(this.child = ref)},然后它使用this.child保存引用。之后,可以在父组件内访问整个子组件实例,并且可以调用子组件函数
静态方法和 React 没有直接关系,React 的组件都是继承自 React.Component 这个类,静态方法属于类本身,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用
这里涉及到了ES6的class,我们定义一个组件的时候通常是定义了一个类,而static则是创建了一个属于这个类的属性或者方法。组件则是这个类的一个实例,component的props和state是属于这个实例的
props
props代表属性
一般用于父组件向子组件通信,在组件之间通信使用
state
state代表状态
一般用于组件内部的状态维护,更新组建内部的数据,状态,更新子组件的props等
1. 混合开发是介于webapp和原生app之间的一种应用,它同时具有webapp可以跨平台的特性,也具备原生app可以进行安装使用的特性
2. webApp
1. 优点: 跨平台 、 维护更新、项目迭代快
2. 缺点: 交互体验不好 、进入应用的方式麻烦
3. 原生app
1.案例: 美团、饿了吗、微信、QQ
2.安装在手机中使用的
3.优点: 手机安装、交互体验好
4.缺点: 维护更新、项目迭代很慢、成本太高了
4. 混合开发: 择中方案
跨平台
维护更新快 成本低
手机安装,交互体验好
为什么混合开发会兴起呢?
1. 混合开发的兴起是偶然的
混合开发方式
1. h5 主导
- 开发思维: H5【 vue/ react/ angular 】 + 第三方可以访问原生设备的库
- 微信公众号: h5网页 + 微信JSSDK
- 历史
1. PhoneGap + cordva.js 淘汰
2. vue/react/angular + ioinc.js
3. vue - uni-app
4. h5 + h5plus.js h5 + h5+
5. 微信公众号: webapp + js-jdk
6. vue/react + weex.js[ 阿里内部 ]
2. React Native
1. facebook 团队项目 16 - 18年很热火,18年后半年开始热度下降,
facebook觉得这个框架对于开发者而言开发难度太大,维护成本也高,Facebook决定不再更新它了、
2. 典型应用: 饿了吗
3. React Native开发出来项目 - 原生app
4. React Native = React + 原生js
5. 构建React Native项目 - 脚手架
1. 构建项目环境: create-react-native-app
2. 手机调试:expo expo-cli
3. 目录解释
1. __test__ expo手机调试的测试文件夹,不用管
2. .expo 临时文件,运行项目
3. .expo-shared 分享
4. assets 静态资源
5. components 公共组件
6. constants 项目公用的常量
7. navigation 底部tabbar栏组件
8. node_modules 依赖包
9. screens 页面
对于路由的触发方式以及页面生命周期函数如下:
路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad, onSHow | |
打开新页面 | 调用 API wx.navigateTo 或使用组件 | onHide | onLoad, onShow |
页面重定向 | 调用 API wx.redirectTo 或使用组件 | onUnload | onLoad, onShow |
页面返回 | 调用 API wx.navigateBack 或使用组件或用户按左上角返回按钮 | onUnload | onShow |
Tab 切换 | 调用 API wx.navigateBack 或使用组件或用户按调用 API wx.switchTab 或使用组件 或用户切换 Tab | 各种情况请参考下表 | |
重启动 | 调用 API wx.reLaunch 或使用组件 | onUnload | onLoad, onShow |
页面跳转触发的生命周期,其实还是存在问题的,并非官方所说的那样。
SwitchTab的跳转BUG
首页跳转到子页面后,在子页面上使用:
跳转首页
这种方式有问题,解决的办法是通过JS来实现跳转,代码如下:
跳转成功后,重新调用onload方法,JS代码如下:
backIndex:function(){
wx.switchTab({
url: '/pages/index/index',
success: function (e) {
var page = getCurrentPages().pop();
if (page == undefined || page == null) return;
page.onLoad();
}
})
}
1.提交方式
get: get会将接收到的数据拼接到url地址中,以"?"问号划分,问号后面是接收到的数据,多个数据之间用&连接。用户可以很直观的看见。
post: post会将接收到的数据放置在html header中一起发送到指定的url地址内。用户看不到这个过程。
2.传递数据大小
get: get传递数据的大小因为受到浏览器地址栏的限制,所以一般在2k-8k,这要据浏览器而定,比如谷歌浏览器就是8k。
post: post传递数据的大小最小是2M,但理论上是无上限的。
3.应用范围
get: get一般用于获取/查询资源信息.多用于a标签的href属性中,也常用于location.href属性中。
post: post一般是用于更新数据信息.多用于表单提交。
4.安全性
get的安全性比post较差。
在子组件中
this.customfunction = this.customfunction.bind(this);
即可
React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过prop和state的浅对比来实现 shouldComponentUpate()。
如果React组件的 render() 函数在给定相同的props和state下渲染为相同的结果,在某些场景下你可以使用 React.PureComponent 来提升性能。
React.PureComponent 的 shouldComponentUpdate() 只会对对象进行浅对比。如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断(表现为对象深层的数据已改变视图却没有更新, 原文:false-negatives)。当你期望只拥有简单的props和state时,才去继承 PureComponent ,或者在你知道深层的数据结构已经发生改变时使用 forceUpate() 。或者,考虑使用 不可变对象 来促进嵌套数据的快速比较。
此外,React.PureComponent 的 shouldComponentUpate() 会忽略整个组件的子级。请确保所有的子级组件也是”Pure”的。
PureComponent的作用:
PureComponent 其实是在内部帮我们简单实现了一下shouldComponentUpdate的功能,以便提供组件的性能;这里的简单指是:对prop和state做浅比较,若浅比较结果相同,则该组件以及其子组件不做render;否则,render。
使用PureComponent注意事项:
PureComponent主要针对prop和state为基本数据类型,如bool、string、number;
对于数组和对象等引用类型,则要引用不同,才会渲染;如果引用相同,则PureComponent浅比较返回结果相同,不做render;
PureComponent 中不建议再另外重写shouldComponentUpdate方法,否则会报warning信息:
PureComponent的最好作为展示组件,如果prop和state每次都会变,PureComponent做浅比较也会影响性能,可以考虑直接用Component;
对于prop和state数据结构比较复杂的情况,可以考虑自己重写shouldComponentUpdate方法来做优化;
React会将当前传入的参数对象与组件当前的状态合并,然后触发调和过程,在调和的过程中,React会以相对高效的方式根据新的状态构建React元素树并且重新渲染整个UI界面.
React得到的元素树之后,React会自动计算出新的树与老的树的节点的差异,然后根据差异对界面进行最小化的渲染,在React的差异算法中,React能够精确的知道在哪些位置发生看改变以及应该如何去改变,这样就保证了UI是按需更新的而不是重新渲染整个界面
单页应用(SinglePage Application,SPA)
指只有一个主页面的应用,一开始只需加载一次 js,css 等相关资源。所有的内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅刷新局部资源。
多页应用(MultiPage Application,MPA)
指有多个独立的页面的应用,每个页面必须重复加载 js,css 等相关资源。多页应用跳转,需要整页资源刷新。
两者对比表格:
SPA ||| MPA
结构:一个主页面 + 许多模块的组件 ||| 许多完整的页面
体验:页面切换快,体验佳;当初次加载文件过多时,需要做相关的调优。 ||| 页面切换慢,网速慢的时候,体验尤其不好
资源文件:组件公用的资源只需要加载一次 ||| 每个页面都要自己加载公用的资源
适用场景:对体验度和流畅度有较高要求的应用,不利于 SEO(可借助 SSR 优化 SEO) ||| 适用于对 SEO 要求较高的应用
过渡动画:Vue 提供了 transition 的封装组件,容易实现 ||| 很难实现
内容更新:相关组件的切换,即局部更新 ||| 整体 HTML 的切换,费钱(重复 HTTP 请求)
路由模式:可以使用 hash ,也可以使用 history ||| 普通链接跳转
数据传递:因为单页面,使用全局变量就好(Vuex) ||| cookie 、localStorage 等缓存方案,URL 参数,调用接口保存等
相关成本:前期开发成本较高,后期维护较为容易 ||| 前期开发成本低,后期维护就比较麻烦,因为可能一个功能需要改很多地方
单页应用实现核心:前端路由
前端路由的核心:改变视图的同时不会向后端发出请求。
TS好处:
1、强类型
2、不需要去浏览器中浏览效果,就能知道编译错误
静态类型检查可以做到early fail,即你编写的代码即使没有被执行到,一旦你编写代码时发生类型不匹配,
语言在编译阶段(解释执行也一样,可以在运行前)即可发现
4、类型就是最好的注释,看类型我们就知道这个是什么
3、即使ts中有编译报错,tsc依旧可以将其编译成js
学习TS的基本数据类型
定类型是为了安全,规矩多就安全
1、基础数据类型 :number \string\boolean\null\undefined
any 表示任意类型 void 表示空类型,空类型是针对函数的,表示函数没有返回值。返回空
2、内置对象类型 : Array \ Boolean \ HTMLElement
3、自定义类型 : 接口 类 泛型 枚举类型
在ts中,定义类型由两种方式:接口(interface)和类型别名(type alias)
interface只能定义对象类型,
type声明的方式可以定义组合类型,交叉类型和原始类型
如果用type alias 声明的方式,会导致一些功能的缺失
1.interface方式可以实现接口的extends/implements,而type 不行
2.interface可以实现接口的merge,但是type不行
webpack打包react vue,与自己的源代码分离使用splitchunks
webpack热更新:不用刷新浏览器而将新变更的模块替换掉旧的模块。
webpack会分析每个入口文件,解析包依赖关系的各个文件,每个模块都打包到bundle.js。webpack给每个模块分配一个唯一的ID并通过这个ID索引和访问模块。页面运行时,先启动entry.js,其他模块会在运行require时候执行。
1.Webpack Loader Plugin
(loader ,plugin分别什么作用,哪个配置可以把依赖包抽离出来,不打包进去)
【Loader】:用于对模块源码的转换,loader描述了webpack如何处理非javascript模块,并且在buld中引入这些依赖。loader可以将文件从不同的语言(如TypeScript)转换为JavaScript,或者将内联图像转换为data URL。比如说:CSS-Loader,Style-Loader等。babel-loader优雅降级配置ES高版本转成低版本
【Plugin】:是用于在webpack打包编译过程里,在对应的事件节点里执行自定义操作,比如资源管理、bundle文件优化等操作,
依赖包抽离 const ExtractTextWebapckPlugin= require("extract-text-webpack-plugin") module exclude node_modules
排除excloude排除node_modules
loader的使用很简单:
在webpack.config.js中指定loader。module.rules可以指定多个loader,对项目中的各个loader有个全局概览。
loader是运行在NodeJS中,可以用options对象进行配置。plugin可以为loader带来更多特性。loader可以进行压缩,打包,语言翻译等等。
loader从模板路径解析,npm install node_modules。也可以自定义loader,命名XXX-loader。
语言类的处理器loader:CoffeeScript,TypeScript,ESNext(Bable),Sass,Less,Stylus。任何开发技术栈都可以使用webpack。
webpack常用的loader
样式:style-loader、css-loader、less-loader、sass-loader等
文件:raw-loader、file-loader 、url-loader等
编译:babel-loader、coffee-loader 、ts-loader等
校验测试:mocha-loader、jshint-loader 、eslint-loader等
目的在于解决loader无法实现的其他事,从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。webpack提供了很多开箱即用的插件:CommonChunkPlugin主要用于提取第三方库和公共模块,避免首屏加载的bundle文件,或者按需加载的bundle文件体积过大,导致加载时间过长,是一把优化的利器。而在多页面应用中,更是能够为每个页面间的应用程序共享代码创建bundle。
webpack功能强大,难点在于它的配置文件,webpack4默认不需要配置文件,可以通过mode选项为webpack指定了一些默认的配置,mode分为:development/production,默认是production。
插件可以携带参数,所以在plugins属性传入new实例。
webpack常用的plugin
webpack内置UglifyJsPlugin,压缩和混淆代码。
webpack内置CommonsChunkPlugin,提高打包效率,将第三方库和业务代码分开打包。
ProvidePlugin:自动加载模块,代替require和import
html-webpack-plugin可以根据模板自动生成html代码,并自动引用css和js文件extract-text-webpack-plugin 将js文件中引用的样式单独抽离成css文件
DefinePlugin 编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用。
【Mode】可以在config文件里面配置,也可以在CLI参数中配置:webpack--mode=production(一般会选择在CLI,也就是npm scripts里面进行配置)。
在webpack4以下版本,webpack3.XX,通过plugins进行环境变量的配置。
【resolve】模块,resolver是个库,帮助webpack找到bundle需要引入的模块代码,打包时,webpack使用enhanced-resolve来解析路径。
2.webpack优化
多进程打包 安装插件thread-loader parallel-webpack HappyPack
多进程压缩 parallel-uglify-plugin terser-webpack-plugin
资源CDN 公用代码提取,使用 CDN 加载
动态polyfill 动态 polyfill 指的是根据不同的浏览器,动态载入需要的 polyfill
http2.0,https连接,
http概述:超文本传输协议,是互联网上应用最为广泛的一种网络协议
http的缺点
1.通信使用明文可能会被窃听。
2.不验证通信方的身份可能遭遇伪装。
3.无法证明报文的完整性,可能已遭篡改。
https就是在安全的传输层上发送的http。它在将http报文发送给TCP之前,先将其发送给了一个安全层 ,对其进行加密。http安全层是通过ssl及其现代替代协议TSL来实现的。
https的优点
(1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
(2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
https的缺点
但是https因为加了层ssl,所以在效率方面比较低,会使页面加载的时长延长近50%,也会增加10-20%的耗电。
需要安装证书,在一定基础上增加部署费用,并且报文加密解密对数据传递有一点的效率影响。
http/2.0的目标是改善用户加载页面的时候更快
HTTP/2采用二进制格式而非文本格式
HTTP/2是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
对称密钥加密是指加密和解密使用同一个密钥的方式,一方通过密钥将信息加密后,把密文传给另一方,另一方通过这个相同的密钥将密文解密,转换成可以理解的明文
非对称加密是加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。
socket是传输控制层协议,webSocket是应用层协议
WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。
一开始的握手需要借助HTTP请求完成。
HTTP请求缺点:
会导致过多不必要的请求,浪费流量和服务器资源,每一次请求、应答,都浪费了一定流量在相同的头部信息上
然而WebSocket的出现可以弥补这一缺点。
在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握 手的动作,然后单独建立一条TCP的通信通道进行数据的传送。
原理:(webSocket)
WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。
1. 浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
2. TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)
3. 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。
4. 当收到了连接成功的消息后,通过TCP通道进行传输通信。
WebSocket与HTTP的关系
相同点:
都是一样基于TCP的,都是可靠性传输协议。
都是应用层协议
不同点:
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
WebSocket是需要握手进行建立连接的。
F12 断点 错误附近输出打印 火狐中的firebug IE开发者工具 Emmet
200 OK 请求成功。一般用于GET与POST请求
3开头 重定向
300 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 查看其它地址。与301类似。使用GET和POST请求查看
304 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 使用代理。所请求的资源必须通过代理访问
306 已经被废弃的HTTP状态码
307 临时重定向。与302类似。使用GET请求重定向
400 客户端请求的语法错误,服务器无法理解
401 请求要求用户的身份认证
402 保留,将来使用
403 服务器理解请求客户端的请求,但是拒绝执行此请求
404 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405 客户端请求中的方法被禁止
406 N服务器无法根据客户端请求的内容特性完成请求
407 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 服务器等待客户端发送的请求时间过长,超时
409 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 服务器无法处理客户端发送的不带Content-Length的请求信息
412 客户端请求信息的先决条件错误
413 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 请求的URI过长(URI通常为网址),服务器无法处理
415 服务器无法处理请求附带的媒体格式
416 客户端请求的范围无效
417 服务器无法满足Expect的请求头信息
500 服务器内部错误,无法完成请求
501 服务器不支持请求的功能,无法完成请求
502 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 充当网关或代理的服务器,未及时从远端服务器获取请求
505 服务器不支持请求的HTTP协议的版本,无法完成处理
HTTP是超文本传输协议,信息是明文传输的,HTTPS是具有ssl/tls加密传输协议。
默认端口不同,前者是80,后者是443。
HTTPS比HTTP安全
HTTPS协议需要到CA申请证书,需要一定费用
什么是浏览器缓存
Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。只有当网站明确标识资源已经更新,浏览器才会再次下载网页。浏览器和网站服务器是根据缓存机制进行缓存的
非HTTP协议定义的缓存机制
浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires; Cache-control等)。但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的节点中加入标签
上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。
浏览器在第一次请求发生后,再次请求时:
浏览器会先获取该资源缓存的header信息,根据其中的expires和cache-control判断是否命中强缓存),若命中则直接从缓存中获取资源,包括缓存的header信息,本次请求不会与服务器进行通信;
如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/IF-Modified-Since、Etag/IF-None-Match),由服务器根据请求中的相关header信息来对比结果是否命中协商缓存,若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容
这里说的缓存是指浏览器(客户端)在本地磁盘中对访问过的资源保存的副本文件。
浏览器缓存主要有以下几个优点:
1. 减少重复数据请求,避免通过网络再次加载资源,节省流量。
2. 降低服务器的压力,提升网站性能。
3. 加快客户端加载网页的速度,提升用户体验。
浏览器缓存分为强缓存和协商缓存,两者有两个比较明显的区别:
1. 如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
2. 在chrome中强缓存(虽然没有发出真实的http请求)的请求状态码返回是200(from cache);而协商缓存如果命中走缓存的话,请求的状态码是304(not modified)。不同浏览器的策略不同,在Fire Fox中,from cache状态码是304.
强缓存
强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。
Expires:
该字段是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。
Cache-Control:
Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较常用的设置值:
no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,
如果之前的响应中存ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。
为什么要有Etag
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
1.一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间)
这个时候我们并不希望客户端认为这个文件被修改了,而重新GET
2.某些文件修改非常频繁,
比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
3.某些服务器不能精确的得到文件的最后修改时间。
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
200 OK(from cache)与304 Not Modified的区别
200 OK( from cache )不向服务器发送请求,直接使用本地缓存文件。
304 Not Modified则向服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304。
缓存类型 获取资源形式 状态码 发送请求到服务器
强缓存 从缓存取 200(from cache) 否,直接从缓存取
协商缓存 从缓存取 304(Not Modified) 否,通过服务器来告知缓存是否可用
用户行为对缓存的影响
用户操作 Expires/Cache-Control Last-Modied/Etag
地址栏回车 有效 有效
页面链接跳转 有效 有效
新开窗口 有效 有效
前进回退 有效 有效
F5刷新 无效 有效
Ctrl+F5强制刷新 无效 无效
1. HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),
或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
2. 需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
3. 经过HTTPS安全加密的请求
4. POST请求无法被缓存
5. HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存
qq、fire fox 、safari 、chrome 这几个浏览器的访问同一个页面,不同的浏览器在 F5 刷新的时候 ,同一个文件 qq 、fire fox 浏览器会返回 `304 Not Nodified`,在请求头中不携带 `Expires/Cache-Control`; 而 chrome 和 safari 刷新的时候,会返回 `200 from cache`, 没有真正发起请求,走强缓存。可见不同的浏览器反馈是不一致的,所以下面表格中"F5刷新"时 `Expires/Cache-Control` 会无效我认为是存在一定争议的。而 Ctrl + F5 强制刷新的时候,会暂时禁用强缓存和协商缓存。
Eslint 是一个JavaScript验证工具,有了它可以让你的编辑器像ide一样进行一些静态的错误提示功能.
npm install eslint -g
某些文件关闭eslint检测
在文件的最顶端加上注释 /*eslint-disable*/
关闭某一行代码的eslint检查
// eslint-disable-next-line
.eslintrc.json配置rules选项
(版本回退是什么命令,哪个命令查看已删除的提交commitId)
git-reset 版本回退
git reset --hard xxx 回到上一个版本
git reset --soft xxx 该命令将最近一次提交节点的提交记录回退到暂存区
git reset --mixed xxx 是将最近一次提交节点记录回退到工作区
git log 与 git reflog 查看历史记录(被删除的历史commit ID)
git场景问题
提交暂存区git add 出错 git reset HEAD <文件名> 回退
提交本地仓库
git commit出错:
1.更改 commit 信息:git commit --amend -m“新提交消息”
2.漏提交:git add missed-file // missed-file 为遗漏提交文件
git commit --amend --no-edit //--no-edit提交消息不会更改
3.git reset --hard commit_id git log查看提交的版本
git revert 是提交一个新的版本
git fetch 将远程主机的更新全部放到本地中
git revert 和 git reset 的区别:
(1)git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
(2)git revert是用一次逆向的commit“中和”之前的提交 ,合并的时候回滚的变化不会出现
git reset是之间把某些commit在某个branch上删除,合并时候回滚的commit会被引入
1.Node不是一个后端语言,但是它可以做类似后端语言的功能
2.Node是使用谷歌V8引擎
3.Node是js的一个运行环境
4.Node具有非阻塞I/O 特点
5.Node采用了Common.js规范
node+koa2 node+express
用于快速构建Node.js项目
node.js 是一个基于 Chrome V8 引擎的 JavaScirpt 运行环境。
Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效**
Node.js基于commonjs规范
事件驱动: 任务执行,发布者,订阅者,事件驱动 .
异步(非阻塞): 执行某一个任务的同时也可以执行其他任务
同步(阻塞): 执行某一个任务,这个任务如果没有执行完成,其他任务必须等待
I/O: 输入/输出( 数据库操作,文件系统操作等 ) - 服务器的环境
非阻塞I/O模型: 当使用Node.js来实现数据库操作、文件系统等操作时,要进行的异步操作,异步操作的核心传统实现方式就是回调函数和事件。
Node.js的包管理工具npm
优点:Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,异步编程,使其轻量又高效。
缺点:单进程,单线程,只支持单核cpu,不能充分的利用多核cpu服务器。一旦这个进程崩掉,那么整个web服务就崩掉了。
内置模块 http 是用于创建一个能够处理和响应 http 响应的服务
fs 用于对系统文件及目录进行读写操作。
path 提供了一些用于处理文件路径的小工具
Url:帮助我们对提交上来的url进行解析处理
querystring 提供用于解析和格式化 URL 查询字符串的工具。qs.parse() qs.stringify()
TypeScript具有类型系统,且是JavaScript的超集。它可以编译成普通的JavaScript代码。
TypeScript支持任意浏览器,任意环境,任意系统并且是开源的。
npm install -g typescript
tsc --init 生成tsconfig.json配置文件
基础数据类型
number、string、boolean、null 、undefined
any 表示任意类型
void 表示空类型
内置对象类型
Array Boolean
HTMLElement
HTMLDivElement
自定义类型
接口 interface
类
泛型 未来的类型定义的时候不知道是什么类型,调用的时候才知道
元组
1、数组中的数据类型必须和规定的类型顺序对应起来
2、当使用越界索引给数组赋值的时候,会使用联合类型(只要值是规定类型的某一种即可)。
枚举 enum类型是对JavaScript标准数据类型的一个补充
never类型表示的是那些永不存在的值的类型。
readonly:只读属性,不可修改
sex? :表示sex是一个可传属性,可以有也可以没有
[propName: string]: any;表示新增的属性可以是任意类型
arr3: Array 数组类型定义
arr2: (number | string)[]
fn (a: number, b: number) : number 函数类型定义
pwd:输入pwd命令,Linux会输出当前目录。
ls命令用来查看目录的内容。
cd命令用来改变所在目录。
cat命令可以用来合并文件,也可以用来在屏幕上显示整个文件的内容。
grep命令的最大功能是在一堆文件中查找一个特定的字符串。
touch命令用来创建新文件
cp命令用来拷贝文件
mv命令用来移动文件
rm命令用来删除文件。
mkdir 创建文件夹创建目录
多进程打包 - 速度分析
多进程压缩 - 体积分析
资源CDN
动态polyfill - 根据不同浏览器,动态载入需要的polyfill,大幅度减少构建体积
split-thunk
前端构建项目中,为了提高打包效率,往往将第三库与业务逻辑代码分开打包,因为第三方库往往不需要经常打包更新。webpack建议使用CommonsChunk 来单独打包第三方库
webpack loader(转换器)和plugin(插件)有什么区别:
loader它是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss转换为A.css,单纯的文件转换过程
plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务
loader:
优雅降级,
图片打包
plugin:
html产出:把public下面的html文件打包到build里面的index.html并自动引入app.js
css抽离
静态资源拷贝
1.原型链继承
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。
(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。
(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2.借用构造函数继承
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
3.组合继承(组合原型链继承和借用构造函数继承)
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
4.原型式继承
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。 object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
5.寄生式继承
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
6.寄生组合式继承(常用)
重点:修复了组合继承的问题
寄生:在函数内返回对象然后调用
组合:1、函数的原型等于另一个实例。
2、在函数中用apply或者call引入另一个构造函数,可传参
防止事件捕获和冒泡:
w3c的方法是e.stopPropagation()
IE则是使用e.cancelBubble = true
取消默认事件
w3c的方法是e.preventDefault()
IE则是使用e.returnValue = false
jQuery用法
阻止默认事件 return false (不停止冒泡)
变量的作用域无非就是两种:
全局变量和局部变量。javascript的作用域是相对函数而言的,可以称为函数作用域
全局作用域:
最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的
局部作用域:
局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的
作用域链:
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。
作用域链的前端,始终都是当前执行的代码所在环境的变量对象
作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
全局执行环境的变量对象始终都是作用域链上的最后一个对象
1.for循环
使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。
2.foreach循环
遍历数组中的每一项,没有返回值,对原数组没有影响,不支持IE。
有一些局限,不能continue跳过或者break终止循环
3.map循环
有返回值,可以return出来
map的回调函数中支持return返回值
并不影响原来的数组,return的是新数组
4.for of遍历
可以正确响应break、continue和return语句
5.filter遍历
不会改变原始数组,返回新数组
6.every遍历
every()是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。
7.some遍历
some()是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true。
8.reduce
reduce()方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
9.reduceRight
reduceRight()方法的功能和reduce()功能是一样的,
不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。
10.find
find()方法返回数组中符合测试函数条件的第一个元素。否则返回undefined
11.findIndex
对于数组中的每个元素,findIndex方法都会调用一次回调函数(采用升序索引顺序),直到有元素返回 true。
只要有一个元素返回 true,findIndex立即返回该返回 true 的元素的索引值。
如果数组中没有任何元素返回 true,则 findIndex 返回 -1。
findIndex 不会改变数组对象。
12.keys,values,entries
ES6 提供三个新的方法 —— entries(),keys()和values() —— 用于遍历数组。
它们都返回一个遍历器对象,可以用for...of循环进行遍历,
唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
前端的话,定义一个新的数组for循环判断,有个公式,计算起始页和终止页的。
符合条件push仅数组中,后端就是用limt判断
1. 普通数组排序
js中用方法sort()为数组排序。sort()方法有一个可选参数,是用来确定元素顺序的函数。如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序。
2. 冒泡排序
(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个位置。
(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
3. 快速排序:递归思想,两边快速的排序,冒泡排序的改进
(1)选择数组中间数作为基数,并从数组中取出此基数;
(2)准备两个数组容器,遍历数组,逐个与基数比对,较小的放左边容器,较大的放右边容器;
(3)进行相同的操作,直到数组中只有一个元素时,返回该数组。
4. 插入排序
(1)从第一个元素开始,该元素可以认为已经被排序
(2)取出下一个元素,在已经排序的元素序列中扫描
(3)如果该元素(已排序)大于新元素,将该元素移到下一位置
(4)重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
(5)将新元素插入到下一位置中
(6)重复步骤2
5. 选择排序
(1)在未排序序列中找到最小(大)元素
(2)并存放到排序序列的起始位置
(3)然后,再从剩余未排序元素中继续寻找最小(大)元素
(4)然后放到已排序序列的末尾。
(5)以此类推
1、concat
js的Array对象提供了一个叫concat()方法,连接两个或更多的数组,并返回结果。
var c = a.concat(b); //c=[1,2,3,4,5,6];
这里有一个问题,concat方法连接a、b两个数组后,a、b两个数组的数据不变,同时会返回一个新的数组。这样当我们需要进行多次的数组合并时,会造成很大的内存浪费,如果是数据量比较小的时候,还可以勉强用,如果数据量大的时候,这个就不妥了,所以这个方法肯定不是最好的。
2、for循环
大概的思路是:遍历其中一个数组,把该数组中的所有元素依次添加到另外一个数组中。直接上代码:
for(var i in b) { a.push ( b[i] );}
3、apply
函数的apply方法有一个特性,那就是func.apply(obj,argv),argv是一个数组。
a.push.apply(a,b);
调用a.push这个函数实例的apply方法,同时把,b当作参数传入,
这样a.push这个方法就会遍历b数组的所有元素,达到合并的效果。
这里可能有点绕,我们可以把b看成[4,5,6],变成这样:
a.push.apply(a,[4,5,6]);
然后上面的操作就等同于:
a.push(4,5,6);
这样就很清楚了!
push,在数组末尾添加一位或多位元素
pop,删除数组最后一位元素
unshift,在数组的开头添加一位或多位元素
shift,删除数组的第一位元素
join,将数组转换为字符串
reserve,反转数组元素的顺序
sort,对数组进行排序
concat,连接两个或多个数组
splice,添加或删除数组中的元素
slice,从已有的数组中返回选定的元素
indexOf、lastIndexOf,查找数组中的元素
forEach,对数组进行遍历循环,对数组中每一项运行指定的函数
map,迭代数组
filter,对数组中的元素进行指定的检查返回符合条件的元素放入一个新数组中
every,测试所有元素是否都符合指定条件
some,测试某些元素是否符合指定条件
reduce,接收一个函数作为累加器,数组中的每个值开始缩减,最终计算为一个值
toString,将数组转换为字符串
使用ES6 Set
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
arr = Array.from(new Set(arr)); [...new Set(arr)]
console.log(arr);//[1, 4, 2, 3, 6]
使用indexOf
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
var newArr = [];
arr.forEach((item) => {
newArr.indexOf(item) === -1 ? newArr.push(item) : "";
});
console.log(newArr);//[1, 4, 2, 3, 6]
使用lastIndexOf
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
var newArr = [];
arr.forEach((item) => {
newArr.lastIndexOf(item) === -1 ? newArr.push(item) : "";
});
console.log(newArr);//[1, 4, 2, 3, 6]
使用双重for循环加splice方法
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
arr.splice(j,1);
j--;
}
}
}
console.log(arr);//[1, 4, 2, 3, 6]
使用forEach和includes方法
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
var newArr = [];
arr.forEach((item) => {
newArr.includes(item) ? "" : newArr.push(item);
});
console.log(newArr);//[1, 4, 2, 3, 6]
使用fliter和includes方法
var arr = [1, 1, 4, 2, 2, 3, 3, 3, 6, 6, 6];
var newArr = [];
arr.filter((item) => {
newArr.includes(item) ? "" : newArr.push(item);
});
console.log(newArr);//[1, 4, 2, 3, 6]
for...of 是ES6引入用来遍历所有数据结构的统一方法。
这里的所有数据结构只指具有iterator接口的数据。
一个数据只要部署了 Symbol.iterator,就具有了 iterator接口,就可以使用 for...of 循环遍历它的成员。
也就是说,for...of循环内部调用的数据结构为Symbol.iterator方法。
部署在 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就认为是"可遍历的"。
Iterator(伊特瑞特):
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
通俗点理解就是为了解决不同数据结构遍历的问题,引入了Iterator.
Iterator的特点:
各种数据结构,提供一个统一的、简便的访问接口
使得数据结构的成员能够按某种次序排列
ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费
原生具备 Iterator 接口的数据结构如下。
Array
Map
Set
String:字符串是一个类似数组的对象,也原生具有 Iterator 接口。
TypedArray:
通俗理解:ArrayBuffer是一片内存空间,不能直接引用里面的数据,可以通过TypedArray类型引用,
用户只能通过TypedArray使用这片内存,不能直接通过ArrayBuffer使用这片内存
函数的 arguments 对象
NodeList 对象
除了原生具备Iterator 接口的数据之外,其他数据结构(主要是对象)的 Iterator 接口,
都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。
对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。不过,严格地说,对象部署遍历器接口并不是很必要,因为这时对象实际上被当作 Map 结构使用,ES5 没有 Map 结构,而 ES6 原生提供了。
一个对象如果要具备可被for...of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。
第一种:
for...in
第二种:
1)Object.keys(obj)
2)Object.values(obj)
参数:
obj:要返回其枚举自身属性的对象
返回值:
一个表示给定对象的所有可枚举属性的字符串数组。
第三种:
使用Object.getOwnPropertyNames(obj)
返回一个数组,包含对象自身的所有属性(包含不可枚举属性)
遍历可以获取key和value
map 与 filter 区别:
相同点:filter 和 map 都是对数组的操作,均返回一个新的数组
不同点:filter是满足条件的留下,是对原数组的过滤;map则是对原数组的加工,映射成一对一映射的新数组
map 与 forEach 区别:
map()会分配内存空间存储新数组并返回,forEach()不会返回数据(undefined)。
forEach()允许callback更改原始数组的元素。map()返回新的数组。
面向对象编程:
将所需要做的功能抽象成一个“对象”,然后一遍遍地调用这个对象来完成你想要的功能。
面向对象的三大特征:
1.封装
我们平时所用的方法和类都是一种封装,当我们在项目开发中,遇到一段功能的代码在好多地方重复使用的时候,我们可以把他单独封装成一个功能的方法,这样在我们需要使用的地方直接调用就可以了。
2.继承
继承在我们的项目开发中主要使用为子类继承父类,继承会继承父类的实例属性和实例方法,并不会继承静态属性和静态方法,并且静态方法只能通过类名去调用。
3.多态
多态的具体表现为方法重载和方法重写:
方法重载:
重载是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数
方法重写:
重写(也叫覆盖)是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现。即函数名和参数都一样,只是函数的实现体不一样
三大特征的优点:
封装:
封装的优势在于定义只可以在类内部进行对属性的操作,外部无法对这些属性指手画脚,要想修改,也只能通过你定义的封装方法;
继承:
继承减少了代码的冗余,省略了很多重复代码,开发者可以从父类底层定义所有子类必须有的属性和方法,以达到耦合的目的;
多态:
多态实现了方法的个性化,不同的子类根据具体状况可以实现不同的方法,光有父类定义的方法不够灵活,遇见特殊状况就捉襟见肘了
1.执行时间
window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。
2.编写个数不同
window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个
$(document).ready()可以同时编写多个,并且都可以得到执行
3.简化写法
window.onload没有简化写法
$(document).ready(function(){})可以简写成$(function(){});
this代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,
随着函数使用场合的不同,this的值会发生变化。
指向:
1.在方法中,this 表示该方法所属的对象。
2.如果单独使用,this 表示全局对象。
3.函数中,this 表示全局对象。
4.严格模式下,this 是未定义的(undefined)。
5.在事件中,this 表示接收事件的元素。
6.类似 call() 和 apply() 方法可以将 this 引用到任何对象。
7.箭头函数本身是没有this和arguments的,引用的this实际上是调用的是定义时的上一层作用域的this。
声明位于文档中的最前面的位置,处于 标签之前。
声明不是一个 HTML 标签;它是用来告知 Web 浏览器页面使用了哪种 HTML 版本。
在 HTML 4.01 中, 声明需引用 DTD (文档类型声明),
因为 HTML 4.01 是基于 SGML (Standard Generalized Markup Language 标准通用标记语言)。
DTD 指定了标记语言的规则,确保了浏览器能够正确的渲染内容。
HTML5 不是基于 SGML,因此不要求引用 DTD。
给您 HTML 文档添加 声明,确保浏览器能够预先知道文档类型。
解构定义:允许按照一定模式,从数组和对象中提取值,对变量进行赋值。
解构必须满足的条件:(模式匹配),只要等号两边的模式相同,左边的变量就会被赋予对应的值。
主要介绍2种解构常用的类型:数组解构和对象解构。
数组解构:
1.数组中的变量个数比赋值的数组中个数少的解构:
2.数组中的变量个数比赋值的数组中个数多的解构:
3.数组中的变量中有空字符的解构:上面的3种数组解构,赋值的数组的数值按位赋值给另外一方数组中的变量
4.数组中的变量中有不定参数(有些时候也叫扩展运算符)的解构:需要注意的是不定参数必须放最后。
5.数组中的变量中有默认值的解构:如果赋值的数组个数没有另外一方数组变量个数多,并且变量数组有默认,
没有进行赋值用默认,进行赋值用赋值的
对象的解构:两方也需要相同类型的括号,对象结构使用大括号{}
普通对象解构:
对象跟数值解构不同的一点,对象解构不是按位去赋值,是根据键名(属性名) 来进行赋值
有默认值的对象解构
跟数组的默认值差不多,有赋值就用赋值的,没有就用默认值
有不定参数的对象解构
跟数组的不定参数差不多,不定参数放在最后,不定参数创建一个对象接受的剩下的键名键值(属性名属性值)
有嵌套的对象解构
主要注意嵌套层次是不是赋值一方对象的嵌套层次相同。
1.图片移动实现原理:
利用浮动将所有所有照片依次排成一行,给这一长串图片添加一个父级的遮罩,每次只显示一张图,其余的都隐藏起来。对图片添加绝对定位,通过控制left属性,实现照片的移动。
2.图片移动动画原理:
从a位置移动到b位置,需要先计算两点之间的差值,通过差值和时间间隔,计算出每次移动的步长,通过添加定时器,每次移动相同的步长,实现动画效果。
3.图片定位停止原理:
每一张照片都有相同的宽度,每张照片都有一个绝对的定位数值,通过检测定每次移动后,照片当前位置和需要到达位置之间的距离是否小于步长,如果小于,说明已经移动到位,可以将定时器清除,来停止动画。
4图片切换原理:
在全局设置一个变量,记录当前图片的位置,每次切换或跳转时,只需要将数值修改,并调用图片页数转像素位置函数,再调用像素运动函数即可。
5.自动轮播原理:
设置定时器,一定时间间隔后,将照片标记加1,然后开始切换。
6.左右点击切换原理:
修改当前位置标记,开始切换。这里需要注意与自动轮播之间的冲突。当点击事件触发之后,停止自动轮播计时器,开始切换。当动画结束后再次添加自动轮播计时器。
7.无缝衔接原理:
需要无缝衔接,难度在于最后一页向后翻到第一页,和第一页向前翻到最后一页。由于图片的基本移动原理。要想实现无缝衔接,两张图片就必须紧贴在一起。所以在第一张的前面需要添加最后一张,最后一张的后面需要添加第一张。
首先判断图片的位置,是否移动到位。当满足当前位置,与预定位置之间的距离小于一步时,认定为移动到位,并把图片直接定位到预定位置。然后判断,图片的位置是否需要跳转。
ps:这里一定要在图片运动函数结束后,在进行跳转。
8.预防鬼畜原理:
始终保证轮播图的运动动画只有一个,从底层杜绝鬼畜。需要在每次动画开始之前,尝试停止动画定时器,然后开始为新的动画添加定时器。
轮播图鬼畜的本质原因就是,同一时间多个定时器添加在图片上,这些定时器直接相互冲突,造成图片的抖动。
解决方法:每次执行运动函数之前,先尝试清除一下,上一个轮播图的定时器。确保同时触发运动函数时,只有一个定时器在工作。
9.预防暴力点击原理:
如果用户快速点击触发事件,会在短时间内多次调用切换函数,虽然动画函数可以保证,不会发生鬼畜,但在照片从最后一张到第一张的切换过程,不会按照正常的轮播,而是实现了跳转。所以需要通过添加口令的方式来,限制用户的点击。当用户点击完成后,口令销毁,动画结束后恢复口令。
10.小圆点的位置显示原理:
每次触发动画时,通过全局变量标记,获取当前页数,操作清除所有小圆点,然后指定一页添加样式。
11.点击触发跳转的原理:
类似于左右点击触发,只是这是将全局页面标记,直接修改,后执行动画。需要避免与自动轮播定时器的冲突。
1.Array.from()方法用于将对象转为真正的数组(类数组转数组)
2.Array.of()方法用于将一组值,转换为数组。
console.log(Array.of(1,2,3,4,4,50));//[1, 2, 3, 4, 4, 50]
3.Object.assign(目标对象,对象1,对象2)用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。(浅拷贝)
一、提升(Hosting)
简单说就是在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。
二、变量提升
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。
变量提升即将变量声明提升到它所在作用域的最开始的部分。
变量声明的提升是以变量所处的第一层词法作用域为“单位”的,即全局作用域中声明的变量会提升至全局最顶层,函数内声明的
三、函数提升
即函数提升只会提升函数声明,而不会提升函数表达式。
四、为什么会有提升?
函数提升就是为了解决相互递归的问题,大体上可以解决像ML语言这样自下而上的顺序问题。
大概是说,变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。
redux和vuex的区别
1)vuex是redux的基础上进行改变,对仓库的管理更加明确
2)使用mutation来替换redux中的reducer
3)vuex有自动渲染的功能,所以不需要更新
redux和flux的区别
1)redux是flux中的一个实现
2))在redux中我们只能定义一个store,在flux中我们可以定义多个
3)在redux中,store和dispatch都放到了store,结构更加清晰
4)在redux中本身就内置State对象,对仓库的管理更加明确
flex是由 flex-grow:1父容器在主轴上还有多少剩余空间,
flex-shrink当父元素的宽度大于所有子元素的宽度的和时(即父元素会有剩余空间),
子元素如何分配父元素的剩余空间
flex-basis基准值组成
flex 怎么实现1个盒子垂直居中 如何实现四个盒子水平均匀分布
父容器 display:flex; justify-content: center; align-items: center;
display: flex; justify-content:space-evenly; align-items: center;
设置css:fixed固定定位
判断滚动条滚动的距离大于导航条距顶部的距离,来判断是否实现吸顶,然后addClass添加样式
a{
&:hover {} //这里&代表它的上一级就是a
}
::before和::after必须配合content属性来使用,
content用来定义插入的内容,content必须有值,至少是空。
默认情况下,伪类元素的display是默认值inline,可以通过设置display:block来改变其显示。
1.清除浮动:
在浮动元素后面添加一个空的Div标签,然后在设置它的清除浮动要是,使用after伪元素
2.常见消息框 :
伪类content:' ' 伪类4条边必须宽度相同,而且其他三条边为transparent
可以通过设置定位元素left,top值为50%,translate(-50%,-50%) 来使任意宽高的元素居中。
div::before{
content:' ';
3.阴影 : 通过设置before,after不同位置,不同旋转角度,要保证伪类的颜色及z-index
div.outer::before,div.outer::after{content:'';
z-index:1;
width:50%;
height:3px;
position:absolute;
left:10px;
bottom:7px;
background-color:transparent;
box-shadow:5px 5px 10px rgba(0,0,0,0.5);
-webkit-transform:rotate(-3deg);
4.做出各种图形效果
#star-five:before {
border-bottom: 80px solid red;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
position: absolute;
height: 0;
width: 0;
top: -45px;
left: -65px;
content: '';
transform: rotate(-35deg);
}
#star-five:after {
width: 0;
height: 0;
border-left: 100px solid transparent;
border-right: 100px solid transparent;
border-bottom: 70px solid yellow;
top: 7px;
left: -110px;
position: absolute;
display: block;
content: '';
transform: rotate(-70deg);
}
权重叠加 0,0,0,5 + 0,0,0,5 =0,0,0,10 而不是 0,0,1,0,所以不会存在10个div能赶上一个类选择器的情况
继承的权重是0
1)如果选中了,那么以上面的公式来计权重。谁大听谁的。
2)如果没有选中,那么权重是0,因为继承的权重为0
当选择器冲突时,权重高的生效;当权重相同时,写在后头的会把前面的覆盖。
方式一:border + border - img + 线性渐变linear-gradient
方式二:定位 + 伪元素 + background + 线性渐变linear-gradient
方式三:定位 + 伪元素 + transform缩放(scale)
方法一:
设置绝对定位
宽度固定区域设置 position:absolute+ left/right+ top + width
自适应区域设置 margin-left/margin-right: 固定宽度区域的宽度。
注意:
(1)若左侧固定的高度大于右侧自适应区域高度
页面布局就变成这样了:(测试布局区域紧挨着自适应区域的下方,盖住了部分固定区域)
简单粗暴的就是测试布局区域定位的top值直接设置为两个区域最高的高度值
(2)若左侧固定的高度大于右侧自适应区域高度,且测试区域不进行定位
方法二:
浮动布局
左侧固定区域浮动+宽度,右侧自适应区域 设置margin-left :左侧宽度值。
方法三:
BFC规则
左侧固定区域浮动+宽度,右侧自适应区域(非浮动元素)设置overflow:hidden。
1、绝对定位布局:position + margin
缺点: 如果中间栏含有最小宽度限制,或是含有宽度的内部元素,当浏览器宽度小到一定程度,会发生层重叠的情况。
2、浮动布局: float + margin
3、flex布局
高度由内容决定。
4、table布局
高度由内容决定。
5、Grid网格布局
6、圣杯布局
7、双飞翼布局
8、对比圣杯布局和双飞翼布局
(1)都是左右栏定宽,中间栏自适应的三栏布局,中间栏都放到文档流前面,保证先行渲染。
(2)解决方案基本相似:都是三栏全部设置左浮动float:left,然后分别结局中间栏内容被覆盖的问题。
(3)解决中间栏内容被覆盖问题时,圣杯布局设置父元素的padding,双飞翼布局在中间栏嵌套一个div,
内容放到新的 div中,并设置margin,实际上,双飞翼布局就是圣杯布局的改进方案。
1 圆角边框:border-radius
2 多背景图:background
3 颜色和透明度:background: rgba(0,0,0,.5)
4 多列布局和弹性盒:display: flex
5 盒子的变幻(2D、3D)
transform: translate(50px,100px);//移动
transform: rotate(); //旋转
transform: scale(); //缩放
transform: skew(); //倾斜
6 过渡 transition: width 1s linear 2s;
动画:animation: myfirst 5s;
@keyframes myfirst { 0% {background: block;} 25% {background: red;} 50% {background: yellow;} 100% {background: green;} }
7 引入web字体(在服务器端存储)
8 媒体查询
9 阴影 h
10 文字阴影 text-shadow div
11 盒子阴影 box-shadow
1 语义化标签 section aside header nav
2 表单新特性:autofocus 自动获取焦点
placeholder 占位
multiple
autocomplete 自动补全,是否自动记录之前提交的数据,以用于下一次输入建议
required 在表单提交时会验证是否有输入,没有则弹出提示消息。
min:限定输入数字的最小值。
max:限定输入数字的最大值
3 video(视频)和audio(音频)
4 canvas画布
5 webworker 就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。
6 webscoket 服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
7 拖拽api
dragstart:源对象开始拖放。
drag:源对象拖放过程中。
dragend:源对象拖放结束。
过程对象:
dragenter:源对象开始进入过程对象范围内。
dragover:源对象在过程对象范围内移动。
dragleave:源对象离开过程对象
标准盒模型一个块的总宽度= width + margin(左右) + padding(左右) + border(左右)
怪异盒模型一个块的总宽度= width + margin(左右)(即width已经包含了padding和 border值)
弹性盒 display:flex(父元素添加)
弹性盒:控制子元素按主轴方向排列
弹性盒可以设置单独内容水平垂直居中
父元素:display:flex 子元素:margin:auto
灵活元素:灵活元素即使是内联元素也能设置宽高
加父元素身上
1.flex-direction 属性指定了弹性子元素在父容器中的位置。
row:横向从左到右排列(左对齐),默认的排列方式。
row-reverse:反转横向排列(右对齐,从后往前排,最后一项排在最前面。
column:纵向排列。
olumn-reverse:反转纵向排列,从后往前排,最后一项排在最上面。
2.justify-content:flex-start/flex-end/space-between/space-around
3.align-items: 设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式。
center/flex-start/flex-end/baseline/stretch
4.flex-wrap:属性用于指定弹性盒子的子元素换行方式。nowrap/wrap/wrap-reverse
5.align-content:设置各个行的对齐:
stretch - 默认。各行将会伸展以占用剩余的空间。
flex-start - 各行向弹性盒容器的起始位置堆叠。
flex-end - 各行向弹性盒容器的结束位置堆叠。
center -各行向弹性盒容器的中间位置堆叠。
space-between -各行在弹性盒容器中平均分布。
space-around
加子元素身
1、align-self:属性用于设置弹性元素自身在侧轴(纵轴)方向上的对齐方式。
align-self: auto | flex-start | flex-end | center | baseline | stretch
flex 属性用于指定弹性子元素如何分配空间。
1: 计算值为 1 1 auto
initial: 计算值为 0 1 auto
none:计算值为 0 0 auto
inherit:从父元素继承
2、第一个参数表示: flex-grow 定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
3、第二个参数表示: flex-shrink 定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
4、第三个参数表示: flex-basis给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小
1.使用margin进行固定长度的偏移
2.使用绝对定位并进行偏移(已知宽高)
#father{ position:relative; }
#son{ position: absolute; left:50%; top:50%;
margin-left: -子元素的宽/2; margin-top: -子元素的高/2; }
3.使用绝对定位并margin自适应进行居中
#father{ position:relative;}
#son{position: absolute; left: 0; top: 0; right: 0; bottom: 0; margin:auto; }
(啊不斯陆特)
4.使用弹性盒子来实现居中
#father{ display: flex; justify-content: center; align-items: center; }
(加斯特佛) (额来) (哎特木)
5.使用定位 + transform
#father{ position:relative;}
#son{ position: absolute; left: 50%; top: 50%; transform:translate(-50% -50%) }
6.table-cell布局
因为table-cell相当与表格的td,td为行内元素,无法设置宽和高,所以嵌套一层,嵌套一层必须设置display: inline-block;
1、相对定位position:relative;参考物是自己,不脱离文档流(初始位置仍然占据空 间),top:100px; 给正值是向该容器的中心点移动;
2、绝对定位position:absolute; 参考物是外层具有position属性的元素, 如果向外 都么有找到最后会参考body/html做定位
3、固定定位position:fixed; 参考物是可视窗口
4、粘性定位(了解)position:sticky; 是绝对定位+固定定位
情况一:
两个div垂直边界相邻,margin会等于二者中margin较大的值
解决方案:
1.position:absolute
2.float:left
情况二:
子元素在父元素内,子元素的margin-top会与父元素的margin-top重叠,值等于二者中较大的,如果只有子元素设置了margin-top,则显示为父元素的margin-top
解决方案:
1.给父元素设置border(给子元素设置边框没有用)
2.给父元素设置padding值
3.给父元素或子元素添加float:left
4.给父元素或子元素添加position:absolute
5.给父元素添加overflow:hidden
6.给子元素添加display:inline-block
情况三:
一个空白元素自身的margin-top和margin-bottom会重叠,值为而这种较大的
解决方案:
1.设置透明border
1、px实际上就是像素,用px设置字体大小时,比较稳定和精确
2、em就是根据基准来缩放字体的大小
3、rem是相对于根元素字体大小来显示的
4、pt的大小等于1英寸的1/72 浏览器的兼容性除了IE6-IE8,其他的浏览器都支持em和rem,px所有浏览器都支持
1、什么是BFC BFC(Block formatting context)直译为“块级格式化上下文”。
他是一个独立的渲染区域,也可以理解成一个独立的容器,并且这个容器里box的布局,与这个容器外的毫不相干。
2、BFC渲染规则
a.内部的box会在垂直方向,一个接一个的放置
b.box垂直方向的距离由margin决定。属于同一个BFC的两个相邻box的margin会发生重 叠
c.每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格 式化,否则相反)。
即使存在浮动也是如此
d.BFC的区域不会与float box重叠
e.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之 也如此
f.计算BFC的高度时,浮动元素也参与计算
3、如何产生BFC
a.根元素
b.float属性不为none
c.position为absolute或fixed
d.display为inline-block, table-cell,table-caption,flex,inline-flex
e.overflow不为visible
4、BFC的作用
a.自适应两栏布局
b.清除内部浮动
c.防止垂直margin重叠(放在两个BFC里)
1)css浏览器兼容问题(比如设置元素透明度,ie浏览器使用滤镜实现,filter
:progid:DXlmage Transform.Microsoft.Alpha(style=0,opacity=50);非IE浏览器
opacity:0.5)
解决方法:现在前端开发已经出现了非常多的框架和类库用于浏览器的兼容问题,比如jq类 库,解决获取元素中包含的所有文本内容兼容性问题,$(“element”).text(“element text”)
2)css3浏览器前缀问题
-ms-:ie浏览器
-o-:opera欧朋浏览器
-webkit-:谷歌浏览器
-moz-:火狐浏览器
工作中遇到的困难
1)IE6中高度不对问题
在div中给定了高度为1px,其它浏览器显示正常,可是ie6中显示的高度就不对了,这时我
给样式表中加 了个font-size:0px;line-height:0px;就好了
2)把border设为“0”像素虽然在页面上看不见,但按border默认值理解,
浏览器依然对 border- width/border-color进行了渲染,
即已经占用了内存值把border设为“none”即没有,浏览器解析“none”时将不作出渲染动作,即不会消耗内存
1.Media Queries 通过查询设备的宽度来执行不同的 css 代码,最终达到界面 的配置
2.Flex弹性布局
3.rem + viewport 缩放 实现原理 根据rem将页面放大dpr倍, 然后viewport设置为1/dpr.
4、rem实现 移动端适配方案:
1)viewport(scale=1/dpr) dpr:备像素比
2)rem 3)flex 4)vm/vh
以iphone8为例,iphone8的CSS像素为375px*677px,DPR是2,
所以其设备像素为750px*1354px
750(px) / 375(px) = 2
css预处理器用一种专门的编程语言,进行web页面样式设计,然后在编译成正常的css文件,
以供项目使用 在css中使用变量、简单的逻辑程序、函数。可以让你的css更加简洁、适应性更强、可读性更佳、更易于代码的维护
absolute:生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。
fixed :生成固定定位的元素,相对于浏览器窗口进行定位。
relative:生成相对定位的元素,相对于其正常位置进行定位。
static :默认值。没有定位。
sticky :粘性定位,该定位基于用户滚动的位置。
inherit :规定应该从父元素继承 position 属性的值。
none | 此元素不会被显示。 | ||
---|---|---|---|
block | 此元素将显示为块级元素,此元素前后会带有换行符。 | ||
inline | 默认。此元素会被显示为内联元素,元素前后没有换行符。 | ||
inline-block | 行内块元素。(CSS2.1 新增的值) | ||
list-item | 此元素会作为列表显示。 | ||
run-in | 此元素会根据上下文作为块级元素或内联元素显示。 | ||
compact | CSS 中有值 compact,不过由于缺乏广泛支持,已经从 CSS2.1 中删除。 | ||
marker | CSS 中有值 marker,不过由于缺乏广泛支持,已经从 CSS2.1 中删除。 | ||
table | 此元素会作为块级表格来显示(类似 ),表格前后带有换行符。
|
||
inline-table | 此元素会作为内联表格来显示(类似 ),表格前后没有换行符。
|
||
table-row-group | 此元素会作为一个或多个行的分组来显示(类似 | ||
table-header-group | 此元素会作为一个或多个行的分组来显示(类似 | ||
table-footer-group | 此元素会作为一个或多个行的分组来显示(类似 | ||
table-row | 此元素会作为一个表格行显示(类似 | ||
table-column-group | 此元素会作为一个或多个列的分组来显示(类似 | ||
table-column | 此元素会作为一个单元格列显示(类似 | ||
table-cell | 此元素会作为一个表格单元格显示(类似 | 和 | ) |
table-caption | 此元素会作为一个表格标题显示(类似 | ||
inherit | 规定应该从父元素继承 display 属性的值。 |
CSS选择符
id选择器(#myid)
类选择器(.myclassname)
标签选择器(div)
相邻选择器(h1+p)
子选择器(ul>li)
后代选择器(li a)
群组选择器(div,p{})
通配符选择器(*)
属性选择器(a[title=""])
伪类选择器(a:hover{}或者li:nth-child{})
link属于HTML标签,@import是CSS提供的
页面被加载时,link引用的css文件会同时被加载,而@import引用的css文件要等到页面被加载完毕再加载
import只在IE5以上才能识别,link是HTML标签,无兼容问题
link 引入样式的权重大于@import 的引用
display:none;隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢。
visibility:hidden;隐藏对应的元素,但在文档布局中仍保留原来的空间。
opacity:0;内容不可见,占据空间。
rgba()和 opacity 都能实现透明效果,但最大的不同是 opacity 作用于元素,以及元素内的所有内容的透明度;
rgba()只作用于元素的颜色或其背景色(设置 rgba 透明的元素的子元素不会继承透明效果)。
在 CSS 当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。
折叠结果遵循下列计算规则如下
两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
两个外边距一正一负时,折叠结果是两者之和。
清除浮动主要是为了解决父元素因为子元素浮动引起的内部高度为0的问题。
常见清除浮动的方法
额外标签法。在最后浮动元素后加一个标签,设置clear:both;
给父级元素设置高度
给父级元素添加浮动
给父级元素设置overflow属性为hidden或者auto
使用after伪元素清除
.clearfix:after {
/*伪元素是行内元素 正常浏览器清除浮动方法*/
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
.clearfix {
*zoom: 1;
}
使用after和before双伪元素清除
.clearfix:before,.clearfix:after {
content: "";
display: block;
clear: both;
}
.clearfix {
zoom: 1;
}
animation属性类似于transition,他们都是随着时间改变元素的属性值
其主要区别在于:
transition需要触发一个事件才会随着时间改变其CSS属性
animation在不需要触发任何事件的情况下,也可以显式的随时间变化来改变元素CSS属性,达到一种动画的效果
动画不需要事件触发,过渡需要
过渡只有一组(两个:开始-结束) 关键帧,动画可以设置多个。
web后端和前端是怎么连接的?
网站数据处理主要分为三层
在网页上填一个表格然后提交会有以下几种数据传输经过:
①你接触到的是这个网页是属于表示层,这个网页一般由HTML标签结合CSS/JAVASCRIPT来实现的。这时候你要先填入数据。
②然后你按提交触发后台处理机制,这时候数据会传到后台的代码进行处理。这部分代码根据不同网站可以使PHP,JSP,JAVA等。代码根据程序员预设的算法将收到的数据进行处理之后会相应的对数据库进行操作,存储数据等。
③成功操作完数据库之后,业务层的代码会再向表示层也就是显示器端传回一个指令通知你表格填写成功
从前端向后台传递参数方法
一、通过表单传递参数
1.前端部分,在前端jsp页面设置form表单,确定需要传递的参数name让用户输入,
通过点击按钮后submit()提交到后台
2.后台对前端请求的反应,接收数据,处理数据以及返回数据。
二.通过ajax传递参数(有post和get写法)
1.ajax是如何将前端数据传到后台的
type: “POST”,//type是ajax的方法
url : “<%=path%>/resource/usermenus”,//参数url,要把参数传到什么地方
data : {parentid:parentid,parentpath:parentpath},//传递什么数据
success : function(data){//sucess表示,当数据返回成功后要怎么做,返回的数据存储在data
2.后台对前端请求的反应,接收数据
3.前端接收到后端返回的数据进行处理的
a.域名解析
b.发起TCP连接的三次握手
c.建立TCP连接后浏览器发起HTTP请求
d.服务端响应http请求,返回响应报文
e.浏览器页面渲染
f.断开TCP连接
sessionStorage(H5新增)
localStorage(H5新增)
cookie
Cookie
本质上就是浏览器里面存储的一个很小的文本文件。向同一域名下发送请求,都会携带相同的Cookie
,服务器拿到Cookie
进行解析,便能拿到客户端的状态,cookie会在超过设置的有效期之后失效,大小一般为4K,参与服务器通信,携带在请求头中cookie又叫会话跟踪技术,是由web服务器保存在用户浏览器上的小文本文件,它可以记录用户ID、密码、浏览过的网页、停留的时间等信息。当用户再次来到该网站时,网站通过读取cookie,得知用户相关信息,就可以做出相应的动作,如在页面显示欢迎用户标语,或者让用户不用输入ID、密码就直接登录等。如果用户清理了cookie,那么用户曾登录过的网站信息就没有了
优点
缺点
介绍
区别
应用场景
1.因为考虑到每个 HTTP 请求都会带着 Cookie 的信息,比较常用的一个应用场景就是判断用户是否登录。针对登录过的用户,服务器端会在他登录时往 Cookie 中插入一段加密过的唯一辨识单一用户的辨识码,下次只要读取这个值就可以判断当前用户是否登录啦。曾经还使用 Cookie 来保存用户在电商网站的购物车信息,如今有了 localStorage,现在基本更加方便
2.sessionStorage可以用来统计当前页面元素的点击次数
3.localStoragese常用于长期登录(判断用户是否已登录),适合长期保存在本地的数据。sessionStorage:敏感账号一次性登录;
登陆信息用cookie好还是localStorage好
1.建议登陆信息用 cookie。即设置有效期的cookie,因为cookie默认会发送回到后端,这样方便后端读取,而使用localStorage,需要在每次请求的时候,都手动带上这个信息,增加了开发过程中的难度,而且还要手动维护过期时间
2.cookie有时效,而localStorage如果不手动清理则永久保存
3.如果要设置关闭网页/标签就失效,请用SessionStorage,这个类似设置不带有效期的cookie
可以通过window.location.hash
获取hash值
document.write
会重绘整个页面
innerHTML
重绘页面的一部分
一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程,使得多线程程序的并发性高
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大提高了程序的运行效率
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配,这就是进程和线程的重要区别
Babel 是一个通用的多功能 JavaScript 编译器,但与一般编译器不同的是它只是把同种语言的高版本规则转换为低版本规则,而不是输出另一种低级机器可识别的代码,并且在依赖不同的拓展插件下可用于不同形式的静态分析(静态分析:指在不需要执行代码的前提下对代码进行分析以及相应处理的一个过程,主要应用于语法检查、编译、代码高亮、代码转换、优化、压缩等等)
babel 做了什么,和编译器类似,babel 的转译过程也分为三个阶段,这三步具体是:
1.解析 Parse
将代码解析生成抽象语法树( 即AST ),也就是计算机理解我们代码的方式(扩展:一般来说每个 js 引擎都有自己的 AST,比如熟知的 v8,chrome 浏览器会把 js 源码转换为抽象语法树,再进一步转换为字节码或机器代码),而 babel 则是通过 babylon 实现的 。简单来说就是一个对于 JS 代码的一个编译过程,进行了词法分析与语法分析的过程
2.转换 Transform
对于 AST 进行变换一系列的操作,babel 接受得到 AST 并通过 babel-traverse 对其进行遍历,在此过程中进行添加、更新及移除等操作
3.生成 Generate
将变换后的 AST 再转换为 JS 代码, 使用到的模块是 babel-generator。而 babel-core 模块则是将三者结合使得对外提供的API做了一个简化
此外需要注意的是,babel 只是转译新标准引入的语法,比如ES6箭头函数:而新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的 API 等(Proxy、Set 等), 这些事不会转译的,需要引入对应的 polyfill 来解决