tanxin03 / web-knowledge Goto Github PK
View Code? Open in Web Editor NEW前端知识点总结
前端知识点总结
ES6规定,Promise是一个构造函数,用来生成promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise生成实例后,可以用then方法分别制定resolve状态和reject状态的回调函数
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法返回的是一个新的Promise实例(是新的,不是原来的),因此可采用链式写法,即then方法后面再调用另一个then方法
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上面带嘛使用then方法,依次制定了两个回调函数,第一个回调函数执行完成过后,会将返回结果作为参数,传入第二个回调函数。
catch()是.then(null, rejection)或.then(undefined, rejection)的别名,用于制定发生错误时的回调函数
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的promise状态到底是fulfilled还是rejected。这表明,finally方法面的操作,应该与状态无关的,不依赖于promise的执行结果
finally本质上是then方法的特例
promise.all()方法用于将多个Promise实例,包装成一个新的promise实例
const p = Promise.all([p1,p2,p3])
上面代码中,promise.all()方法接受一个数组作为参数,p1、p2、p3都是promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为promise实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每一个成员都是Promise实例
p的状态由p1、p2、p3决定,分成两种情况。
1.只有p1、p2、p3的状态变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
2.只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
allSettled()方法接受一组promise实例作为参数,包装成一个新的promise实例。只有等到所有参数实例都返回结果,不管是fulfilled还是reject,实例才会结束
const promises = [
fetch('/api-1'),
fetch('/api-2'),
fetch('/api-3'),
];
await Promise.allSettled(promises);
removeLoadingIndicator();
上面带嘛对服务器发出三个请求,等到三个请求都结束,不管请求成功还是失败,都会返回
该方法接受一组promise实例作为参数,包装一个新的promise实例返回。只要参数实力有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成reject状态,包装实例就会变成rejected状态
有时需要将现有对象转为Promise对象,promise.resolve()方法就起到这个作用
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
content.onmousemove = throttle(count,1000);
let isAndroid = navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1; let isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //这是必须要写的,用来创建一些设置 function setupWebViewJavascriptBridge(callback) { //Android使用 if (isAndroid) { if (window.WebViewJavascriptBridge) { callback(window.WebViewJavascriptBridge); } else { document.addEventListener( 'WebViewJavascriptBridgeReady', () => { callback(window.WebViewJavascriptBridge); }, false ); } console.log('tag', '安卓'); sessionStorage.phoneType = 'android'; } //iOS使用 if (isiOS) { if (window.WebViewJavascriptBridge) { return callback(window.WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; document.documentElement.appendChild(WVJBIframe); setTimeout(() => { document.documentElement.removeChild(WVJBIframe); }, 0); console.log('tag', 'ios'); sessionStorage.phoneType = 'ios'; } } //注册回调函数,第一次连接时调用 初始化函数(android需要初始化,ios不用) setupWebViewJavascriptBridge((bridge) => { if (isAndroid) { //初始化 bridge.init((message, responseCallback) => { var data = { 'Javascript Responds': 'Wee!' }; responseCallback(data); }); } }); export default { // js调APP方法 (参数分别为:app提供的方法名 传给app的数据 回调) callHandler(name, data, callback) { setupWebViewJavascriptBridge((bridge) => { bridge.callHandler(name, data, callback); }); }, // APP调js方法 (参数分别为:js提供的方法名 回调) registerHandler(name, callback) { setupWebViewJavascriptBridge((bridge) => { bridge.registerHandler(name, (data, responseCallback) => { callback(data, responseCallback); }); }); } }
import Bridge from './config/JSbridge.js' Vue.prototype.$bridge = Bridge
methods:{ #### js调用app方法 sendMsgToAndroid(){ let msg = "传给app的数据" this.$bridge.callHandler('dataToAndroid',msg,(res)=>{ alert('获取app响应数据:'+res) }) } #### app调用js方法 getAPPDate(){ this.$bridge.registerHandler('androiddataToJs', (data, responseCallback) => { alert('app主动调用js方法,传入数据:'+ data) responseCallback(data) }) } }
CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用。
CommonJS模块是运行时加载,ES6模块是编译时输出接口。
CommonJS模块输出的是值的拷贝,也就是说,一但输出一个值,模块内部变化不会影响这个值
// common.js
var count = 1;
var printCount = () =>{
return ++count;
}
module.exports = {
printCount: printCount,
count: count
};
// index.js
let v = require('./common');
console.log(v.count); // 1
console.log(v.printCount()); // 2
console.log(v.count); // 1
common.js里面改变了count,但是输出的结果还是原来的。这是因为count是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动的值。将common里的module.exports改写成
module.exports = {
printCount: printCount,
get count(){
return count
}
};
而在es6中,写法是这样的,利用export和import导入的
// es6.js
export let count = 1;
export function printCount() {
++count;
}
// main1.js
import { count, printCount } from './es6';
console.log(count) // 1
printCount();
console.log(count) // 2
es6模块是动态引入,并且不会缓存,模块里面的便令绑定其所在的模块,而是动态地去加载值,并且不能重新复制
另外还想说一个 export default
let count = 1;
function printCount() {
++count;
}
export default { count, printCount}
// main3.js
import res form './main3.js'
console.log(res.count)
浏览器在加载页面的时候会生成一个render(渲染)树,加载完成后当渲染树中的某一些元素发生了比如形状,尺寸,隐藏,由于元素之间位置的相互关系发生改变,都会使渲染树发生改变,从而需要重新构建渲染树,这叫回流
而当渲染树中的某些元素发生的改变不会影响个元素之间的位置关系,比如color,background等只是改变外观,则不需要重建渲染树,这就叫做重绘。
区别:当发生回流时一定发生了重绘,但是当发生重绘时则不一定发生回流
provide可以是一个对象,也可以是一个函数返回对象,和$data类似
provide:Object | () => Object
inject:Array | { [key: string]: string | Symbol | Object }
provide和inject是vue2.2.0版本新增
provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中
这对选项需要一起使用
作用:允许一个祖先组件向所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终有效。
provide 选项应该是一个对象或者返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 Symbol 作为key,但是旨在原生支持 Symbol 和Reflect.ownKeys 的环境下可工作。
inject选项应该是: 一个字符串数组或者一个对象,对象的key是本地的绑定名,value是可用的注入内容中搜索用的key(字符串或Symbol),或者一个对象,
该对象的:from属性是在可用的注入内容中搜索可用的key(字符串或Symbol)
default属性是降级情况下使用value
###使用场景:
由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject 可以轻松实现跨级访问组件组件的数据
###一种常见的用法是刷新vue组件
// app.vue主要内容
<template>
<div
id="app"
>
<router-view
v-if="isRouterAlive"
/>
</div>
</template>
// 父组件中返回要传给下级的数据
provide(){
return {
reload:this.reload
}
},
methods:{
reload(){
this.isrouterAlive = false;
this.$nextTice(()=>{
this.isrouterAlive = true;
})
}
}
// 子级主要内容
<template>
<div class="hello">
<div>子级的数据</div>
{{message}}
</div>
</template>
<script>
export default {
inject: ['message','reload'],
data () {
return {
}
},
mounted(){
this.reload()
}
}
</script>
##提示:provide和inject绑定并不是可相应的。这是刻意为之的。然后,如果传入了一个可监听的对象,那么其对象的属性还是可响应的。
定义: 保证一个类仅有一个实例,并提供一个访问它的全局访问点
核心: 确保只有一个实例,并提供全局访问
**实现:**假设调用一个方法,多次调用也只能设置一次
function SetManager(name) { this.manager = name; } SetManager.prototype.getName = function() { console.log(this.manager); }; var SingletonSetManager = (function() { var manager = null; return function(name) { if (!manager) { manager = new SetManager(name); } return manager; } })(); SingletonSetManager('a').getName(); // a SingletonSetManager('b').getName(); // a SingletonSetManager('c').getName(); // a
<style> .el-table--border th.gutter:last-of-type { display: block!important; width: 17px!important; } </style>###在app.vue或者index.html中添加以上样式,即可完美解决,其他一些比如:
this.$nextTick(() => { this.$refs.table.doLayout(); //解决表格错位 });### 不能很好解决,用css方式解决最完美
如果我告诉你,get和post本质上没有区别,你信么
get和post是什么,是http协议中两种发送请求方法
http的底层是tcp/ip。所以get和post的底层也是tcp/ip,也就是说,get和post都是tcp/ip连接
get和post能做的事情是一样的,你要个get加上request body,给post加上url参数,在技术上完全是行得通的
那么,那些所谓的标准区别究竟是什么
在我大万维网世界中,还有另外一种通讯角色:运输公司,不同的浏览器(发起http请求)和服务器(接受http请求)都是不同的运输公司。虽然理论上,你可以在车上加很多货物(url中无限加参数)。
但是运输公司可不傻,装货和卸货都是需要成本的,所以要限制单次运输量来控制降低风险,数据量太大对浏览器和服务器都是很大负担。浏览器只会处理自己规定长度的字节,超出部分,恕不处理。
如果你用了get服务,在requrest body中偷偷藏了数据。不同服务器的处理方式也是不同的,有些浏览器会帮你卸货,读取数据,有些则自动忽略,所以get虽然可以带request body,但是不一定能被接收到
** 总体来说,就是get和post本质上并无差别,但是由于http的规定和浏览器、服务器之间的限制,导致他们在应用过程中有一些些去区别 **
简单的说就是:
长的来说就是:
也就是说get只需要汽车跑一趟就把货送到了,而post得跑两趟,第一趟先和服务器打个招呼,“hai 等下我要送一批货过来,记得迎接一下”,然后再回头把货送过去
因为post需要两步。时间上消耗多一点点。看起来get比post更有效,就有团队推荐使用get代替post来优化网站性能,但是这是一个坑,需要谨慎处理。
parent.vue
<template>
<div>
<slot-children>
<p>我是slot</p>
</slot-children>
<div>--------------------</div>
</div>
</template>
childen.vue
<template>
<div>
<slot >我是默认信息1</slot>
<slot >我是默认信息2</slot>
</div>
</template>
<slot :data='data'></slot>
,父组件使用<slot-children>
<template slot-scope="user">
<p>{{user.data}}</p>
</template>
</slot-children>
什么叫具名插槽?
官方说法:其实就是在子组件中定义插槽时,给对应的插槽分别起个名字,方便后边插入父组件将内容根据name来填充对应的内容。
接地气说法:slot加一个name属性命名,父组件中使用 v-slot:[name] 对应皆可
作用域插槽:<slot :自定义name=data中的属性或对象>
<myli :title="val.title">
<template v-slot:footer="message">
<div>{{message.aa}}</div>
</template>
</myli>
//书写组件时
<template>
<li>
<slot name='footer' :aa="title"></slot>
</li>
</template>
function Animal(name){ this.name = name } Animal.color = "black" Animal.prototype.say = function(){ console.log('im'+this.name) } var cat = new Animal("cat") cat.say() cat.name cat.color; Animal.say() Animal.name Animal.color
以上分别打印出什么,如果不看答案,自己独立做出来,那构造函数方面的知识点,就懂了,反之,建议往下看一看
答案 : im cat ; cat; undefined;error is not a function;Animal;black
第一个和第二个很简单,省略
cat.color 为undefine的原因是因为 cat是构造函数Animal实例化出来的,cat本身只有name,原型上有say方法,没有color属性,有的人说Animal.color = ‘black’是定义了属性的,Animal.color是再一个函数对象里面添加的静态属性,不属于原型链上的属性,所以为undefine
Animal.say() Animal是一个方法,该方法内部没有say方法,无法提供链式操作,所以报错
Animal.proto.say=function(){
console.log(333)
}
如果添加以上三行,则Animal.say()会打印出 333
Animal.name name属性为函数本身的表达式名字,则为 name
Animal.color 为添加的静态属性值,为 black
总之一句话 静态方法不能被实例对象调用
var a = 3
function a(){
console.log('fn')
}
console.log(a)
结果为3
// 交换顺序
function a(){
console.log('fn')
}
var a = 3
console.log(a)
结果为3
var a
function a(){
console.log('fn')
}
console.log(a)
结果为 a()
function a(){
console.log('fn')
}
var a
console.log(a)
结果为 a()
在解释什么是BFC之前,我们先来了解一下Box,Formatting Context的概念
Box是CSS布局的对象和基本单位,直观点来说,就是一个页面是由很多个Box组成的。元素的类型和display属性,决定了这个Box的类型。不同类型的Box,会参与不同的Formatting Context (一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看可能有哪些盒子:
Formatting Context 是 W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定其子元素如何定位,以及和其他元素的关系和相互作用。最常见的Formatting context 有Block formatting context(简称BFC) 和Inline foramtting context(简称IFC)
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒和行盒(行盒由一行中所有的内敛元素所组成)都会垂直的沿着其父元素的边框排列。
###BFC的布局规则
<title>防止margin重叠</title>
<style>
*{
margin: 0;
padding: 0;
}
p {
color: #f55;
background: yellow;
width: 200px;
line-height: 100px;
text-align:center;
margin: 30px;
}
</style>
看看我的 margin是多少
看看我的 margin是多少
function test() { let arr = [1, 2, 3] arr.forEach(async item => { const res = await fetch(item) console.log(res) }) console.log('end') } function fetch(x) { return new Promise((resolve, reject) => { resolve(x) }) } test()
为了保证 ‘end’ 最后输出,我们肯定要先等待循环的返回结果因此改成如下代
async function test() { let arr = [1, 2, 3] await arr.forEach(async item => { const res = await fetch(item) console.log(res) }) console.log('end') }
但是这样改之后依然行不通,原因是foreach没有返回值,所以我们必须保证循环能够有返回值,所以要将foreach改成map
async function test() { let arr = [1, 2, 3] await arr.map(async item => { const res = await fetch(item) console.log(res) }) console.log('end') }
结果依然不行,然后我们会发现其实map返回的并不是一个promise对象,而是一个包含promise对象的数组[promise, promise, promise],其中每个promise对象都是循环迭代产生的结果。而await是处理不了数组的,它只能处理promise对象。考虑到这一点我们基本上就差不多知道如何改正了、有两种方法。
第一是将循环改成常规的遍历方式
async function test() { let arr = [1, 2, 3] for(let i in arr){ const res = await fetch(arr[i]) console.log(res) } console.log('end') }
第二种就比较高端了,使用Promise.all(),这是一个专门处理promise数组的方法,当async标记的箭头函数返回一个promise对象时,map方法得到的就是一个promise对象数组,然后我们将这个数组丢给Promise.all()去依次执行,然后只需要使用await去等待执行结果,就能保证后面的end在得到结果后才会被输出,得到最终输出结果1,2,3,end
async function test() { let arr = [1, 2, 3] await Promise.all(arr.map(async item => { const res = await fetch(item) console.log(res) })) console.log('end') }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.