scofield09 / personblog Goto Github PK
View Code? Open in Web Editor NEW个人博客 mysql+nodejs+vue
Home Page: http://小鹿.club:12306
个人博客 mysql+nodejs+vue
Home Page: http://小鹿.club:12306
var gulp = require('gulp');
//压缩HTML
//gulp中插件应用 下载插件-->取到插件-->应用插件
var htmlClean = require('gulp-htmlclean');
//压缩图片插件
var imageMin = require('gulp-imagemin');
//压缩js插件
var uglify = require('gulp-uglify');
//去掉js中调试语句
var debug = require('gulp-strip-debug');
//将less转换为css
var less = require('gulp-less');
//压缩css
var cleanCss = require('gulp-clean-css');
//postcss autoproFix
var postCss = require('gulp-postcss');
var autopreFixer = require('autoprefixer');
//开启服务器
var connect = require('gulp-connect');
//判断当前环境变量
var devMod = process.env.NODE_ENV == 'development';
//export NODE_ENV=development 设置环境变量
console.log(devMod);
var folder = {
src:'src/',
dist:'dist/',
}
gulp.task('html',function(){
var page = gulp.src(folder.src + 'html/*')
.pipe(connect.reload());
if(!devMod){
page.pipe(htmlClean())
}
page.pipe(gulp.dest(folder.dist + 'html/'))
})
gulp.task('image',function(){
gulp.src(folder.src + 'image/*')
//有些图片压缩不了不知道为啥
// .pipe(imageMin())
.pipe(gulp.dest(folder.dist + 'image/'))
})
gulp.task('css',function(){
var page = gulp.src(folder.src + 'css/*')
.pipe(connect.reload())
.pipe(less())
.pipe(postCss([autopreFixer()]));
if(!devMod){
page.pipe(cleanCss())
}
page.pipe(gulp.dest(folder.dist + 'css/'))
})
gulp.task('js',function(){
var page = gulp.src(folder.src + 'js/*')
.pipe(connect.reload())
if(!devMod){
page.pipe(uglify())
.pipe(debug());
}
page.pipe(gulp.dest(folder.dist + 'js/'))
})
gulp.task('server',function(){
connect.server({
port:'8888',
livereload:true,
})
})
//监听文件变化
gulp.task('watch',function(){
gulp.watch(folder.src + 'html/*',['html']);
gulp.watch(folder.src + 'css/*',['css']);
gulp.watch(folder.src + 'js/*',['js']);
})
gulp.task("default",['html','css','js','image','server','watch']);
Unicode 是计算机科学领域里的一项业界标准,包括字符集(包含来自世界各国各地的文字字符)和编
码方案(将每个字符唯一映射到一个二进制编码)。
UTF-8是一种可变长度字符编码方式,以8-bit 为单元,使用1至4个字节为每个字符编码。
UTF-16是一种可变长度字符编码方式,以16-bit 为单元,使用2个或4个字节为每个字符编码。
打个比喻,它们理论和实现的关系:Unicode制定了的理论,UTF-8和UTF-16是具体的实现方案。
而更形象的比喻则是:Unicode相当于中文, UTF-8、 UTF-16等相当于 行书、 楷书、草书等各种书写方式。
转自:https://www.jianshu.com/p/9ed19a6645df
for…in循环会遍历一个object所有的可枚举属性。
for…of只能应用于可迭代对象,即拥有[Symbol.iterator] 属性的collection对象,并不适用于所有的object.
let obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: function () {
let curIndex = 0;
let next = () => {
return {
value: this[curIndex],
done: this.length == ++curIndex,
}
}
return {
next
}
}
};
for (let p of obj) {
console.log(p)
};
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function(prev, next){
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, [])
}
console.log(flatten(arr))
在ES5中,顶层对象的属性和全局变量是等价的,var 命令和 function 命令声明的全局变量,自然也是顶层对象。
var a = 12;
function f(){};
console.log(window.a); // 12
console.log(window.f); // f(){}
但ES6规定,var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性,但 let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
let aa = 1;
const bb = 2;
console.log(window.aa); // undefined
console.log(window.bb); // undefined
怎么获取?在定义变量的块级作用域中就能获取啊,既然不属于顶层对象,那就不加 window(global)呗。
let aa = 1;
const bb = 2;
console.log(aa); // 1
console.log(bb); // 2
Transition有几个主要的属性:
animation属性
当-webkit-animation动画结束时有一个webkitAnimationEnd事件,只要监听这个事件就可以了。
不同浏览器的AnimationEnd写法 (webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend)
来源:https://juejin.im/post/5ad3f1156fb9a028b86e78be#heading-8
由于V8最开始就是为JavaScript在浏览器执行而打造的,不太可能遇到使用大量内存的场景,所以它可以申请的最大内存就没有设置太大,在64位系统下大约为1.4GB,在32位系统下大约为700MB。
在NodeJS环境中,我们可以通过**process.memoryUsage()**来查看内存分配。
rss(resident set size):所有内存占用,包括指令区和堆栈
heapTotal:V8引擎可以分配的最大堆内存,包含下面的 heapUsed
heapUsed:V8引擎已经分配使用的堆内存
external: V8管理C++对象绑定到JavaScript对象上的内存
以上所有内存单位均为字节(Byte)。
如果说想要扩大Node可用的内存空间,可以使用Buffer等堆外内存内存,这里不详细说明了,大家有兴趣可以去看一些资料。
自动垃圾回收有很多算法,由于不同对象的生存周期不同,所以无法只用一种回收策略来解决问题,这样效率会很低。
所以,V8采用了一种代回收的策略,将内存分为两个生代:新生代(new generation)和老生代(old generation)。
新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象,分别对新老生代采用不同的垃圾回收算法来提高效率,对象最开始都会先被分配到新生代(如果新生代内存空间不够,直接分配到老生代),新生代中的对象会在满足某些条件后,被移动到老生代,这个过程也叫晋升,后面我会详细说明。
默认情况下,32位系统新生代内存大小为16MB,老生代内存大小为700MB,64位系统下,新生代内存大小为32MB,老生代内存大小为1.4GB。
新生代平均分成两块相等的内存空间,叫做semispace,每块内存大小8MB(32位)或16MB(64位)。
分配方式
新生代存的都是生存周期短的对象,分配内存也很容易,只保存一个指向内存空间的指针,根据分配对象的大小递增指针就可以了,当存储空间快要满时,就进行一次垃圾回收。
算法
新生代采用Scavenge垃圾回收算法,在算法实现时主要采用Cheney算法。
Cheney算法将内存一分为二,叫做semispace,一块处于使用状态,一块处于闲置状态。
处于使用状态的semispace称为From空间,处于闲置状态的semispace称为To空间。
step2. GC进来判断对象B没有其他引用,可以回收,对象A和C依然为活跃对象
step8. 将活跃对象A、C、E从From空间复制到To空间
通过上面的流程图,我们可以很清楚的看到,进行From和To交换,就是为了让活跃对象始终保持在一块semispace中,另一块semispace始终保持空闲的状态。
Scavenge由于只复制存活的对象,并且对于生命周期短的场景存活对象只占少部分,所以它在时间效率上有优异的体现。Scavenge的缺点是只能使用堆内存的一半,这是由划分空间和复制机制所决定的。
由于Scavenge是典型的牺牲空间换取时间的算法,所以无法大规模的应用到所有的垃圾回收中。但我们可以看到,Scavenge非常适合应用在新生代中,因为新生代中对象的生命周期较短,恰恰适合这个算法。
当一个对象经过多次复制仍然存活时,它就会被认为是生命周期较长的对象。这种较长生命周期的对象随后会被移动到老生代中,采用新的算法进行管理。
对象从新生代移动到老生代的过程叫作晋升。
对象晋升的条件主要有两个:
对象从From空间复制到To空间时,会检查它的内存地址来判断这个对象是否已经经历过一次Scavenge回收。如果已经经历过了,会将该对象从From空间移动到老生代空间中,如果没有,则复制到To空间。总结来说,如果一个对象是第二次经历从From空间复制到To空间,那么这个对象会被移动到老生代中。
当要从From空间复制一个对象到To空间时,如果To空间已经使用了超过25%,则这个对象直接晋升到老生代中。设置25%这个阈值的原因是当这次Scavenge回收完成后,这个To空间会变为From空间,接下来的内存分配将在这个空间中进行。如果占比过高,会影响后续的内存分配。
介绍
在老生代中,存活对象占较大比重,如果继续采用Scavenge算法进行管理,就会存在两个问题:
由于存活对象较多,复制存活对象的效率会很低。
采用Scavenge算法会浪费一半内存,由于老生代所占堆内存远大于新生代,所以浪费会很严重。
所以,V8在老生代中主要采用了Mark-Sweep和Mark-Sweep相结合的方式进行垃圾回收。
Mark-Sweep
Mark-Sweep是标记清除的意思,它分为标记和清除两个阶段。
与Scavenge不同,Mark-Sweep并不会将内存分为两份,所以不存在浪费一半空间的行为。Mark-Sweep在标记阶段遍历堆内存中的所有对象,并标记活着的对象,在随后的清除阶段,只清除没有被标记的对象。
也就是说,Scavenge只复制活着的对象,而Mark-Sweep只清除死了的对象。活对象在新生代中只占较少部分,死对象在老生代中只占较少部分,这就是两种回收方式都能高效处理的原因。
step3. GC进入清除阶段,回收掉死亡的B、D、F对象所占用的内存空间
可以看到,Mark-Sweep最大的问题就是,在进行一次清除回收以后,内存空间会出现不连续的状态。这种内存碎片会对后续的内存分配造成问题。
如果出现需要分配一个大内存的情况,由于剩余的碎片空间不足以完成此次分配,就会提前触发垃圾回收,而这次回收是不必要的。
**Mark-Compact是标记整理的意思,**是在Mark-Sweep的基础上演变而来的。Mark-Compact在标记完存活对象以后,会将活着的对象向内存空间的一端移动,移动完成后,直接清理掉边界外的所有内存。如下图所示:
step1. 老生代中有对象A、B、C、D、E、F(和Mark—Sweep一样)
step2. GC进入标记阶段,将A、C、E标记为存活对象(和Mark—Sweep一样)
step3. GC进入整理阶段,将所有存活对象向内存空间的一侧移动,灰色部分为移动后空出来的空间
step4. GC进入清除阶段,将边界另一侧的内存一次性全部回收
总结
V8的垃圾回收机制分为新生代和老生代。
新生代主要使用Scavenge进行管理,主要实现是Cheney算法,将内存平均分为两块,使用空间叫From,闲置空间叫To,新对象都先分配到From空间中,在空间快要占满时将存活对象复制到To空间中,然后清空From的内存空间,此时,调换From空间和To空间,继续进行内存分配,当满足那两个条件时对象会从新生代晋升到老生代。
老生代主要采用Mark-Sweep和Mark-Compact算法,一个是标记清除,一个是标记整理。两者不同的地方是,Mark-Sweep在垃圾回收后会产生碎片内存,而Mark-Compact在清除前会进行一步整理,将存活对象向一侧移动,随后清空边界的另一侧内存,这样空闲的内存都是连续的,但是带来的问题就是速度会慢一些。在V8中,老生代是Mark-Sweep和Mark-Compact两者共同进行管理的。
转自:https://juejin.im/post/5c23993de51d457b8c1f4ee1
同源策略限制内容有:
但是有三个标签是允许跨域加载资源:
<img src=''>
<link href=XXX>
<script src=XXX>
利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。
*{
padding: 0px;
margin: 0px;
text-decoration: none;
}
#b{
width: 1000px;
height: 400px;
border: 1px solid black;
/* text-align: center; */
margin: 0 auto;
position: relative;
}
input{
width: 200px;
height: 20px;
top: 10px;
position: absolute;
top: 10px;
left: 400px;
}
ul{
width: 200px;
position: absolute;
top: 35px;
left: 400px;
list-style: none;
border: 1px solid black;
display: none;
}
li a{
margin-top: 5px;
color: burlywood;
}
a:hover{
color: #f40;
}
</style>
</head>
<body>
<div id="b">
<input type="text">
<ul></ul>
</div>
<script>
var oul = document.getElementsByTagName('ul')[0];
var oinput = document.getElementsByTagName('input')[0];
oinput.oninput = function () {
var value = this.value;
// console.log(this.value);
var oscript = document.createElement('script');
oscript.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd= ' + value + '&cb=dojson'
document.body.appendChild(oscript);
document.body.removeChild(oscript);
}
function dojson(data) {
// console.log(data);
var s = data.s;
var str = '';
if (s.length > 0) {
s.forEach(function (ele, index) {
str += '<li><a href="https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&ch=&tn=baiduerr&bar=&wd='+ele+'">' + ele + '</a></li>';
})
oul.innerHTML = str;
oul.style.display = 'block';
} else {
oul.style.display = 'none';
}
}
利用jsonp制作的百度搜索框
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
otherWindow.postMessage(message, targetOrigin, [transfer]);
接下来我们看个例子: http://localhost:3000/a.html页面向http://localhost:4000/b.html传递“我爱你”,然后后者传回"我不爱你"。
// a.html
<iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe> //等它加载完触发一个事件
//内嵌在http://localhost:3000/a.html
<script>
function load() {
let frame = document.getElementById('frame')
frame.contentWindow.postMessage('我爱你', 'http://localhost:4000') //发送数据
window.onmessage = function(e) { //接受返回数据
console.log(e.data) //我不爱你
}
}
</script>
// b.html
window.onmessage = function(e) {
console.log(e.data) //我爱你
e.source.postMessage('我不爱你', e.origin)
}
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
我们先来看个例子:本地文件socket.html向localhost:3000发生数据和接受数据
// socket.html
<script>
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('我爱你');//向服务器发送数据
}
socket.onmessage = function (e) {
console.log(e.data);//接收服务器返回的数据
}
</script>
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('我不爱你')
});
})
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
其中a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000
// a.html(http://localhost:3000/b.html)
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
let first = true
// onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
function load() {
if(first){
// 第1次onload(跨域页)成功后,切换到同域代理页面
let iframe = document.getElementById('iframe');
iframe.src = 'http://localhost:3000/b.html';
first = false;
}else{
// 第2次onload(同域b.html页)成功后,读取同域window.name中数据
console.log(iframe.contentWindow.name);
}
}
</script>
b.html为中间代理页,与a.html同域,内容为空。
// c.html(http://localhost:4000/c.html)
<script>
window.name = '我不爱你'
</script>
总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
实现原理: a.html欲与c.html跨域相互通信,通过中间页b.html来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
具体实现步骤:一开始a.html给c.html传一个hash值,然后c.html收到hash值后,再把hash值传递给b.html,最后b.html将结果放到a.html的hash值中。
同样的,a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000
// a.html
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
<script>
window.onhashchange = function () { //检测hash的变化
console.log(location.hash);
}
</script>
// b.html
<script>
window.parent.parent.location.hash = location.hash
//b.html将结果放到a.html的hash值中,b.html可通过parent.parent访问a.html页面
</script>
// c.html
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#idontloveyou';
document.body.appendChild(iframe);
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。 只需要给页面添加 document.domain ='test.com' 表示二级域名都相同就可以实现跨域
实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
我们看个例子:页面a.zf1.cn:3000/a.html获取页面b.zf1.cn:3000/b.html中a的值
// a.html
<body>
helloa
<iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
<script>
document.domain = 'zf1.cn'
function load() {
console.log(frame.contentWindow.a);
}
</script>
</body>
// b.html
<body>
hellob
<script>
document.domain = 'zf1.cn'
var a = 100;
</script>
</body>
来源:http://www.ruanyifeng.com/blog/2016/04/cors.html
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。
_ GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0..._
上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。
3.2 withCredentials 属性
上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。
但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials。
xhr.withCredentials = false;
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
4.1 预检请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
下面是一段浏览器的JavaScript脚本。
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header。
浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。
除了Origin字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
4.2 预检请求的回应
服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
Access-Control-Allow-Origin: *
如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。
XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
服务器回应的其他CORS相关字段如下。
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
(1)Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
(2)Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
(3)Access-Control-Allow-Credentials
该字段与简单请求时的含义相同。
(4)Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
4.3 浏览器的正常请求和回应
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
下面是"预检"请求之后,浏览器的正常CORS请求。
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
上面头信息的Origin字段是浏览器自动添加的。
下面是服务器正常的回应。
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8
上面头信息中,Access-Control-Allow-Origin字段是每次回应都必定包含的。
我们用PUT向后台请求时,属于复杂请求,后台需做如下配置:
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
res.end()
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
console.log(req.headers)
res.end('我不爱你')
})
接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段
// index.html
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response)
//得到响应头,后台需设置Access-Control-Expose-Headers
console.log(xhr.getResponseHeader('name'))
}
}
}
xhr.send()
//server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
//server2.js
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function(req, res, next) {
let origin = req.headers.origin
if (whitList.includes(origin)) {
// 设置哪个源可以访问我
res.setHeader('Access-Control-Allow-Origin', origin)
// 允许携带哪个头访问我
res.setHeader('Access-Control-Allow-Headers', 'name')
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 允许携带cookie
res.setHeader('Access-Control-Allow-Credentials', true)
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// 允许返回的头
res.setHeader('Access-Control-Expose-Headers', 'name')
if (req.method === 'OPTIONS') {
res.end() // OPTIONS请求不做任何处理
}
}
next()
})
app.put('/getData', function(req, res) {
console.log(req.headers)
res.setHeader('name', 'jw') //返回一个响应头,后台需设置
res.end('我不爱你')
})
app.get('/getData', function(req, res) {
console.log(req.headers)
res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)
上述代码由http://localhost:3000/index.html向http://localhost:4000/跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键。
楼主投了两月迎来了第一次面试 不出意外的凉了 问的都很基础 但是面试前只准备难的问题了 难受
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
闭包就是能够读取其他函数内部变量的函数。
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。私有化变量
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
https://segmentfault.com/a/1190000010699788
relative是相对正常文档流的位置进行偏移,原先占据的位置依然存在,也就是说它不会影响后面元素的位置。left表示相对原先位置右边进行偏移,top表示相对原先位置下边进行偏移。当left和right同时存在,仅left有效,当top和bottom同时存在仅top有效。relative的偏移是基于对象的margin左上侧的。
fixed是特殊的absolute,即fixed总是以body为定位对象的,按照浏览器的窗口进行定位。
static: 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
absolute: 生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。元素的位置通过left,top,right以及bottom属性进行规定。
个人觉得文档流的翻译容易误导人,没看过原版的我竟然拿"document flow"去Google……原文是"normal flow",不明白为什么会被翻译成文档流,也有人叫普通流、正常流,指语言文本从左到右,从上到下显示,这是传统HTML文档的文本布局。浮动(float)、绝对定位(absolute)、固定定位(fixed)三种方式定位会脱离文档流。
什么是脱离文档流?
脱离文档流是相对正常文档流而言的。正常文档流就是我们没有用CSS样式去控制的HTML文档结构,你写的界面的顺序就是网页展示的顺序。比如写了5个div元素。正常文档流就是按照依次显示这5个div元素。由于div元素是块元素,因此每个div元素独占一行
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为rejected), 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
then方法可以接受两个回调函数作为参数。
第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
拥有length属性,length-0可隐式转换为number类型,并且不大于Math.pow(2,32)(比如:22.33和'022'都满足条件)
不具有数组所具有的方法
概念
原型链是一种机制,指的是JavaScript每个对象包括原型对象都有一个内置的[[proto]]属性指向创建它的函数对象的原型对象,即prototype属性。
作用
原型链的存在,主要是为了实现对象的继承。
https://segmentfault.com/a/1190000007535316
一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。
因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值。注意到 await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。所以下面这个示例完全可以正确运行
promise + generate 实现的
https://juejin.im/entry/5a45f4816fb9a044fa1a3023
https://juejin.im/post/59f16ffaf265da43085d4108
https://zhuanlan.zhihu.com/p/26536815
currentTarget始终是监听事件者,而target是事件的真正发出者
target发生在事件流的目标阶段,而currentTarget发生在事件流的整个阶段(捕获、目标和冒泡阶段)
三个阶段:
捕获阶段:在事件冒泡的模型中,捕获阶段不会响应任何事件;
目标阶段:目标阶段就是指事件响应到触发事件的最底层元素上;
冒泡阶段:冒泡阶段就是事件的触发响应会从最底层目标一层层地向外到最外层(根节点),事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层
Internet Explorer 8 及更早IE版本:
目标阶段
冒泡阶段
委托的优点:
减少内存消耗
动态绑定事件
DOM事件模型中的事件对象常用属性:
type用于获取事件类型
target获取事件目标
stopPropagation()阻止事件冒泡
preventDefault()阻止事件默认行为
IE事件模型中的事件对象常用属性:
type用于获取事件类型
srcElement获取事件目标
cancelBubble阻止事件冒泡
returnValue阻止事件默认行为
这篇文章不错
https://segmentfault.com/a/1190000005654451
执行顺序:
对于非target节点则先执行捕获在执行冒泡
对于target节点则是先执行先注册的事件,无论冒泡还是捕获
来源:你不知道的js下册 想要详细了解的话,建议读一下
Array(..) 构造器有一个众所周知的陷阱,就是如果只传入一个参数,并且这个参数是数
字的话,那么不会构造一个值为这个数字的单个元素的数组,而是构造一个空数组,其
length 属性为这个数字。这个动作会产生不幸又诡异的“空槽”行为,这是 JavaScript 数
组广为人所诟病的一点。
Array.of(..) 取代了 Array(..) 成为数组的推荐函数形式构造器,因为 Array.of(..) 并有这个特殊的单个数字参数的问题。考虑
var a = Array( 3 );
a.length; // 3
a[0]; // undefined
var b = Array.of( 3 );
b.length; // 1
b[0]; // 3
var c = Array.of( 1, 2, 3 );
c.length; // 3
c; // [1,2,3]
Array.from(..) 检查第一个参数是否为 iterable(参见 3.1 节),如果是的话,就使用迭代来产生值并“复制”进入返回的数组。因为真正的数组有一个这些值之上的迭代器,所以
会自动使用这个迭代器。
而如果你把类数组对象作为第一个参数传给 Array.from(..),它的行为方式和 slice()
(没有参数)或者 apply(..) 是一样的,就是简单地按照数字命名的属性从 0 开始直到
length 值在这些值上循环。
考虑:
var arrLike = {
length: 4,
2: "foo"
};
Array.from( arrLike );
// [ undefined, undefined, "foo", undefined ]
因为位置 0、1 和 3 在 arrLike 上并不存在,所以在这些位置上是 undefined 值。
var a = Array( 4 );
// 4个空槽位!
var b = Array.apply( null, { length: 4 } ); // 4个undefined值
而现在 Array.from(..) 使其简单了很多:
var c = Array.from( { length: 4 } );
// 4个undefined值
注意:像前面代码中的 a 那样使用空槽位数组能在某些数组函数上工作,但是另外
一些会忽略空槽位(比如 map(..) 等)。永远不要故意利用空槽位工作,因为
它几乎肯定会导致程序出现诡异 / 意料之外的行为。
var arrLike = {
length: 4,
2: "foo"
};
Array.from( arrLike, function mapper(val,idx){
if (typeof val == "string") {
return val.toUpperCase();
}
else {
return idx;
}
} );
// [ 0, 1, "FOO", 3 ]
注意:和其他接收回调的数组方法一样,Array.from(..) 接收一个可选的第三个参
数,如果设置了的话,这个参数为作为第二个参数传入的回调指定 this 绑
定。否则,this 将会是 undefined。
Array.from(..) 如何把数组中的空槽位看作值为undefined 的槽位。
这实际上是因为在底层数组迭代器是这样工作的:
var a = [];
a.length = 3;
a[1] = 2;
[...a.values()]; // [undefined,2,undefined]
[...a.keys()]; // [0,1,2]
[...a.entries()]; // [ [0,undefined], [1,2], [2,undefined] ]
概念
原型链是一种机制,指的是JavaScript每个对象包括原型对象都有一个内置的[[proto]]属性指向创建它的函数对象的原型对象,即prototype属性。
作用
原型链的存在,主要是为了实现对象的继承。
在 JavaScript 中,每个 JavaScript 都是一个对象,对象中有些属性外面可以访问,有些不
可以,这些属性仅供 JavaScript 引擎存取,[[scope]]就是其中之一,作用域即[[scope]],
它存储了运行上下文的集合。
作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接。
(执行期上下文为预编译过程中,创建的 AO 对象)
https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
该sessionStorage属性允许您访问Storage当前源的会话对象。sessionStorage类似于localStorage; 唯一的区别是当存储的数据localStorage没有到期时间时,存储的数据在sessionStorage页面会话结束时被清除。只要浏览器处于打开状态,页面会话就会持续,并且会在页面重新加载和恢复后继续存在。在新选项卡或窗口中打开页面将导致使用顶级浏览上下文的值启动新会话,这与会话cookie的工作方式不同。
http://www.w3school.com.cn/tags/tag_meta.asp
元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。
标签位于文档的头部,不包含任何内容。 标签的属性定义了与文档相关联的名称/值对。
HTML 与 XHTML 之间的差异
在 HTML 中, 标签没有结束标签。
在 XHTML 中, 标签必须被正确地关闭。
https://juejin.im/post/5c17ad756fb9a049ff4e0a62#heading-17
CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD CMD解决方案。
AMD规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅。
CMD规范与AMD规范很相似,都用于浏览器编程,依赖就近,延迟执行,可以很容易在Node.js中运行。不过,依赖SPM 打包,模块的加载逻辑偏重
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
函数
class EventEmitter{
constructor(){
this.cache = {}
};
on(type,handle){
this.cache[type]?this.cache[type].push(handle):this.cache[type] = [handle];
};
//可以传多个参数
emit(type,...args){
this.cache[type].forEach(ele=>ele(...args))
};
removeListener(type,handle){
//删除这个handle函数
this.cache[type] = this.cache[type].filter(ele=>ele!==handle);
};
once(type,callback){
//这里必须写一个具名函数
let wrap = (...args)=>{
//emit调用之后销毁
callback(...args);
this.removeListener(type,wrap);
};
//写入on中
this.on(type,wrap);
}
}
测试函数
var oE = new EventEmitter();
function deal1(time) {
console.log('overtime1:' + time);
}
function deal2(time){
console.log('overtime2:' + time);
}
// oE.on('over', deal1);
// oE.on('over', deal2);
// oE.emit('over','2019-4-6');
// oE.removeListener('over',deal1);
// oE.removeListener('over',deal2);
// oE.emit('over','2019-4-5');
oE.once('over', deal1);
oE.emit('over','2019-4-6');
oE.emit('over','2019-4-6');
不想给自己找理由,自己太菜,连续两次面试都挂在一面,有点难受
keep-alive
https://juejin.im/entry/5766c29d6be3ff006a31b84e
cookie 数据存放在客户的浏览器上,session数据放在服务器上
cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗考虑到安全应当使用 session
session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用 COOKIE
单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存20个 cookie。
innerHTML指的是从对象的起始位置到终止位置的全部内容,包括Html标签。
innerText 指的是从起始位置到终止位置的内容,但它去除Html标签。
同时,innerHTML 是所有浏览器都支持的,innerText 是IE浏览器和chrome 浏览器支持的,Firefox浏览器不支持。其实,innerHTML 是W3C 组织规定的属性;而innerText 属性是IE浏览器自己的属性,不过后来的浏览器部分实现这个属性罢了
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
我回答了vh vw rem 感觉不是他想要的答案,现在才想起来还有百分比
https://imweb.io/topic/5b8f6a1580495bb24c9217ac
(1)普通钟表相当于圆,其时针或分针走一圈均相当于走过360°角;
(2)钟表上的每一个大格(时针的一小时或分针的5分钟)对应的角度是:360°/12=30°;
(3)时针每走过1分钟对应的角度应为:360°/12*60=0.5°;
(4)分针每走过1分钟对应的角度应为:360°/60=6°。
类如:7:15时针与分针的差值
时针:730+150.5 = 217.5°
分针:15*6 = 90°
差值为127.5°
总结:大的值减去小的值就行
第一步:25个人分成5组,每组5人,分别比赛,得出每组的第一名,并对第一名进行排序,为A1, B1, C1, D1, E1;
第二步:,A1, B1, C1, D1, E1进行一次比赛,得出第一名,假设为A1,此时经过6轮比赛,得出第一名;
第三步: 找第二名第三名;首先第一步中D1, E1排除,同时排除对应组所有成员;剩A1, B1, C1三组
第四步: 第二名可能人员是A2,B1; 第三名可能人员是A2,A3, B1,B2, C1
第五部: 综合第四步猜猜,A2,A3, B1,B2, C1进行一轮比赛,得出第二名第三名,此时总共经过7轮比赛;
来源:你不知道的js
如果你的 JavaScript 经验丰富的话,应该会了解对象是创建无序键 / 值对数据结构 [ 也称为
映射(map)] 的主要机制。但是,对象作为映射的主要缺点是不能使用非字符串值作为键
map 的本质是允许你把某些额外的信息(值)关联到一个对象(键)上,而无需把这个信
息放入对象本身。
对于 map 来说,尽管可以使用任意类型的值作为键,但通常我们会使用对象,因为字符串
或者其他基本类型已经可以作为普通对象的键使用。换句话说,除非某些或者全部键需要
是对象,否则可以继续使用普通对象作为影射,这种情况下 map 才更加合适。
new Map()构造函数:创建Map集合
set()方法:往集合中添加新元素[键值对]
size属性:集合元素个
get()方法:从集合中获取某个键对应的值
has()方法:判断集合中是否存在某键的元素
delete()方法:从集合中删除某键的元素
clear()方法:清空集合元素
forEach()方法:遍历集合元素
如果使用对象作为映射的键,这个对象后来被丢弃(所有的引用解除),试
图让垃圾回收(GC)回收其内存,那么 map 本身仍会保持其项目。你需要
从 map 中移除这个项目来支持 GC。
WeakMap 是 map 的变体,二者的多数外部行为特性都是一样的,区别在于内部内存分配
(特别是其 GC)的工作方式。
WeakMap(只)接受对象作为键。这些对象是被弱持有的,也就是说如果对象本身被垃圾
回收的话,在 WeakMap 中的这个项目也会被移除。然而我们无法观测到这一点,因为对
象被垃圾回收的唯一方式是没有对它的引用了。但是一旦不再有引用,你也就没有对象引
用来查看它是否还存在于这个 WeakMap 中了。
WeakMap 没有 size 属性或 clear() 方法,也不会暴露任何键、值或项目上的迭代器。所
以即使你解除了对 x 的引用,它将会因 GC 时这个条目被从 m 中移除,也没有办法确定这
一事实。所以你就相信 JavaScript 所声明的吧!
和 Map 一样,通过 WeakMap 可以把信息与一个对象软关联起来。而在对这个对象没有完
全控制权的时候,这个功能特别有用,比如 DOM 元素。如果作为映射键的对象可以被删
除,并支持垃圾回收,那么 WeakMap 就更是合适的选择了。
set 是一个值的集合,其中的值唯一(重复会被忽略)。
set 的 API 和 map 类似。只是 add(..) 方法代替了 set(..) 方法(某种程度上说有点讽刺),
没有 get(..) 方法。
// new Set()构造函数:创建Set集合
// add()方法:往集合添加元素
// size属性:集合长度
// has()方法:判断集合内是否包含某元素
// delete()方法:从集合中删除某元素
// clear()方法:清空集合元素
// forEach()方法:遍历集合元素
// 差集
// [1, 2, 4, 5];
// let arr1 = [1, 2, 3, 2, 3,6];
// let arr2 = [3, 2, 4, 4, 5];
// let oS1 = new Set(arr1);
// let oS2 = new Set(arr2);
// let newArr1 = [...oS1].filter(ele =>!oS2.has(ele));
// let newArr2 = [...oS2].filter(ele =>!oS1.has(ele));
// console.log( [...newArr1,...newArr2] );
同理也有weakset
代码的执行顺序可以分为以下几步
1.将函数对象设置为对象的属性
2.执行这个函数
3.删除这个函数
es5的方式
Function.prototype.myCall = function(context){
var context = context||window;
var arg = [];
//把函数绑定到对象上
context.fn = this||window;
for(var i = 1;i<arguments.length;i++){
arg.push(arguments[i]);
}
//数组变成字符串
arg = arg.join(',');
var res = eval('context.fn('+arg+')')
delete context.fn;
return res;
}
es6的方式
Function.prototype.myCall = function(context){
var context = context||window;
context.fn = this||window;
//从1开始截取
let arg = [...arguments].slice(1);
var res = context.fn(...arg);
delete context.fn;
return res;
}
Function.prototype.myApply = function(context){
var context = context||window;
context.fn = this;
//从1开始截取
var res;
if(!arguments){
res = context.fn()
}else{
res = context.fn(...arguments[1])
};
delete context.fn;
return res;
}
Function.prototype.myBind = function(context){
let fn = this;
let args = [...arguments].slice(1);
return function(){
fn.apply(context,args.concat(...arguments))
}
}
在html中通过标签打开一个链接,通过 标签的 target 属性规定在何处打开链接文档。
如果在标签中写入target属性,则浏览器会根据target的属性值去打开与其命名或名称相符的 框架或者窗口.
在target中还存在四个保留的属性值如下,
_blank |在新窗口中打开被链接文档。
_self |默认。在相同的框架中打开被链接文档。
_parent | 在父框架集中打开被链接文档。
_top | 在整个窗口中打开被链接文档。
framename | 在指定的框架中打开被链接文档。
CSS Sprites在国内很多人叫css精灵,是一种网页图片应用处理方式。它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来了。
利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置。
利用CSS Sprites能很好地减少网页的http请求,从而大大的提高页面的性能,这也是CSS Sprites最大的优点,也是其被广泛传播和应用的主要原因;
CSS Sprites能减少图片的字节,曾经比较过多次3张图片合并成1张图片的字节总是小于这3张图片的字节总和。所以C错误
解决了网页设计师在图片命名上的困扰,只需对一张集合的图片上命名就可以了,不需要对每一个小元素进行命名,从而提高了网页的制作效率。
更换风格方便,只需要在一张或少张图片上修改图片的颜色或样式,整个网页的风格就可以改变。维护起来更加方便。
今天在linux上执行git clone 报错(github上的项目 使用https协议)
使用ssh报错的话,应该是没配置公钥
fatal: unable to access 'https://github.com/scofield09/PersonBlog': Peer reports incompatible or unsupported protocol version.
查找原因是curl,nss版本低的原因,解决办法就是更新nss,curl。
yum update nss curl # nss为名称解析和认证服务 curl为网络请求库
curl是一个可以从服务器传输数据或者传输数据到一个服务器的工具,支持以下协议(HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, DICT, TELNET, LDAP or FILE)。该命令被设计而无需用户交互工作。
根据wikipedia中的说明,NSS(Name Service Switch, 名称服务开关)是类unix操作系统中的一种工具,它为通用配置数据库和名称解析机制提供了各种来源。这些源文件包括本地操作系统文件(例如/etc/passwd、/etc/group和/etc/hosts)、域名系统(DNS)、网络信息服务(NIS)和LDAP。
来源:你不知道的的js下册
快速创建全为一个数的数组有用
可以通过 ES6 原生支持的方法 Array#fill(..) 用指定值完全(或部分)填充已存在的数
组:
var a = Array( 4 ).fill( undefined );
a;
// [undefined,undefined,undefined,undefined]
fill(..) 可选地接收参数 start 和 end,它们指定了数组要填充的子集位置,比如:
var a = [ null, null, null, null ].fill( 42, 1, 3 );
a; // [null,42,42,null]
查找数组里面的值
一般来说,在数组中搜索一个值的最常用方法一直是 indexOf(..) 方法,这个方法返回找
到值的索引,如果没有找到就返回 -1:
var a = [1,2,3,4,5];
(a.indexOf( 3 ) != -1); // true
(a.indexOf( 7 ) != -1); // false
(a.indexOf( "2" ) != -1); // false
相比之下,indexOf(..) 需要严格匹配 ===,所以搜索 "2" 不会找到值 2,反之也是如此。
indexOf(..) 的匹配算法无法覆盖,而且要手动与值 -1 进行比较也很麻烦 / 笨拙。
从 ES5 以来,控制匹配逻辑的最常用变通技术是使用 some(..) 方法。它的实现是通过为
每个元素调用一个函数回调,直到某次调用返回 true / 真值时才会停止。因为你可以定义
这个回调函数,也就有了对匹配方式的完全控制:
var a = [1,2,3,4,5];
a.some( function matcher(v){
return v == "2";
} ); // true
a.some( function matcher(v){
return v == 7;
} ); // false
但这种方式的缺点是如果找到匹配的值的时候,只能得到匹配的 true/false 指示,而无得到真正的匹配值本身。
ES6 的 find(..) 解决了这个问题。基本上它和 some(..) 的工作方式一样,除了一旦回调
返回 true/ 真值,会返回实际的数组值:
var a = [1,2,3,4,5];
a.find( function matcher(v){
return v == "2";
} ); // 2
a.find( function matcher(v){
return v == 7; // undefined
});
> 通过自定义 matcher(..) 函数也可以支持比较像对象这样的复杂值:
var points = [
{ x: 10, y: 20 },
{ x: 20, y: 30 },
{ x: 30, y: 40 },
{ x: 40, y: 50 },
{ x: 50, y: 60 }
];
points.find( function matcher(point) {
return (
point.x % 3 == 0 &&
point.y % 4 == 0
);
} ); // { x: 30, y: 40 }
注意:就像其他接受回调的数组方法一样,find(..) 接受一个可选的第二个参
数,如果设定这个参数就绑定到第一个参数回调的 this。否则,this 就undefined。
查找这个数的索引
前面一小节展示了 some(..) 如何 yield 出一个布尔型结果用于在数组中搜索,以及
find(..) 如何从数组搜索 yield 出匹配的值本身,另外,还需要找到匹配值的位置索引。
indexOf(..) 会提供这些,但是无法控制匹配逻辑;它总是使用 === 严格相等。所以 ES6
的 findIndex(..) 才是解决方案:
var points = [
{ x: 10, y: 20 },
{ x: 20, y: 30 },
{ x: 30, y: 40 },
{ x: 40, y: 50 },
{ x: 50, y: 60 }
];
points.findIndex( function matcher(point) {
return (
point.x % 3 == 0 &&
point.y % 4 == 0
);
} ); // 2
points.findIndex( function matcher(point) {
return (
point.x % 6 == 0 &&
point.y % 7 == 0
);
} ); // -1
不要使用 findIndex(..) != -1(这是 indexOf(..) 的惯用法)从搜索中得到布尔值,因
为 some(..) 已经 yield 出你想要的 true/false。也不要用 a[ a.findIndex(..) ] 来得匹配值,因为这是 find(..) 所做的事。最后,如果需要严格匹配的索引值,那么使用
indexOf(..);如果需要自定义匹配的索引值,那么使用 findIndex(..)。
注意:就像其他接收回调的数组方法一样,findIndex(..) 接收一个可选的第二个
参数,如果设定这个参数就绑定到第一个参数回调的 this。否则,this 就undefined。
//比较完美的单例
// var Test = (function(){
// var instance;
// return function(name){
// this.name = name;
// if(typeof instance == 'object'){
// return instance;
// };
// instance = this;
// }
// })()
// var a = new Test(name);
// var b = new Test();
// console.log(a===b)
function getSingal(fun){
var res;
return function(){
//res没有值的时候
if(!res){
//单例核心
res = fun.apply(this,arguments)
}
return res;
}
}
function ajaxFunc(method, url, data, callback, flag) {
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}
method = method.toUpperCase();
if (method == 'GET') {
xhr.open(method, url + '?' + data, flag);
xhr.send();
} else if (method == 'POST') {
xhr.open(method, url, flag);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(data);
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log(0)
// var data = JSON.parse(xhr.responseText);
callback(xhr.responseText);
}
}
}
}
xhr.readyState的值
0 (未初始化) or (请求还未初始化)
1 (正在加载) or (已建立服务器链接)
2 (加载成功) or (请求已接受)
3 (交互) or (正在处理请求)
4 (完成) or (请求已完成并且响应已准备好)
收集自:https://cloud.tencent.com/developer/article/1359550
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function() {},
error: function() {}
})
优缺点
本身是针对MVC的编程,不符合现在前端MVVM的浪潮
基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)
axios({
method: 'GET',
url: url,
})
.then(res => {console.log(res)})
.catch(err => {console.log(err)})
写法有很多种,自行查看文档 , 并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// Both requests are now complete
}));
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF(请求中携带cookie)
提供了一些并发请求的接口(重要,方便了很多的操作)
这个支持防止CSRF其实挺好玩的,是怎么做到的呢,就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
为什么要用axios?
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。,它本身具有以下特征:
从浏览器中创建 XMLHttpRequests
从 node.js 创建 http 请求
支持 Promise API
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换 JSON 数据
客户端支持防御 XSRF
函数节流: 指定时间间隔内只会执行一次任务;
函数防抖: 任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
其实函数防抖的原理非常地简单,通过闭包保存一个标记来保存 setTimeout 返回的值,每当用户输入的时候把前一个 setTimeout clear 掉,然后又创建一个新的 setTimeout,这样就能保证函数执行后的 interval 间隔内如果还有触发函数的话,就不会执行 fn 函数了。
function debounce(fn, interval = 300) {
let timeout = null;
return function () {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, interval);
};
}
简单来说,函数的节流就是通过闭包保存一个标记(canRun = true),在函数的开头判断这个标记是否为 true,如果为 true 的话就继续执行函数,否则则 return 掉,判断完标记后立即把这个标记设为 false,然后把外部传入的函数的执行包在一个 setTimeout 中,最后在 setTimeout 执行完毕后再把标记设置为 true(这里很关键),表示可以执行下一次的循环了。当 setTimeout 还未执行的时候,canRun 这个标记始终为 false,在开头的判断中被 return 掉。
function throttle(fn, interval = 300) {
let canRun = true;
return function () {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn.apply(this, arguments);
canRun = true;
}, interval);
};
}
来自点击
四大步骤:
1、创建(或者说构造)一个全新的对象
2、这个新对象会被执行[[Prototype]]连接
3、这个新对象会绑定到函数调用的this
4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
实现:
function myNew(func){
var mythis = {};
mythis.__proto__ = func.prototype;
var res = func.call(mythis);
if (typeof(res) == "object" || typeof(res) == "function"){
return res;
}
return mythis;
}
1.hash
即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比如这个 URL:
http://www.abc.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会
被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
2.history
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
转载自:https://segmentfault.com/q/1010000010340823
https://juejin.im/entry/59225ff8a22b9d005885cb15
Vue.component('my-component', {
template: '<div>OK</div>',
data() {
return {} // 返回一个唯一的对象,不要和其他组件共用一个对象进行返回
},
})
每一个vue组件都是一个vue实例,通过new Vue()实例化,引用同一个对象,如果data直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变。
而data是函数的话,每个vue组件的data都因为函数有了自己的作用域,互不干扰。
一个典型的针对移动端优化的站点包含类似下面的内容:
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
init-scale:设置页面的初始缩放程度
maximum-scale:设置了页面最大缩放程度
minimum-scale:设置了页面最小缩放程度
user-scalable:是否允许用户对页面进行缩放操作
其实,要把当前的viewport宽度设为ideal viewport的宽度,既可以设置width=device-width,也可以设置initial-scale=1,但有一个小缺陷,就是width=device-width会导致iphone、ipad横竖屏不分,initial-scale=1会导致IE横竖屏不分,都以竖屏的ideal viewport宽度为准。所以,最完美的写法两者都写上去, initial-scale=1 解决 iphone、ipad的缺陷,width=device-width解决IE的缺陷。
使用media的三种方法
1.直接在CSS文件中使用:
@media 类型 and (条件1) and (条件二){
css样式
}
@media screen and (max-width:1024px) {
body{
background-color: red;
}
}
2.使用@import导入
@import url("css/moxie.css") screen and (max-width:980px);
3.也是最常用的方法--直接使用link连接,media属性用于设置查询方法
<link rel="stylesheet" type="text/css" href="css/moxie.css" media=“screen and (min-width=980px)”/>
function deep(node){
console.log(node);
if(node.children.length){
for(let i = 0;i<node.children.length;i++){
deep(node.children[i]);
}
}
}
function guangdu(node){
var arr = [];
arr.push(node);
while(arr.length>0){
node = arr.shift();
console.log(node)
if(node.children.length){
for(var i = 0;i<node.children.length;i++){
arr.push(node.children[i])
}
}
}
}
1 .childNodes:(数组)获取元素的所有子节点
2 .firstChild:获取元素的第一个子节点;
3 .lastChild:获取元素的最后一个子节点;
4 .ownerDocument:获取当前文档根节点。在html文档中,为document节点
5 .parentNode:获取当前节点的父节点;
6 .previousSibling:获取当前节点的前一个兄弟节点
7 .nextSibling:获取当前节点的后一个兄弟节点
注:上述属性,均会获得所有的元素节点和文本节点,如果只需要元素节点,需要使用对应Element属
性,例如:firstChild--->firstElementChild 8 .attributes:获取当前元素节点的所有属性节点
长期以来,做牛客春招的编程题,输入输出最让我头疼,我先总结一些
var N;
var main = (N)=>{
if(N<=1)return 1;
var first = 1;
var second = 1;
var third = 0;
for(var i = 2;i<=N;i++){
third = first + second;
first = second;
second = third;
};
return third;
};
//读取单行的输入
while ((N=read_line())!=null) {
let c = main(N);
//执行输出
print(c);
}
1.什么是懒加载
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式。用户滚动到它们之前,可视区域外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。常适用图片很多,页面很长的电商网站场景中。
<style>
body{
height: 1500px;
}
img{
position: absolute;
top: 1000px;
}
</style>
<body>
//把图片地址放在data上
<img src="" data='lu.jpg'>
</body>
<script>
function lazyload(){
var imgs = document.getElementsByTagName('img');
//获取可视区高度
var viewHeight =document.documentElement.clientHeight
for(var i= 0;i<imgs.length;i++){
// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
var x=imgs[i].getBoundingClientRect();
if(x.bottom>=0&&x.top<=viewHeight){
imgs[i].src = imgs[i].getAttribute('data')
};
}
}
document.addEventListener("scroll",lazyload)
</script>
另提一嘴 chrome75将提供loading能过自己执行懒加载(截至2019/4/23/22:30,chrome最高版本是73,貌似快了哈)
该loading属性允许浏览器推迟加载屏幕外图像和iframe,直到用户在它们附近滚动。loading支持三个值:
lazy:是一个很好的懒人加载候选人。
eager:不适合延迟加载。马上加载。
auto:浏览器将确定是否延迟加载。
根本不指定属性将产生与设置相同的影响loading=auto。
<!-- Lazy-load an offscreen image when the user scrolls near it -->
<img src="unicorn.jpg" loading="lazy" alt=".."/>
<!-- Load an image right away instead of lazy-loading -->
<img src="unicorn.jpg" loading="eager" alt=".."/>
<!-- Browser decides whether or not to lazy-load the image -->
<img src="unicorn.jpg" loading="auto" alt=".."/>
<!-- Lazy-load images in <picture>. <img> is the one driving image
loading so <picture> and srcset fall off of that -->
<picture>
<source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x">
<source srcset="small.jpg 1x, small-hd.jpg 2x">
<img src="fallback.jpg" loading="lazy">
</picture>
<!-- Lazy-load an image that has srcset specified -->
<img src="small.jpg"
srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
sizes="(min-width: 36em) 33.3vw, 100vw"
alt="A rad wolf" loading="lazy">
<!-- Lazy-load an offscreen iframe when the user scrolls near it -->
<iframe src="video-player.html" loading="lazy"></iframe>
在网页全部加载之前,对一些主要内容进行加载,以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,直到所有内容加载完毕
预加载我也模糊不清 具体可以看 这篇博客
在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,
这时候就可以使用预加载。
预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,
可以使用以下代码开启预加载
<link rel="preload" href="http://example.com">
预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的
文件延后加载,唯一缺点就是兼容性不好。
两者都是提高页面性能有效的办法,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
来源:你不知道的js下册
静态函数 Object.is(..) 执行比 === 比较更严格的值比较。
Object.is(..) 调用底层 SameValue 算法(ES6 规范,7.2.9 节)。SameValue 算法基本上和
=== 严格相等比较算法一样(ES6 规范,7.2.13 节),但有两个重要的区别。
考虑:
var x = NaN, y = 0, z = -0;
x === x; // false
y === z; // true
Object.is( x, x ); // true
Object.is( y, z ); // false
你应该继续使用 === 进行严格相等比较;不应该把 Object.is(..) 当作这个运算符的替代。
但是,如果需要严格识别 NaN 或者 -0 值,那么应该选择 Object.is(..)。
Symbol 很 可 能 会 成 为 对 象 最 常 用 的 特 殊( 元 ) 属 性。 所 以 引 入 了 工 具 Object.
getOwnPropertySymbols(..),它直接从对象上取得所有的符号属性:
var o = {
foo: 42,
[ Symbol( "bar" ) ]: "hello world",
baz: true
};
Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]
var o1 = {
foo() { console.log( "foo" ); }
};
var o2 = {
// .. o2的定义 ..
};
Object.setPrototypeOf( o2, o1 );
// 委托给o1.foo()
o2.foo(); // foo
也可以:
var o1 = {
foo() { console.log( "foo" ); }
};
var o2 = Object.setPrototypeOf( {
// .. o2的定义 ..
}, o1 );
// 委托给o1.foo()
o2.foo(); // foo
前面两段代码中,o2 和 o1 的关系都出现在 o2 定义的结尾处。更通俗地说,o2 和 o1 的关系
在 o2 的定义上指定,就像类一样,也和字面值对象中的 proto 一样
很多 JavaScript 库 / 框架提供了用于把一个对象的属性复制 / 混合到另一个对象中的工具
(比如,JQuery 的 extent(..))。这些不同的工具之间有各种细微的区别,比如是否忽略值
为 undefined 的属性。
ES6 新增了 Object.assign(..),这是这些算法的简化版本。第一个参数是 target,其他
传入的参数都是源,它们将按照列出的顺序依次被处理。对于每个源来说,它的可枚举
和自己拥有的(也就是不是“继承来的”)键值,包括符号都会通过简单 = 赋值被复制。
Object.assign(..) 返回目标对象。
考虑这个对象设定:
var target = {},
o1 = { a: 1 }, o2 = { b: 2 },
o3 = { c: 3 }, o4 = { d: 4 };
// 设定只读属性
Object.defineProperty( o3, "e", {
value: 5,
enumerable: true,
writable: false,
configurable: false
} );
// 设定不可枚举属性
Object.defineProperty( o3, "f", {
value: 6,
enumerable: false
} );
o3[ Symbol( "g" ) ] = 7;
// 设定不可枚举符号
Object.defineProperty( o3, Symbol( "h" ), {
value: 8,
enumerable: false
} );
Object.setPrototypeOf( o3, o4 );
只有属性 a、b、c、e 以及 Symbol("g") 会被复制到 target 中:
212 | 第 6 章
Object.assign( target, o1, o2, o3 );
target.a; // 1
target.b; // 2
target.c; // 3
Object.getOwnPropertyDescriptor( target, "e" );
// { value: 5, writable: true, enumerable: true,
// configurable: true }
Object.getOwnPropertySymbols( target );
// [Symbol("g")]
复制过程会忽略属性 d、f 和 Symbol("h");不可枚举的属性和非自有的属性都被排除在赋值过程之外。
另外,e 作为一个普通属性赋值被复制,而不是作为只读属性复制。
在前面一节中,我们展示了使用 setPrototypeOf(..) 设定对象 o2 和 o1 之间的 [[Prototype]]
关系。还有另外一种应用了 Object.assign(..) 的形式:
var o1 = {
foo() { console.log( "foo" ); }
};
var o2 = Object.assign(
Object.create( o1 ),
{
// .. o2的定义 ..
}
);
// 委托给o1.foo()
o2.foo(); // foo
var b =10;
var a = 10;
var ll = function b(){
a = 20;
b = 20;
console.log(a,b)
}
ll()
console.log(a,b)
打印出来的
//20 ƒ b(){
a = 20;
b = 20;
console.log(a,b)
}
//20 10
解释:
这种函数的作用域链大概是这样的:
|-函数调用时的变量对象
|-特殊对象 它有一个键名为函数名的属性
……若干上层变量对象
|-全局变量对象
在这种函数内部里,函数名同名的变量是一个特殊对象,只支持DontDelete以及ReadOnly,是无法修改的。
不过,你可以在内部再声明一个同名变量,他会创建在该函数的变量对象中。
var ll = function b(){
a = 20;
b = 20;//赋值不会成功 但不会报错 foo变量挂靠在作用域链上的特殊对象中
console.log(a,b)
}
不过在函数内部'use strict' 就会报错 ‘Assignment to constant variable’报错跟const重复赋值一样
每次期待下一次凑齐参数
function add(a,b,c,d){
return a+b+c+d
}
function curry(fn,arr = []){
return fn.length == arr.length?fn.apply(null,arr):function(...args){
return curry(fn,arr.concat(args));
}
}
var newadd = curry(add);
console.log(newadd(1)(2)(2)(4))
实在搞不懂递归了
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
var letterCombinations = function(digits) {
var res = [];
if(digits == '')return res;
var arr = [' ','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz'];
find(digits,0,'');
function find(digits,index,s){
if(index === digits.length){
res.push(s);
return;
}
var c = digits[index];
var letters = arr[c - '0'];
for(let i = 0;i<letters.length;i++){
find(digits,index+1,s+letters[i]);
}
}
return res;
};
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
var permute = function(nums) {
var res = [];
if(nums.length == 0)return res;
var arr = [...Array(nums.length)].map((ele)=>ele = false);
find(nums,0,p=[])
function find(num,index,p){
if(index===num.length){
//每次创建一个新数组 不然js是浅克隆
var a = [];
for(var j = 0;j<index;j++){
a.push(p[j]);
}
res.push(a);
return;
}
for(var i =0;i<num.length;i++){
if(!arr[i]){
console.log(i+'2')
p.push(num[i]);
arr[i] = true;
find(num,index+1,p);
p.pop();
arr[i] = false;
}
};
return
};
return res;
};
permute([1,2,3])
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:输入: n = 4, k = 2输出:[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],]
var combine = function(n, k) {
var res = [];
find(n,k,1,p=[])
function find(n,k,start,p){
if(p.length == k){
var a = [];
for(var j = 0;j < p.length;j++){
a.push(p[j])
}
res.push(a)
return
};
for(var i = start;i<=n;i++){
console.log(i)
p.push(i);
find(n,k,i+1,p);
console.log('hh')
p.pop();
}
return
}
return res;
};
console.log(combine(4,2))
<style>
.parent {
width: 100%;
height: 200px;
}
.right {
float: right;
background: #00b3ee;
height: inherit;
width: 300px;
}
.left {
height: inherit;
float: left;
background: #eee789;
width: 300px;
}
.center {
height: inherit;
background: #7b007b;
}
</style>
<div class="parent">
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</div>
<style>
.parent {
position: relative;
width: 100%;
height: 200px;
}
.left {
position: absolute;
width: 200px;
background: #007bff;
height: 200px;
}
.center {
position: absolute;
background: #7b007b;
height: 200px;
left: 200px;
right: 200px;
}
.right {
right: 0;
position: absolute;
width: 200px;
background: yellow;
height: 200px;
}
</style>
<div class="parent">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
<style>
.parent > *{
height: 200px;
}
.parent {
width: 100%;
height: 200px;
display: flex;
}
.left {
background: yellow;
width: 300px;
}
.center {
background: #7b007b;
flex: 1;
}
.right {
background: #00aa88;
width: 300px;
}
</style>
<div class="parent">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
https://www.nowcoder.com/discuss/132414
来自:https://juejin.im/post/59e7190bf265da4307025d91#heading-5
1.利用别的元素清楚浮动
clear:both
原理:告诉元素左右两边不能有浮动元素 只能移动到浮动元素下方 父元素高度也被撑起 clear都是这个道理 浮动元素仍然在文档流中,它必须在父元素的边界内,父元素只有增加其高度才能达到此目的
2.父元素添加伪类
.clearfix:after {
content: '.';
height: 0;
//必须块级元素
display: block;
clear: both;
}
该样式在clearfix,即父级元素的最后,添加了一个:after伪类,通过清除伪元素的浮动,达到撑起父元素高度的目的。注意到该伪元素的display值为block,即,它是一个不可见的块级元素(有的地方使用table,因为table也是一个块级元素)。你可能已经意识到,这也只不过是前一种清除浮动方法(添加空白div)的另一种变形,其底层逻辑也是完全一样的
3.利用overflow清除浮动
给父级设置overflow 最好是auto
这里的overflow值,可以是除了"visible"之外的任何有效值,它们都能达到撑起父元素高度,清除浮动的目的。不过,有的值可能会带来副作用,比如,scroll值会导致滚动条始终可见,hidden会使得超出边框部分不可见等。
4.float布局对后续元素的影响
浮动元素脱离文档流,如果后续元素为浮动元素,则依此排列;如果使文本节点,则围绕浮动元素;否则,会被浮动元素覆盖,布局忽略浮动元素。
var obj = {
name:"123",
wife:{
son:"ahsa"
},
han:[1,2,4]
}
function deepClone(origin,target){
var target = target || {};
for(var prop in origin){
//解决原型上属性不遍历
if(origin.hasOwnProperty(prop)){
if(origin[prop]!=="null"&&typeof(origin)=="object"){
if(Object.prototype.toString.call(origin[prop])=="[object Array]"){
target[prop] = [];
}else{
target[prop] = {};
};
//递归调用
deepClone(origin[prop],target[prop]);
}else{
target[prop] = origin[prop];
}
}
};
return target
}
var obj1 = {};
deepClone(obj,obj1)
console.log(obj1)
2.最简单的深克隆方法
let target = JSON.parse(JSON.stringify(obj));
console.log(target)
var obj = {
name:"123",
wife:{
son:"ahsa"
},
han:[1,2,4]
}
Object.prototype.c = 10;
function clone(origin,target){
var target = target || {};
//会遍历原型上属性
for(var prop in origin){
target[prop] = origin[prop];
};
return target;
}
var obj1 = {}
clone(obj,obj1)
console.log(obj1)
2.利用Object.assign()实现浅克隆
非自身属性和不可枚举属性会被排除在外
var obj1 ={}
obj1 = Object.assign(obj1,obj)
obj1.han = [12];
console.log(obj1,obj);
这篇关于Object.assign()的博客不错点击
function bubbleSort(arr){
for(var i= 0;i<arr.length;i++){
for(var j= 0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
var temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
};
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort(arr));
改进之后的
function bubbleSort(arr){
let r = arr.length - 1;
let l = 0;
let temp;
while(l<r){
//正向冒泡 找最大值
for(let i =l;i<r;i++){
if(arr[i]>arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
};
--r;
//反向冒泡 找最小值
for(let j = r;j>l;j--){
if(arr[j]<arr[j-1]){
temp = arr[j];
arr[j] = arr[j - 1];
arr[j -1] = temp;
}
};
l++;
};
return arr;
}
最佳情况:T(n) = O(n)
当输入的数据已经是正序时(都已经是正序了,为毛何必还排序呢....)
最差情况:T(n) = O(n2)
当输入的数据是反序时(卧槽,我直接反序不就完了....)
平均情况:T(n) = O(n2)
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
function selectionSort(arr) {
var min;
for(let i = 0;i<arr.length;i++){
//储存最小值
min = i;
for(let j = 1 + i;j<arr.length;j++){
if(arr[j]<arr[min]){
min = j;
};
};
var temp = arr[i];
arr[i] = arr[min];
arr[min] = temp
};
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));
最佳情况:T(n) = O(n2)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(n2)
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
function insertionSort(arr) {
for(let i =1 ;i<arr.length;i++){
let key = arr[i];
let j = i - 1;
//向前比较
while(j>=0&&arr[j]>key){
arr[j+1] = arr[j];
j--;
};
//实际是j的值 j--会先减去1 所以要再加上去
arr[j+1] = key;
}
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(insertionSort(arr));
最佳情况:输入数组按升序排列。T(n) = O(n)
最坏情况:输入数组按降序排列。T(n) = O(n2)
平均情况:T(n) = O(n2)
快速排序的基本**:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
function quickSort(arr){
if(arr.length<=1)return arr;
var l = [],r = [];
var mid = Math.floor(arr.length/2);
var cur = arr.splice(mid,1);
for(var i = 0;i<arr.length;i++){
if(arr[i]<cur){
l.push(arr[i])
}else[
r.push(arr[i])
]
}
return quickSort(l).concat(cur,quickSort(r))
}
var arr=[3,33,3,3,3,3,4];
console.log(quickSort(arr));
最佳情况:T(n) = O(nlogn)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(nlogn)
希尔排序是插入排序的一种改进算法。它先将一个大的待排序数列分成多个小的分组,并分别对这些小的分组使用插入排序算法。经过多轮分组与组内排序,逐步合并小的分组,最终将分组重新合并成一个有序序列。
function shellSort(arr){
var gar = Math.floor(arr.length/2);
while(gar!==0){
for(var i = gar;i<arr.length;i++){
var temp = arr[i];
//没搞明白为啥像下面这一行写
for(var j = i-gar;j>=0&&arr[j]>temp;j-=gar){
arr[j+gar] = arr[j]
};
//应该是多减去的gar
arr[j+gar] = temp;
};
gar = Math.floor(gar/2);
}
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));
最佳情况:T(n) = O(nlog2 n)
最坏情况:T(n) = O(nlog2 n)
平均情况:T(n) =O(nlog n)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
function mergeSort(arr) {
//出口
if(arr.length<2){
return arr;
}
var mid = Math.floor(arr.length/2),
left = arr.slice(0,mid),
right = arr.slice(mid);
return merge(mergeSort(left),mergeSort(right))
};
function merge(left,right){
var result = [];
while(left.length&&right.length){
left[0] <= right[0]?result.push(left.shift()):result.push(right.shift())
};
while(left.length)result.push(left.shift());
while(right.length)result.push(right.shift());
return result;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(mergeSort(arr));
最佳情况:T(n) = O(n)
最差情况:T(n) = O(nlogn)
平均情况:T(n) = O(nlogn)
[这是我第一次写文章,一定会有所欠缺,还希望大家指正,这个博客对BigInt有详细的讲解,有兴趣的同学可以查看(https://developers.google.com/web/updates/2018/05/bigint)
一.较小的数值
js是二进制浮点数,而二进制浮点数最大的问题(不仅js,所以遵循IEEE 754规范的语言都是如此),会出现0.1+0.2 === 0.3//false,简单来说二进制浮点数会出现精度不准,那么如何来判断0.1+0.2和0.3相不相等呢。
1.最常见的方法是设置一个误差范围值,通常称为“机器精度”,对于js的数字来说,这个值通常是2的-52次方。从ES6开始这个值定义在Number.EPSILON中,我们可以直接拿来用,或者写一个ployfill;
if(!Number.EPSILON){
Number.EPSILON = Math.pow(2,-52);
};
可以使用Number.EPSILON来比较两个数字是不是相等
function numberCloseEnoughToEqual(n1,n2){
return Math.abs(n1-n2)<Number.EPSILON;
}
var a = 0.1+0.2;
var b = 0.3;
numberCloseEnoughToEqual(a,b) //true
2.这个方法就比较笨了。使用toFixed(),需要规定保留几个小数,注意toFixed返回的是字符串
function tofix(a,b,n){
return a.toFixed(n) === b.toFixed(n);
}
var a = 0.1+0.2;
var b = 0.3;
tofix(a,b,1)
二. 整数的安全范围
大家都知道一直到es6可以检验7种类型,而在较高版本的谷歌,可以检验BigInt,BigInt是一个内置对象,它提供了一种表示大于2的53次方的整数的方法,这是JavaScript可以用Number原语可靠地表示的最大数字。
[http://www.ruanyifeng.com/blog/2014/06/git_remote.html]阮一峰这篇文章不错
SVN是集中化的版本控制系统,大家协同工作但是用的是同一个服务器,一旦出了问题所有人都不能提交更新。历史记录存放位置单一,出现问题可能面临版本丢失的问题
Git是分布式存储管理,客户端存的是原始代码的完整镜像,存储到本地,也就是说每一个客户端的代码仓库都是一样的,任何部分代码出现问题,可以使用其他客户端代码进行修复
本地环境配置
git config –global user.name ‘xxx’
git config –global user.email [email protected]
本地分支与远程分支建立关联
git remote add origin yougithub
查看远程仓库
git remote –v
添加源仓库地址为远程仓库
git remote add
克隆仓库
git clone
查看当前文件的状态
git status
提交到暂存区
git add
提交到本地仓库
git commit -m "...”
提交内容到远程仓库
git push
克隆版本库的时候,所使用的远程主机自动被Git命名为origin。如果想用其他的主机名,需要用git clone命令的-o选项指定。
撤销工作区修改
git checkout --
暂存区文件撤销(不覆盖工作区)
git reset HEAD
版本回退
git reset --(soft | mixed | hard) <HEAD~(num )> |
$ git reset --hard HEAD^ 回退到上个版本
$ git reset --hard commit_id 退到/进到 指定commit_id
比较工作区与暂存区
git diff
比较工作区与本地版本库中最近一次commit的内容
git diff HEAD
查看状态
git status
查看日志
git log
查看历史操作记录
git reflog
查看分支
git branch
创建新分支
git branch
切换分支
git checkout
创建并切换分支
git checkout –b
删除本地分支
git branche –d
删除远程分支
git push -d
展示Git命令大纲及常用命令
git help(--help)
展示Git命令大纲及全部命令列表
git help –a
展示具体命令说明手册
git help
添加改动到stash
git stash save -a "messeag”
查看stash列表
git stash list
恢复改动
git stash pop <stash@{id}>
git pull = git fetch + git merge
在git仓库中运行命令:git remote -v
可以看到fetch和push命令可以分别对远程分支进行fetch和push操作,而pull不是直接跟远程分支对话的。
fetch同pull的区别在于:git fetch:是从远程获取最新版本到本地,不会自动merge而git pull是从远程获取最新版本并merge到本地仓库从安全角度出发,git fetch比git pull更安全,因为我们可以先比较本地与远程的区别后,选择性的合并。git push 默认推送到master,如果有多个分支,则多个分支一起推送到远程
楼主今天(2019.4.30)早晨起来的时候,突然一阵头晕目眩,感觉人生已经到达了高潮。想了半天,昨天到底干了什么,怎么今天这么晕,然后就想起了昨天为了改善生活条件喝了一大瓶酸奶,科学上网搜了一下,发现以下知识点:
喝酸奶后头晕,不舒服是因为酸牛奶中含有大量的活性乳酸菌,本来对人体是有益无害的,但是,当
人的胃液酸度PH值在2以下,乳酸菌易被杀死,同时,也破坏了有益菌群体的生长条件,还会影响
正常的消化功能,把包括乳酸菌在内的菌破坏了,所以我们不能正常地好好消化,为了缓解,血
液都往胃流,导致大脑缺氧,头晕乎乎。
得知真相的我,发了一个真香誓言,以后再也不喝酸奶了
正当我考虑要不要自己催吐的时候,我的室友赵志和甩给了我一版药(铝碳酸镁咀嚼片),我当然是选择吃药了。没想到十分钟之后,竟然好了很多,眩晕感没有那么强烈了。然后楼主本着刨根问底的态度,搜了一下原理,得出:
铝碳酸镁(其主要成分的化学式为AlMg(OH)3CO3)与胃酸(其主要成分为盐酸)反应的化学方程式为:
AlMg(OH)3CO3+5HCl═MgCl2+AlCl3+4H2O+CO2↑
该物质中含有Al3+、Mg2+、OH-和CO32-.结合该物质与盐酸反应的化学方程式分析,该药物
起抗酸作用(降低胃液酸性)的微粒是OH-和CO32-;
由此得出结论:喝奶不规范,自己两行泪。
不要空腹喝,而且一次不要喝的太多
我怀疑我买的奶也有问题(商家打暖气储存酸奶)
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
//继承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSuperValue = function(){
return this.property;
}
var instance = new SubType();
console.log(instance.getSuperValue())
引用类型值的原型属性会被所有实例共享,通过原型来实现继承时,原型实际上会变成另一个类型的实例。于是,原来的实例属性也就顺理成章的变成了现在的原型属性了。
function SuperType(){
this.color = ["red","blue","green"];
}
function SubType(){
SuperType.call(this)
}
var instance = new SubType();
instance.color.push("black");
console.log(instance.color);
var instance2 = new SubType()
console.log(instance2.color)
方法都在构造函数里面定义了,无法函数复用,每个子类都有父类实例函数的副本,影响性能
只能继承父类的实例和方法,不能继承原型属性和方法
function SuperType(name){
this.name = name;
this.color = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name)
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
}
组合继承避免了原型链和构造函数的缺陷,融合了优点,成为javascript中最常用的继承模式,而且instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象
缺点:生成了两份实例,
function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name:'Nichiolas',
friends:["Shelby","Court","Van"]
}
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push('Rob');
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push('Barbie');
console.log(person.friends)
就是 ES5 Object.create 的模拟实现,将传入的对象作为创建的对象的原型。
缺点:包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样
注意:修改anotherPerson .name的值,yetAnotherPerson .name的值并未发生改变,并不是因为anotherPerson 和yetAnotherPerson 有独立的 name 值,而是因为anotherPerson .name = 'Greg',给anotherPerson 添加了 name 值,并非修改了原型上的 name 值。
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。无法实现函数复用
function inheritPrototype(SubType,SuperType){
// 使用原型的副本
var prototype = Object.create(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
function SuperType(name){
this.name = name;
};
function SubType(name){
SuperType.call(this,"lu")
this.age = 18;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayName = function(){
console.log(this.name)
}
var a = new SubType();
a.sayName()
这个例子的高效体现在它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的,多余的属性。与此同时,原型链还能保持不变;因此,还能正常使用instanceOf和isPrototypeOf()。开发人员普遍认为寄生组合式继承是引用最理想的继承方式
1.forEach
第二个参数可以绑定this
Array.prototype.myforEach = function(fuc){
var len = this.length;
for (i = 0; i < len; i++) {
var _this = arguments[1]||window;
fuc.apply(_this,[this[i],i,this]);
}
}
2.filter
返回数组
Array.prototype.myFilter = function (func) {
var arr = [];
var len = this.length;
var _this = arguments[1] || window;
for (var i = 0; i < len; i++) {
func.apply(_this, [this[i], i, this]) && arr.push(this[i]);
}
return arr;
}
3.map
映射关系
Array.prototype.myMap = function (func) {
var arr = [];
var len = this.length;
var _this = arguments[1] || window;
for (var i = 0; i < len; i++) {
arr.push(func.call(_this, this[i], i, this));
}
return arr;
}
4.every
目的:判断数组中的元素是否都符合条件 true false 函数 ele index self , this
Array.prototype.myEvery = function (func) {
var flag = true;
var len = this.length;
var _this = arguments[1] || window;
for (var i = 0; i < len; i++) {
if(func.apply(_this, [this[i], i, this]) == false) {
flag = false;
break;
}
}
return flag;
}
5.reduce
Array.prototype.myReduce = function (func, initialValue) {
var len = this.length,
_this = arguments[2] || window,
nextValue = initialValue;
for (var i = 0; i < len; i++) {
nextValue = func.apply(_this, [nextValue, this[i], i, this]);
}
return nextValue;
}
6.春招题 用reduce实现map函数
Array.prototype.myMap = function(callback){
var arr = this;
var _this = arguments[1]||window;
var res = arr.reduce((next,ele,i,self)=>{
next.push(callback.apply(_this,[ele,i,self]));
return next
},[]);
return res;
}
var mySetInterval= function(fn, time) {
// 定义一个递归函数,持续调用定时器
var execute = function(fn, time) {
setTimeout(function(){
fn();
execute(fn, time);
}, time)
}
execute(fn, time);
}
setTimeout 与 requestAnimationFrame 的区别:
createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。
当你想提取文档的一部分,改变,增加,或删除某些内容及插入到文档末尾可以使用createDocumentFragment() 方法。
你也可以使用文档的文档对象来执行这些变化,但要防止文件结构被破坏,createDocumentFragment() 方法可以更安全改变文档的结构及节点。
使用Fragment
var oFrag=document.createDocumentFragment();
for(var i=0;i<1000;i++){
var op=document.createElement("div");
var oText=document.createTextNode(‘i’);
op.appendChild(oText);
oFrag.appendChild(op);
}
document.body.appendChild(oFrag);
// function pp(){
// this.aa = 0
// }
// pp.prototype.a=function(){
// console.log(this)
// }
// var p = new pp();
// var q = p.a;
// q()
这个this指向undefined
主要来源:https://juejin.im/post/5c6cffde6fb9a049d975c8c1#heading-22
webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。它可以很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源。
将所有依赖打包成一个bundle.js,通过代码分割成单元片段按需加载
bundle是webpack打包出来的文件,chunk是webpack在进行模块的依赖分析的时候,代码分割出来的代码块。module是开发中的单个模块
可以用一些官方脚手架
// 首先安装
npm install -g @vue/cli
// 新建项目hello
vue create hello
nuxt-cli
// 确保安装了npx,npx在npm5.2.0默认安装了
// 新建项目hello
npx create-nuxt-app hello
单个页面
module.exports = {
entry: './path/to/my/entry/file.js'
}
### 多页面应用程序
module.entrys = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js'
}
}
var UglifyJSPlugin = require('uglifyjs-webpack-plugin');
var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var providePlugin = new webpack.ProvidePlugin({$: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery'});
module.exports = {
entry: {
index: './src/js/index.js',
goodsInfo: './src/js/goodsInfo.js'
},
output: {
filename: '[name].js',
path: __dirname + '/out',
publicPath: 'http://localhost:8080/out'
},
module: {
rules: [
{test: /.js$/, use: ['babel-loader']},
// // {test: /.css$/, use: ['style-loader','css-loader']},
// {
// test: /.css$/,
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: "css-loader"
// })
// },
{test: /.jpg|png|gif|svg$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},
{test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}
]
},
plugins: [
new UglifyJSPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
filename: "commons.js",
minChunks:2}),
new ExtractTextPlugin("[name].css"),
providePlugin
]
}
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.