CSS篇
垂直居中
方式一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>垂直居中
</title>
</head>
<style>
.wrapper {
overflow: hidden;
width: 1000px;
height: 500px;
background: #999;
}
.center {
width: 18em;
height: 10em;
text-align: center;
background-color: orange;
color: #fff;
margin: 50vh auto;
transform: translateY(-50%);
}
</style>
<body>
<div class="wrapper">
<div class="center">
基于视口的垂直居中
<br />
不要求原生有固定的宽高。
<br />
但是这种居中是在整个页面窗口内居中,不是基于父元素
<br />
</div>
</div>
</body>
</html>
方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>垂直居中
</title>
<style>
.center {
width: 18em;
height: 10em;
position: absolute;
background: orange;
text-align: center;
top: 50%;
left: 50%;
margin-left: -9em;
margin-top: -5em;
}
</style>
</head>
<body>
<div class="center">
要求原生有固定的宽高。
<br />
position: absolute;
<br />
top和left 为 50%;
<br />
margin上为高的一半
<br />
margin左为宽的一半
<br />
</div>
</body>
</html>
方式三
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>垂直居中
</title>
</head>
<style>
.center {
width: 18em;
height: 10em;
text-align: center;
background-color: orange;
color: #fff;
position: absolute;
top: calc(50% - 5em);
left: calc(50% - 9em);
}
</style>
<body>
<div class="center">
要求原生有固定的宽高。
<br/>
position: absolute;
<br/>
top 为 calc(50% 剪 一半高)
left 为 calc(50% 剪 一半宽)
</div>
</body>
</html>
方式四
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>垂直居中
</title>
</head>
<style>
.center {
width: 18em;
height: 10em;
text-align: center;
background-color: orange;
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<body>
<div class="center">
不要求原生有固定的宽高。
<br/>
position: absolute;
<br/>
top和left 为 50%;
<br/>
transform: translate(-50%, -50%);
</div>
</body>
</html>
方式五
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>垂直居中
</title>
</head>
<style>
.wrapper {
width: 1000px;
height: 600px;
background: #999;
display: flex;
}
.center {
width: 18em;
height: 10em;
text-align: center;
background-color: orange;
color: #fff;
margin: auto;
}
</style>
<body>
<div class="wrapper">
<div class="center">
使用flex居中
<br/>
父元素 display: flex;
<br/>
居中块: margin: auto;
</div>
</div>
</body>
</html>
方式六
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>垂直居中
</title>
</head>
<style>
.wrapper {
width: 1000px;
height: 600px;
background: #999;
display: flex;
justify-content: center;
align-items: center;
}
.center {
width: 18em;
height: 10em;
text-align: center;
background-color: orange;
color: #fff;
}
</style>
<body>
<div class="wrapper">
<div class="center">
使用flex居中
<br/>
父元素 display: flex;
<br/>
justify-content: center;
<br/>
align-items: center;
<br/>
</div>
</div>
</body>
</html>
水平居中
方式一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>水平居中
</title>
<style>
.wrapper {
text-align: center;
height: 200px;
background: orange;
}
.center {
display: inline-block;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="center">如果需要居中的元素为常规流中 inline / inline-block 元素,为父元素设置 text-align: center;
</div>
</div>
</body>
</html>
方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>水平元素居中
</title>
</head>
<style>
.wrapper {
width: 100%;
height: 500px;
text-align: center;
}
.center {
width: 500px;
text-align: left;
margin: 0 auto;
background-color: orange;
}
</style>
<body>
<div class="wrapper">
<div class="center">
父元素上设置 text-align: center;
<br />
居中元素上margin 为 auto。
</div>
</div>
</body>
</html>
方式三
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>水平元素居中
</title>
</head>
<style>
.wrapper {
width: 80%;
height: 500px;
background: #888;
position: relative;
}
.center {
width: 500px;
position: absolute;
left: 50%;
margin-left: -250px;
background-color: orange;
}
</style>
<body>
<div class="wrapper">
<div class="center">如果元素positon: absolute; 那么 0)设置父元素postion: relative 1)为元素设置宽度,2)偏移量设置为 50%,3)偏移方向外边距设置为元素宽度一半乘以-1
</div>
</div>
</body>
</html>
方式四
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>水平元素居中
</title>
</head>
<style>
.wrapper {
width: 80%;
height: 500px;
background: #888;
}
.center {
width: 500px;
position: relative;
left: 50%;
margin-left: -250px;
background-color: orange;
}
</style>
<body>
<div class="wrapper">
<div class="center">如果元素positon: relative。 那么 1)为元素设置宽度,2)偏移量设置为 50%,3)偏移方向外边距设置为元素宽度一半乘以-1
</div>
</div>
</body>
</html>
布局
绝对定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>绝对定位
</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
* {
margin: 0;
padding: 0;
}
aside {
position: absolute;
width: 300px;
min-height: 100px;
}
left {
left: 0;
background-color: red;
}
.right {
right: 0;
background-color: blue;
}
.center {
position: absolute;
left: 300px;
right: 300px;
background-color: orange;
}
</style>
</head>
<body>
<aside class="left"></aside>
<aside class="right"></aside>
<main class="center">
<h1>绝对定位解决方案
</h1>
<p>左右区域分别postion:absolute,固定到左右两边
</p>
<p>中间区域postion:absolute;left:300px; right: 300px
</p>
<p>给总的宽度加一个min-width,不然缩小窗口会有毛病
</p>
</main>
</body>
</html>
三栏-表格布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>表格布局
</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
.wrapper {
display: table;
width: 100%;
}
.left,
.main,
.right {
min-height: 100px;
display: table-cell;
}
.left {
width: 100px;
background-color: red;
}
.main {
background-color: orange;
}
.right {
width: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="wrapper">
<aside class="left"></aside>
<main class="main">
<h1>表格布局
</h1>
<p>父元素display:table并且宽度为100%
</p>
<p>每一个子元素display:table-cell
</p>
<p>左右两侧添加宽度,中间不加宽度
</p>
</main>
<aside class="right"></aside>
</div>
</body>
</html>
三栏-浮动方案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>浮动方案
</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.left,
.right,
.main {
height: 200px;
}
.left {
float: left;
width: 100px;
background-color: blue;
}
.main {
background-color: seagreen;
width: 100%;
}
.right {
float: right;
width: 100px;
background-color: red;
}
</style>
</head>
<body>
<aside class="left"></aside>
<aside class="right"></aside>
<main class="center">
<h1>浮动解决方案
</h1>
<p>方法:left和right都写在center前面,并且分别左右浮动
</p>
<p>中间的这个div因为是块级元素,所以在水平方向按照他的包容快自动撑开
</p>
<p>简单,但是中心部分过长下面会溢出,然后文字就会跑到两边去。
</p>
</main>
</body>
</html>
三栏-网格布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>网格布局
</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.wrapper {
display: grid;
width: 100%;
grid-template-columns: 100px 1fr 100px;
}
.left {
background-color: red;
}
.center {
background-color: orange;
}
.right {
background-color: blue;
}
</style>
</head>
<body>
<div class="wrapper">
<aside class="left"></aside>
<main class="center">
<h1>网格布局
</h1>
<p>父元素display:grid
</p>
</main>
<aside class="right"></aside>
</div>
</body>
</html>
三栏-flex布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>flex布局
</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.wrapper {
display: flex;
height: 200px;
}
.left {
width: 100px;
background-color: seagreen;
}
.right {
width: 200px;
background-color: sienna;
}
.main {
flex: 1;
background-color: springgreen;
}
</style>
</head>
<body>
<div class="wrapper">
<aside class="left"></aside>
<main class="main">
<h1>flex布局
</h1>
</main>
<aside class="right"></aside>
</div>
</body>
</html>
圣杯布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>圣杯布局
</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.left {
width: 100px;
background-color: springgreen;
}
.right {
width: 200px;
background-color: steelblue;
}
.main {
width: 100%;
background-color: red;
}
.left,
.right,
.main {
float: left;
position: relative;
height: 200px;
}
.left {
margin-left: -100%;
left: -100px;
}
.container {
padding-left: 100px;
padding-right: 200px;
}
.right {
margin-left: -200px;
right: -200px;
}
</style>
</head>
<body>
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
双飞翼布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>双飞翼布局
</title>
<style>
html,
body {
padding: 0;
margin: 0;
}
.left,
.right,
.main {
min-height: 200px;
}
.left {
width: 200px;
background-color: thistle;
}
.main {
background: #999;
width: 100%;
}
.right {
width: 300px;
background-color: violet;
}
.left,
.right,
.main {
float: left;
}
.main-inner {
margin-left: 200px;
margin-right: 300px;
}
.left {
margin-left: -100%;
}
.right {
margin-left: -300px;
}
</style>
</head>
<body>
<div class="main">
<div class="main-inner">中心区
</div>
</div>
<div class="left">left
</div>
<div class="right">right
</div>
</body>
</html>
JS篇
闭包问题
循环中赋值为引用的问题
for (var i
= 1; i
< 5; i
++) {
setTimeout(function timer() {
console
.log(i
)
}, i
* 1000)
}
解决方法有3种
第一种,使用立即执行函数方式
for (var i
= 1; i
< 5; i
++) {
(function(j
){
setTimeout(function timer() {
console
.log(j
)
}, j
* 1000)
})(i
)
}
第二种,使用ES6的let
for (let i
= 1; i
< 5; i
++) {
setTimeout(function timer() {
console
.log(i
)
}, i
* 1000)
}
第三种,使用setTimeout的第三个参数
for (var i
= 1; i
< 5; i
++) {
setTimeout(function timer(j
) {
console
.log(j
)
}, i
* 1000, i
)
}
计数器
实现一个foo函数 可以这么使用:
a
= foo();
b
= foo();
c
= foo();
foo
.clear();d
= foo();
function myIndex() {
var index
= 1;
function foo(){
return index
++;
}
foo
.clear = function() {
index
= 1;
}
return foo
;
}
var foo
= myIndex();
防抖节流
防抖 debounce
函数防抖就是在函数需要频繁触发的情况下,只有足够的空闲时间,才执行一次。
典型应用
百度搜索框在输入稍有停顿时才更新推荐热词。拖拽
function debounce(handler
, delay
){
delay
= delay
|| 300;
var timer
= null;
return function(){
var _self
= this,
_args
= arguments
;
clearTimeout(timer
);
timer
= setTimeout(function(){
handler
.apply(_self
, _args
);
}, delay
);
}
为啥要记录this
function debounce(handler
, delay
){
delay
= delay
|| 300;
var timer
= null;
return function(){
var _self
= this,
_args
= arguments
;
clearTimeout(timer
);
timer
= setTimeout(function(){
handler
.apply(_self
, _args
);
}, delay
);
}
}
function add(counterName
) {
console
.log(counterName
+ ": " + this.index
++);
}
let counter
= {
index
: 0
}
let db_add
= debounce(add
, 10).bind(counter
)
setInterval(function() {
db_add("someCounter1");
db_add("someCounter2");
db_add("someCounter3");
}, 500)
节流 throttle
一个函数只有在大于执行周期时才执行,周期内调用不执行。好像水滴积攒到一定程度才会触发一次下落一样。
典型应用:
抢券时疯狂点击,既要限制次数,又要保证先点先发出请求窗口调整页面滚动
function throttle(fn
,wait
=300){
var lastTime
= 0
return function(){
var that
= this,args
=arguments
var nowTime
= new Date().getTime()
if((nowTime
-lastTime
)>wait
){
fn
.apply(that
,args
)
lastTime
= nowTime
}
}
}
观察者模式
JS观察者模式
观察者模式:观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。而js中最常见的观察者模式就是事件触发机制。
先来个完整的
class EventEmitter {
constructor () {
this.eventPool
= {
}
}
listen(eventName
, callback
) {
if(this.eventPool
[eventName
]) {
if(this.eventPool
[eventName
].indexOf(callback
) === -1) {
this.eventPool
[eventName
].push(callback
)
}
} else {
this.eventPool
[eventName
] = [callback
]
}
}
trigger(eventName
, ...args
) {
if(this.eventPool
[eventName
]) {
this.eventPool
[eventName
].forEach(cb
=> cb(...args
))
}
}
remove(eventName
, callback
) {
if(this.eventPool
[eventName
]) {
let cbIndex
= this.eventPool
[eventName
].indexOf(callback
)
this.eventPool
[eventName
].splice(cbIndex
, 1)
}
}
once(eventName
, callback
) {
this.listen(eventName
, function _cb(...args
) {
callback(...args
);
this.remove(eventName
, _cb
)
})
}
}
ES5/ES6实现观察者模式(自定义事件) - 简书
先搭架子
要有一个对象,存储着它自己的触发函数。而且这个对象的触发函数可能有很多种,比如一个onclick可能触发多个事件,那么handler的属性应该是一个数组,每个数组的值都是一个函数。
handler
={
type1
:[func1
,func2
...],
type2
:[func3
,func4
...],
...
}
现在这个对象的主体部分已经思考好了,现在就是要它‘动起来’,给它添加各种动作。 一个事件可能有哪些动作呢?
add:添加事件某种类型的函数,remove: 移除某种类型的函数,fire:触发某种类型的函数,once:触发某种类型的函数,然后移除掉这个函数
现在,自定义事件的架子已经搭建好了
eventOb
={
handler
:{
type1
:[func1
,func2
...],
type2
:[func2
,func4
...],
...
},
add
:function(){},
remove
:function(){},
fire
:function(){},
once
:function(){},
}
add
添加一个事件监听,首先传入参数应该是 事件类型type,和触发函数 func,传入的时候检测有没有这个函数,有了就不重复添加。
add
:function (type
,func
) {
if(eventOb
.handleFunc
[type
]){
if(eventOb
.handleFunc
[type
].indexOf(func
)===-1){
eventOb
.handleFunc
[type
].push(func
);
}
}
else{
eventOb
.handleFunc
[type
]=[func
];
}
},
remove
remove有一个潜在的需求,就是如果你的事件不存在,它应该会报错。而这里不会报错,index在func不存在的时候是-1;这时候要报错。
remove
:function (type
,func
) {
try{
let target
= eventOb
.handleFunc
[type
];
let index
= target
.indexOf(func
);
if(index
===-1) throw error
;
target
.splice(index
,1);
}catch (e){
console
.error('别老想搞什么飞机,删除我有的东西!');
}
},
fire
触发一个点击事件肯定是要触发它全部的函数,这里也是一样,所以只需要传入type,然后事件可能不存在,像上面一样处理。
fire
:function (type
,func
) {
try{
let target
= eventOb
.handleFunc
[type
];
let count
= target
.length
;
for (var i
= 0; i
< count
; i
++) {
target
[i
]();
}
}
catch (e){
console
.error('别老想搞什么飞机,触发我有的东西!');
}
},
但会有问题,我只想触发并且删除某个事件怎么办,fire一下就全触发了呀。 所以fire的问题就显现出来了。我们还是要给它一个func,但是可选。
fire
:function (type
,func
) {
try{
let target
= eventOb
.handleFunc
[type
];
if(arguments
.length
===1) {
let count
= target
.length
;
for (var i
= 0; i
< count
; i
++) {
target
[i
]();
}
}else{
let index
=target
.indexOf(func
);
if(index
===-1)throw error
;
func();
}
}catch (e){
console
.error('别老想搞什么飞机,触发我有的东西!');
}
},
once
fire,然后remove
once (event
, callback
) {
this.fire(event
, (...args
) => {
callback(...args
);
this.remove(event
)
})
}
完整代码
class eventObs {
constructor(){
this.handleFunc
={}
}
add(type
,func
){
if(this.handleFunc
[type
]){
if(this.handleFunc
[type
].indexOf(func
)===-1){
this.handleFunc
[type
].push(func
);
}
}else{
this.handleFunc
[type
]=[func
];
}
};
fire(type
,func
){
try{
if(arguments
.length
===1) {
let target
= this.handleFunc
[type
];
let count
= target
.length
;
for (var i
= 0; i
< count
; i
++) {
target
[i
]();
}
}else{
let target
= this.handleFunc
[type
];
let index
=target
.indexOf(func
);
if(index
===-1)throw error
;
func();
}
return true;
}catch (e){
console
.error('别老想搞什么飞机,触发我有的东西!');
return false;
}
};
remove(type
,func
){
try{
let target
= this.handleFunc
[type
];
let index
=target
.indexOf(func
);
if(index
===-1)throw error
;
target
.splice(index
,1);
}catch (e){
console
.error('别老想搞什么飞机,删除我有的东西!');
}
};
once(type
,func
) {
this.fire(type
, func
)
? this.remove(type
, func
)
: null;
}
}
尽早顺序打印Ajax请求
const urlList
= [1, 2, 3, 4, 5]
loadData(urlList
)
function fetchData(url
, succCallback
) {
setTimeout(() => {
succCallback('ok: ' + url
);
}, (Math
.random() * 5 * 1000) >> 0);
}
function loadData(urlList
) {
let resArr
= [],
doneId
= 0
for (let i
= 0; i
< urlList
.length
; i
++) {
fetchData(urlList
[i
], res
=> {
console
.log(`${i+1} is done`)
resArr
[i
] = res
outPutRes(resArr
)
})
}
function outPutRes(resArr
) {
for (let i
= doneId
; i
< resArr
.length
; i
++) {
if (resArr
[i
]) {
console
.log(resArr
[i
]);
doneId
++;
} else {
break;
}
}
}
}
curry
柯里化(英语:Currying),又称为部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数的技术,新函数接受余下参数并返回运算结果。
实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6
add(1, 2)(3) = 10
实现方法: 做一个闭包,返回一个函数,这个函数每次执行会改写闭包里面记录参数的数组。当这个函数判断参数个数够了,就去执行它。
function curry(func
) {
let _args
= []
function _curry(...args
) {
_args
= _args
.concat(args
)
if (_args
.length
>= func
.length
) {
const result
= func(..._args
)
_args
= []
return result
;
}
else {
return _curry
}
}
return _curry
}
function add1(a
, b
, c
) {
return a
+ b
+ c
}
let testAdd
= curry(add1
)
console
.log(testAdd(1)(2)(3))
console
.log(testAdd(1, 2)(3))
console
.log(testAdd(1)(2, 3))
实现一个类型判断函数
判断null判断基础类型使用Object.prototype.toString.call(target)来判断引用类型
注意: 一定是使用call来调用,不然是判断的Object.prototype的类型 之所以要先判断是否为基本类型是因为:虽然Object.prototype.toString.call()能判断出某值是:number/string/boolean,但是其实在包装的时候是把他们先转成了对象然后再判断类型的。 但是JS中包装类型和原始类型还是有差别的,因为对一个包装类型来说,typeof的值是object
function getType(target
) {
if(target
=== null) {
return 'null';
}
const typeOfT
= typeof target
if(typeOfT
!== 'object') {
return typeOfT
;
}
const template
= {
"[object Object]": "object",
"[object Array]" : "array",
"[object Function]": "function",
"[object String]": "object - string",
"[object Number]": "object - number",
"[object Boolean]": "object - boolean"
};
const typeStr
= Object
.prototype
.toString
.call(target
);
return template
[typeStr
];
}
实现一个 sleep 函数
比如 sleep(1000) 意味着等待1000毫秒,可从 Promise、Generator、Async/Await 等角度实现
Promise
const sleep = time
=>{
new Promise((resolve
) => {
setTimeout(resolve
, time
)
})
}
sleep(1000).then(() => {
console
.log(1)
})
Generator
function *sleep(time
) {
yield new Promise(resolve
=> {
setTimeout(resolve
, time
)
})
}
sleep(1000).next().value
.then(() => {
console
.log(1)
})
async
async function sleep(time
, func
) {
await new Promise(resolve
=> setTimeout(resolve
, time
))
return func()
}
sleep(1000, () => {
console
.log(1)
})
ES5
function sleep(callback
,time
) {
if(typeof callback
=== 'function')
setTimeout(callback
,time
)
}
function output(){
console
.log(1);
}
sleep(output
,1000);
异步编程
promise与setTimeout 判断执行顺序
promise和setTimeout都会将事件放入异步队列,但setTimeout即便是写0,也会有4ms的延迟
console
.log('begin');
setTimeout(() => {
console
.log('setTimeout 1');
Promise
.resolve()
.then(() => {
console
.log('promise 1');
setTimeout(() => {
console
.log('setTimeout2');
});
})
.then(() => {
console
.log('promise 2');
});
new Promise(resolve
=> {
console
.log('a');
resolve();
}).then(() => {
console
.log('b');
});
}, 0);
console
.log('end');
答案
begin
end
setTimeout 1
a
promise 1
b
promise 2
setTimeout2
async函数的使用
function repeat(func
, times
, wait
) {
}
const repeatFunc
= repeat(alert
, 4, 3000);
repeatFunc('hellworld');
repeatFunc('worldhello')
我自己的实现,没有成功。这种实现是setTimeout新建了两个,然而只清理了一个。
function repeat(func
, times
, wait
) {
var timer
= null;
var count
= 0;
return function(...args
) {
timer
= setInterval(function() {
func
.apply(null, args
);
count
++;
console
.log('count', count
, "times", times
)
if( count
>= times
) {
clearInterval(timer
);
}
}, wait
);
}
}
const repeatFunc
= repeat(console
.log
, 4, 3000);
repeatFunc('hellworld');
repeatFunc('worldhello');
正确解法:使用 async/await来实现
async function wait(seconds
) {
return new Promise((res
) => {
setTimeout(res
, seconds
);
});
}
function repeat(func
, times
, s
) {
return async function (...args
) {
for (let i
= 0; i
< times
; i
++) {
func
.apply(null, args
);
await wait(s
);
}
};
}
let log
= console
.log
let repeatFunc
= repeat(log
,4,3000)
repeatFunc('HelloWorld')
repeatFunc('WorldHello')
async执行练习
await后面的才是异步的,之前都是同步的
async function async1() {
console
.log('async1 start');
await async2();
console
.log('async1 end');
}
async function async2() {
console
.log('async2');
}
console
.log('script start');
setTimeout(function() {
console
.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve
) {
console
.log('promise1');
resolve();
}).then(function() {
console
.log('promise2');
});
console
.log('script end');
bind、apply实现
自封装bind方法
因为bind的使用方法是 某函数.bind(某对象,…剩余参数)
所以需要在Function.prototype 上进行编程 将传递的参数中的某对象和剩余参数使用apply的方式在一个回调函数中执行即可要在第一层获取到被绑定函数的this,因为要拿到那个函数用apply
Function
.prototype
.myBind = (that
, ...args
) => {
const funcThis
= this;
return function(..._args
) {
return funcThis
.apply(that
, args
.concat(_args
));
}
}
Function
.prototype
.mybind = function(ctx
) {
var _this
= this;
var args
= Array
.prototype
.slice
.call(arguments
, 1);
return function() {
return _this
.apply(ctx
, args
.concat(args
, Array
.prototype
.slice
.call(arguments
)))
}
}
Function
.prototype
.myBind = function (target
){
target
= target
|| window
;
var self
= this;
var args
= [].slice
.call(arguments
, 1);
var temp = function(){};
var F = function() {
var _args
= [].slice
.call(arguments
, 0);
return self
.apply(this instanceof temp ? this: target
, args
.concat(_args
));
}
temp
.prototype
= this.prototype
;
F.prototype
= new temp();
return F;
}
自封装一个apply
首先要先原型上即 Function.prototype上编程需要拿到函数的引用, 在这里是 this让 传入对象.fn = this执行 传入对象.fn(传入参数)返回执行结果
Function
.prototype
.myApply = function(context
) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context
= context
|| window
context
.fn
= this
let result
if (arguments
[1]) {
result
= context
.fn(...arguments
[1])
} else {
result
= context
.fn()
}
delete context
.fn
return result
}
deepclone
const typeMap
= {
'[object Array]': 'array',
'[object Object]': 'object',
'[object Function]': 'function',
'[object Symbol]': 'symbol',
'[object RegExp]': 'regexp'
}
function deepClone(target
, map
= new WeakMap()) {
let cloneTarget
let type
= typeMap
[getType(target
)]
if (type
=== 'symbol') {
return Object(Symbol
.prototype
.valueOf
.call(target
));
} else if (type
=== 'function') {
return cloneFunction(target
)
} else if (type
=== 'object' || type
=== 'array') {
cloneTarget
= getInit(target
)
} else {
return target
}
if (map
.get(target
)) {
return map
.get(target
)
} else {
map
.set(target
, cloneTarget
)
}
for (const key
in target
) {
cloneTarget
[key
] = deepClone(target
[key
], map
)
}
return cloneTarget
function getInit(target
) {
const constructor
= target
.constructor
return new constructor()
}
function getType(target
) {
return Object
.prototype
.toString
.call(target
)
}
function cloneFunction(func
) {
const bodyReg
= /\{([\s\S]*)\}$/;
const paramReg
= /(?<=\().+(?=\)\s+{)/;
const funcString
= func
.toString();
if (func
.prototype
) {
console
.log('普通函数');
const param
= paramReg
.exec(funcString
);
const body
= bodyReg
.exec(funcString
);
console
.log(body
)
if (body
) {
console
.log('匹配到函数体:', body
[0]);
if (param
) {
const paramArr
= param
[0].split(',');
console
.log('匹配到参数:', paramArr
);
return new Function(...paramArr
, body
[0]);
} else {
return new Function(body
[0]);
}
} else {
return null;
}
} else {
return eval(funcString
);
}
}
}
const target
= {
field1
: 1,
field2
: undefined
,
field3
: {
child
: 'child'
},
field4
: [2, 4, 8],
field6
: function (age
, w
) {
console
.log(age
, w
)
},
field7
: Symbol('www')
};
target
.target
= target
;
let t
= deepClone(target
)
console
.log(deepClone(target
))
flat
let arr
= [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]
let result
= []
function flat(arr
) {
for (let i
= 0; i
< arr
.length
; i
++) {
if (Array
.isArray(arr
[i
])) {
flat(arr
[i
])
} else {
result
.push(arr
[i
])
}
}
}
flat(arr
)
console
.log(result
)
jsonp
var jsonp = function (url
, param
, callback
) {
var querystring
= url
.indexOf("?") == -1 ? "?" : "&";
for (var k
in param
) {
querystring
+= k
+ "=" + param
[k
] + '&';
}
var random
= Math
.random().toString().replace(".", "");
var cbval
= "my_jsonp" + random
;
var cb
= "callback=" + cbval
;
querystring
+= cb
;
var script
= document
.createElement("script");
script
.src
= url
+ querystring
;
window
[cbval
] = function (param
) {
callback(param
);
document
.body
.removeChild(script
);
};
document
.body
.appendChild(script
);
}
jsonp(
"https://www.baidu.com", {
aa
: 11
},
function () {
console
.log(param
);
}
);
reduce
reduce
reduce函数第一个参数是累计值,如果有初始值,则total=初始值,cur=arr[0],否则,total=arr[0],cur=arr[1]每次返回的值当做下一次的初始值输入
累加累乘
function Accumulation(...vals
) {
return vals
.reduce((t
, v
) => t
+ v
, 0);
}
function Multiplication(...vals
) {
return vals
.reduce((t
, v
) => t
* v
, 1);
}
Accumulation(1, 2, 3, 4, 5);
Multiplication(1, 2, 3, 4, 5);
权重求和
const scores
= [{
score
: 90,
subject
: "chinese",
weight
: 0.5
},
{
score
: 95,
subject
: "math",
weight
: 0.3
},
{
score
: 85,
subject
: "english",
weight
: 0.2
}
];
const result
= scores
.reduce((total
, cur
) => total
+ cur
.score
* cur
.weight
, 0)
reverse
let arr
= [1, 2, 3, 4, 5]
let result
result
= arr
.reduceRight(function (total
, cur
) {
return total
.concat(cur
)
}, [])
console
.log(result
);
实现map
let arr
= [0, 2, 4, 6]
let result
let map = v
=> v
* 2
result
= arr
.reduce((total
, cur
) => {
return total
.concat(map(cur
))
}, [])
console
.log(result
);
扁平化
let arr
= [0, 1, [2, 3],
[4, 5, [6, 7]],
[8, [9, 10, [11, 12]]]
];
let result
function flat(arr
) {
return arr
.reduce((total
, cur
) => Array
.isArray(cur
) ? total
.concat(flat(cur
)) : total
.concat(cur
), [])
}
console
.log(flat(arr
))
去重
let arr
= [2, 1, 0, 3, 2, 1, 2];
let result
function uniq(arr
) {
return arr
.reduce((total
, cur
) => total
.includes(cur
) ? total
: total
.concat(cur
), [])
}
console
.log(uniq(arr
))
this指向
this指向
面试题目
请分别写出下面题目的答案。
function Foo() {
getName = function() {
console
.log(1);
};
return this;
}
Foo
.getName = function() {
console
.log(2);
};
Foo
.prototype
.getName = function() {
console
.log(3);
};
var getName = function() {
console
.log(4);
};
function getName() {
console
.log(5);
}
Foo
.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
箭头函数中的this 判断
箭头函数里面的this是继承它作用域父级的this, 即声明箭头函数处的this
let a
= {
b
: function() {
console
.log(this)
},
c
: () => {
console
.log(this)
}
}
a
.b()
a
.c()
let d
= a
.b
d()
this判断 下面输出为多少?
var name1
= 1;
function test() {
let name1
= 'kin';
let a
= {
name1
: 'jack',
fn
: () => {
var name1
= 'black'
console
.log(this.name1
)
}
}
return a
;
}
test().fn()
答案: 输出1
因为fn处绑定的是箭头函数,箭头函数并不创建this,它只会从自己的作用域链的上一层继承this。这里它的上一层是test(),非严格模式下test中this值为window。
如果在绑定fn的时候使用了function,那么答案会是 ‘jack’如果第一行的 var 改为了 let,那么答案会是 undefined, 因为let不会挂到window上
最后
行文至此,感谢阅读,如果您喜欢的话,可以帮忙点个like哟~
欢迎转载,但要注明出处哟~
该文章首发自【全栈web之路】,web开发之路,诚邀您携手同行。