Coder Social home page Coder Social logo

personblog's People

Contributors

scofield09 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

personblog's Issues

gulp

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']);

一些小知识点

1.UTF-8 UTF-16 和 Unicode 什么关系

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

2.for...of

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)
        };

3.数组扁平化

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))

4.关于 const 和 let 声明的变量不在 window 上

在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

5.css3中什么时候用transition什么时候用animation实现动画

  • 当有事件触发动画的时候我们就用transition。比如hover事件mouseove、mouseout事件等等
  • 当没有事件触发直接播放的时候我们就用animation。

Transition有几个主要的属性:

  • transition-property
  • transition-duration
  • transition-timing-function
  • transition-delay

animation属性

  • animation-name | 规定需要绑定到选择器的 keyframe 名称。。
  • animation-duration | 规定完成动画所花费的时间,以秒或毫秒计。
  • animation-timing-function | 规定动画的速度曲线。
  • animation-delay | 规定在动画开始之前的延迟。
  • animation-iteration-count | 规定动画应该播放的次数。
  • animation-direction | 规定是否应该轮流反向播放动画。

当-webkit-animation动画结束时有一个webkitAnimationEnd事件,只要监听这个事件就可以了。 

不同浏览器的AnimationEnd写法 (webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend)

V8垃圾回收策略

来源: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位)。

新生代

  1. 分配方式
    新生代存的都是生存周期短的对象,分配内存也很容易,只保存一个指向内存空间的指针,根据分配对象的大小递增指针就可以了,当存储空间快要满时,就进行一次垃圾回收。

  2. 算法
    新生代采用Scavenge垃圾回收算法,在算法实现时主要采用Cheney算法。
    Cheney算法将内存一分为二,叫做semispace,一块处于使用状态,一块处于闲置状态。
    image

处于使用状态的semispace称为From空间,处于闲置状态的semispace称为To空间。

step1. 在From空间中分配了3个对象A、B、C
image

step2. GC进来判断对象B没有其他引用,可以回收,对象A和C依然为活跃对象
image

step3. 将活跃对象A、C从From空间复制到To空间
image

step4. 清空From空间的全部内存
image

step5. 交换From空间和To空间
image

step6. 在From空间中又新增了2个对象D、E
image

step7. 下一轮GC进来发现对象D没有引用了,做标记
image

step8. 将活跃对象A、C、E从From空间复制到To空间
image

step9. 清空From空间全部内存
image

step10. 继续交换From空间和To空间,开始下一轮
image

通过上面的流程图,我们可以很清楚的看到,进行From和To交换,就是为了让活跃对象始终保持在一块semispace中,另一块semispace始终保持空闲的状态。

Scavenge由于只复制存活的对象,并且对于生命周期短的场景存活对象只占少部分,所以它在时间效率上有优异的体现。Scavenge的缺点是只能使用堆内存的一半,这是由划分空间和复制机制所决定的。

由于Scavenge是典型的牺牲空间换取时间的算法,所以无法大规模的应用到所有的垃圾回收中。但我们可以看到,Scavenge非常适合应用在新生代中,因为新生代中对象的生命周期较短,恰恰适合这个算法。

3. 晋升

当一个对象经过多次复制仍然存活时,它就会被认为是生命周期较长的对象。这种较长生命周期的对象随后会被移动到老生代中,采用新的算法进行管理。
对象从新生代移动到老生代的过程叫作晋升。

对象晋升的条件主要有两个:

  • 对象从From空间复制到To空间时,会检查它的内存地址来判断这个对象是否已经经历过一次Scavenge回收。如果已经经历过了,会将该对象从From空间移动到老生代空间中,如果没有,则复制到To空间。总结来说,如果一个对象是第二次经历从From空间复制到To空间,那么这个对象会被移动到老生代中。

  • 当要从From空间复制一个对象到To空间时,如果To空间已经使用了超过25%,则这个对象直接晋升到老生代中。设置25%这个阈值的原因是当这次Scavenge回收完成后,这个To空间会变为From空间,接下来的内存分配将在这个空间中进行。如果占比过高,会影响后续的内存分配。

老生代

  1. 介绍
    在老生代中,存活对象占较大比重,如果继续采用Scavenge算法进行管理,就会存在两个问题:
    由于存活对象较多,复制存活对象的效率会很低。
    采用Scavenge算法会浪费一半内存,由于老生代所占堆内存远大于新生代,所以浪费会很严重。
    所以,V8在老生代中主要采用了Mark-Sweep和Mark-Sweep相结合的方式进行垃圾回收。

  2. Mark-Sweep
    Mark-Sweep是标记清除的意思,它分为标记和清除两个阶段。
    与Scavenge不同,Mark-Sweep并不会将内存分为两份,所以不存在浪费一半空间的行为。Mark-Sweep在标记阶段遍历堆内存中的所有对象,并标记活着的对象,在随后的清除阶段,只清除没有被标记的对象。
    也就是说,Scavenge只复制活着的对象,而Mark-Sweep只清除死了的对象。活对象在新生代中只占较少部分,死对象在老生代中只占较少部分,这就是两种回收方式都能高效处理的原因。

step1. 老生代中有对象A、B、C、D、E、F
image

step2. GC进入标记阶段,将A、C、E标记为存活对象
image

step3. GC进入清除阶段,回收掉死亡的B、D、F对象所占用的内存空间
image

可以看到,Mark-Sweep最大的问题就是,在进行一次清除回收以后,内存空间会出现不连续的状态。这种内存碎片会对后续的内存分配造成问题。
如果出现需要分配一个大内存的情况,由于剩余的碎片空间不足以完成此次分配,就会提前触发垃圾回收,而这次回收是不必要的。

  1. Mark-Compact
    为了解决Mark-Sweep的内存碎片问题,Mark-Compact就被提出来了。

**Mark-Compact是标记整理的意思,**是在Mark-Sweep的基础上演变而来的。Mark-Compact在标记完存活对象以后,会将活着的对象向内存空间的一端移动,移动完成后,直接清理掉边界外的所有内存。如下图所示:

step1. 老生代中有对象A、B、C、D、E、F(和Mark—Sweep一样)
image

step2. GC进入标记阶段,将A、C、E标记为存活对象(和Mark—Sweep一样)
image

step3. GC进入整理阶段,将所有存活对象向内存空间的一侧移动,灰色部分为移动后空出来的空间
image

step4. GC进入清除阶段,将边界另一侧的内存一次性全部回收
image

  1. 两者结合
    在V8的回收策略中,Mark-Sweep和Mark-Conpact两者是结合使用的。
    由于Mark-Conpact需要移动对象,所以它的执行速度不可能很快,在取舍上,V8主要使用Mark-Sweep,在空间不足以对从新生代中晋升过来的对象进行分配时,才使用Mark-Compact

总结
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
同源策略限制内容有:

  1. Cookie、LocalStorage、IndexedDB 等存储性内容
  2. DOM 节点
  3. AJAX 请求发送后,结果被浏览器拦截了
    CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案

但是有三个标签是允许跨域加载资源:

<img src=''>
<link href=XXX>
<script src=XXX>

1.jsonp

利用 <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制作的百度搜索框

2.postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  1. 页面和其打开的新窗口的数据传递
  2. 多窗口之间消息传递
  3. 页面与嵌套的iframe消息传递
  4. 上面三个场景的跨域数据传递
    postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。、

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • message: 将要发送到其他 window的数据。
  • targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
  • transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

接下来我们看个例子: 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)
 }

3.websocket

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('我不爱你')
  });
})

4.window.name + iframe

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从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

5.location.hash + iframe

实现原理: 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);

6.document.domain + 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>

跨域资源共享 CORS 详解

来源: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) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST
    (2)HTTP的头信息不超出以下几种字段:
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

三、简单请求

对于简单请求,浏览器直接发出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),这时一定要小心,不要随便改变父函数内部变量的值。

position

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元素独占一行

flex

http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

promise

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属性。

作用
原型链的存在,主要是为了实现对象的继承。

理解 JavaScript 的 async/await

https://segmentfault.com/a/1190000007535316
一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。

因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值。注意到 await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。所以下面这个示例完全可以正确运行

promise + generate 实现的

generate

https://juejin.im/entry/5a45f4816fb9a044fa1a3023

e.target与e.currentTarget

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节点则是先执行先注册的事件,无论冒泡还是捕获

es6新增的API之Array.of和Array.from(..)

来源:你不知道的js下册 想要详细了解的话,建议读一下

1.Array.of

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(..)

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 值。

  1. 避免空槽位
    前面代码中的 emptySlotArr 和 Array.from(..) 调用的结果有一个微妙但重要的区别。也就
    是 Array.from(..) 永远不会产生空槽位。
    在 ES6 之前,如果你想要产生一个初始化为某个长度,在每个槽位上都是真正的
    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(..) 等)。永远不要故意利用空槽位工作,因为
它几乎肯定会导致程序出现诡异 / 意料之外的行为。

  1. 映射
    Array.from(..) 工具还有另外一个有用的技巧。如果提供了的话,第二个参数是一个映射
    回调(和一般的 Array#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 对象)

H5

如果关闭一个标签页 它的sessionStorage还有吗 那它什么时候清除

https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
该sessionStorage属性允许您访问Storage当前源的会话对象。sessionStorage类似于localStorage; 唯一的区别是当存储的数据localStorage没有到期时间时,存储的数据在sessionStorage页面会话结束时被清除。只要浏览器处于打开状态,页面会话就会持续,并且会在页面重新加载和恢复后继续存在。在新选项卡或窗口中打开页面将导致使用顶级浏览上下文的值启动新会话,这与会话cookie的工作方式不同。

html中的meta标签是用***什么的

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 规范,成为浏览器和服务器通用的模块解决方案。

简单实现一个EventEmitter类

函数

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

cookie和session区别

https://juejin.im/entry/5766c29d6be3ff006a31b84e
cookie 数据存放在客户的浏览器上,session数据放在服务器上
cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗考虑到安全应当使用 session
session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用 COOKIE
单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存20个 cookie。

computed和data区别

innerHTML和innerText有什么区别

innerHTML指的是从对象的起始位置到终止位置的全部内容,包括Html标签。
innerText 指的是从起始位置到终止位置的内容,但它去除Html标签。
同时,innerHTML 是所有浏览器都支持的,innerText 是IE浏览器和chrome 浏览器支持的,Firefox浏览器不支持。其实,innerHTML 是W3C 组织规定的属性;而innerText 属性是IE浏览器自己的属性,不过后来的浏览器部分实现这个属性罢了

axios如何取消请求

ohhoney1/notes#3

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

使用requestAnimationFrame的好处

  1. requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
  2. 在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的 CPU、GPU 和内存使用量
  3. requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了 CPU 开销

audio

http://www.lucklnk.com/godaddy/details/aid/790350379

面试智力题

时针分针问题

(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个人一个跑道,最少经过几次比赛,得到前三名

第一步: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轮比赛;

Map与Set

来源:你不知道的js

Map

如果你的 JavaScript 经验丰富的话,应该会了解对象是创建无序键 / 值对数据结构 [ 也称为
映射(map)] 的主要机制。但是,对象作为映射的主要缺点是不能使用非字符串值作为键
map 的本质是允许你把某些额外的信息(值)关联到一个对象(键)上,而无需把这个信
息放入对象本身。
对于 map 来说,尽管可以使用任意类型的值作为键,但通常我们会使用对象,因为字符串
或者其他基本类型已经可以作为普通对象的键使用。换句话说,除非某些或者全部键需要
是对象,否则可以继续使用普通对象作为影射,这种情况下 map 才更加合适。

new Map()构造函数:创建Map集合
        set()方法:往集合中添加新元素[键值对]
        size属性:集合元素个
        get()方法:从集合中获取某个键对应的值
        has()方法:判断集合中是否存在某键的元素
        delete()方法:从集合中删除某键的元素
        clear()方法:清空集合元素
        forEach()方法:遍历集合元素

如果使用对象作为映射的键,这个对象后来被丢弃(所有的引用解除),试
图让垃圾回收(GC)回收其内存,那么 map 本身仍会保持其项目。你需要
从 map 中移除这个项目来支持 GC。

WeakMap

WeakMap 是 map 的变体,二者的多数外部行为特性都是一样的,区别在于内部内存分配
(特别是其 GC)的工作方式。
WeakMap(只)接受对象作为键。这些对象是被弱持有的,也就是说如果对象本身被垃圾
回收的话,在 WeakMap 中的这个项目也会被移除。然而我们无法观测到这一点,因为对
象被垃圾回收的唯一方式是没有对它的引用了。但是一旦不再有引用,你也就没有对象引
用来查看它是否还存在于这个 WeakMap 中了。
WeakMap 没有 size 属性或 clear() 方法,也不会暴露任何键、值或项目上的迭代器。所
以即使你解除了对 x 的引用,它将会因 GC 时这个条目被从 m 中移除,也没有办法确定这
一事实。所以你就相信 JavaScript 所声明的吧!
和 Map 一样,通过 WeakMap 可以把信息与一个对象软关联起来。而在对这个对象没有完
全控制权的时候,这个功能特别有用,比如 DOM 元素。如果作为映射键的对象可以被删
除,并支持垃圾回收,那么 WeakMap 就更是合适的选择了。

Set

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

实现call,apply,bind

1. call

代码的执行顺序可以分为以下几步
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;
}

2.apply

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;
}

3. bind

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错误
解决了网页设计师在图片命名上的困扰,只需对一张集合的图片上命名就可以了,不需要对每一个小元素进行命名,从而提高了网页的制作效率。
更换风格方便,只需要在一张或少张图片上修改图片的颜色或样式,整个网页的风格就可以改变。维护起来更加方便。

git clone 报错:Peer reports incompatible or unsupported protocol version解决办法

今天在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。

es6新增的API之数组原型方法 fill(..) , find(..), findIndex(..)

来源:你不知道的的js下册

原型方法 fill(..)

快速创建全为一个数的数组有用

可以通过 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]

原型方法 find(..)

查找数组里面的值

一般来说,在数组中搜索一个值的最常用方法一直是 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。

原型方法 findIndex(..)

查找这个数的索引

前面一小节展示了 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;
            }
        }

封装一个Ajax函数

  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 (请求已完成并且响应已准备好)

ajax和axios的优缺点以及比较

收集自:https://cloud.tencent.com/developer/article/1359550

jquery ajax

$.ajax({
    type: 'POST',
    url: url,
    data: data,
    dataType: dataType,
    success: function() {},
    error: function() {}
})

优缺点

本身是针对MVC的编程,不符合现在前端MVVM的浪潮
基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)

axios

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);
    };
}

来自点击

new操作符都做了什么

四大步骤:
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;
}

vue相关问题

vue-router的两种模式的区别

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

Vue 组件 data 为什么必须是函数?

https://juejin.im/entry/59225ff8a22b9d005885cb15

Vue.component('my-component', {
  template: '<div>OK</div>',
  data() {
    return {} // 返回一个唯一的对象,不要和其他组件共用一个对象进行返回
  },
})

每一个vue组件都是一个vue实例,通过new Vue()实例化,引用同一个对象,如果data直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变。

而data是函数的话,每个vue组件的data都因为函数有了自己的作用域,互不干扰。

vue双向数据绑定原理及实现

https://juejin.im/entry/5923973da22b9d005893805a

响应式

1.设置 Meta 标签

一个典型的针对移动端优化的站点包含类似下面的内容:
<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的缺陷。

2.通过媒介查询来设置样式 Media

使用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)”/>

DOM树的深度遍历和广度遍历

深度遍历,本质递归

 function deep(node){
    console.log(node);
    if(node.children.length){
        for(let i = 0;i<node.children.length;i++){
            deep(node.children[i]);
        }
    }
}

广度遍历,本质数组加while

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:获取当前元素节点的所有属性节点

赛码网js(V8)输入输出的问题-斐波那契数列

长期以来,做牛客春招的编程题,输入输出最让我头疼,我先总结一些

赛码网的

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">
预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的
文件延后加载,唯一缺点就是兼容性不好。

懒加载和预加载的对比

两者都是提高页面性能有效的办法,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

es6新增的API之Object

来源:你不知道的js下册

静态函数 Object.is(..)

静态函数 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(..)。

静态函数 Object.getOwnPropertySymbols(..)

Symbol 很 可 能 会 成 为 对 象 最 常 用 的 特 殊( 元 ) 属 性。 所 以 引 入 了 工 具 Object.
getOwnPropertySymbols(..),它直接从对象上取得所有的符号属性:

var o = { 
  foo: 42, 
  [ Symbol( "bar" ) ]: "hello world", 
  baz: true 
}; 
Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]

静态函数 Object.setPrototypeOf(..)

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 一样

静态函数 Object.assign(..)

很多 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))

三栏布局和垂直居中及清楚浮动的原理

1.浮动布局

    <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>

2. 绝对定位实现

  <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>

3. flex布局

    <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布局对后续元素的影响
浮动元素脱离文档流,如果后续元素为浮动元素,则依此排列;如果使文本节点,则围绕浮动元素;否则,会被浮动元素覆盖,布局忽略浮动元素。

垂直居中

https://juejin.im/post/5bc3eb8bf265da0a8a6ad1ce#heading-27

浅克隆与深克隆

深克隆

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()的博客不错点击

js十大经典排序

1.冒泡排序

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)

2.选择排序

选择排序(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)

3.插入排序

插入排序(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)

4.快排

快速排序的基本**:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

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)

5.希尔排序

希尔排序是插入排序的一种改进算法。它先将一个大的待排序数列分成多个小的分组,并分别对这些小的分组使用插入排序算法。经过多轮分组与组内排序,逐步合并小的分组,最终将分组重新合并成一个有序序列。

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)

6.归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(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)

js精度不准的解决方案

[这是我第一次写文章,一定会有所欠缺,还希望大家指正,这个博客对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原语可靠地表示的最大数字。

git

[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

image

image

查看远程仓库
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

image

比较工作区与暂存区
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()。开发人员普遍认为寄生组合式继承是引用最理想的继承方式

数组方法的es5实现

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;
}

用setTimeout简单实现一个setInterval&&requestAnimationFrame与setTimeout的区别

var mySetInterval= function(fn, time) {
// 定义一个递归函数,持续调用定时器
  var execute = function(fn, time) {
     setTimeout(function(){
        fn();
        execute(fn, time);
     }, time)
   }
  execute(fn, time);
}

setTimeout 与 requestAnimationFrame 的区别:

  • 引擎层面:setTimeout 属于 JS 引擎,存在事件轮询,存在事件队列。
    requestAnimationFrame 属于 GUI 引擎,发生在渲
    染过程的中重绘重排部分,与电脑分辨路保持一致。
  • 性能层面:当页面被隐藏或最小化时,定时器 setTimeout 仍在后台执行动画任
    务。
    当页面处于未激活的状态下,该页面的屏幕刷新任
    务会被系统暂停,requestAnimationFrame 也会停止。
  • 应用层面:利用 setTimeout,这种定时机制去做动画,模拟固定时间刷新页面。
    requestAnimationFrame 由浏览器专门为动画提供
    的 API,在运行时浏览器会自动优化方法的调用,在特定性环境下可以有效节省了
    CPU 开销。

一次性插入1000个div,如何优化性能

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);

问题来源@airuikun/technology-blog#15

this的小知识

// function pp(){
//     this.aa = 0
// }
// pp.prototype.a=function(){
//     console.log(this)
// }
// var p = new pp();
//  var q = p.a;
//  q()
这个this指向undefined

webpack面试题

主要来源:https://juejin.im/post/5c6cffde6fb9a049d975c8c1#heading-22

1.谈谈你对webpack的看法

webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。它可以很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源。

webpack的基本功能和工作原理?

  • 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
  • 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
  • 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
  • 模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
  • 自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
  • 代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
  • 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

webpack构建过程

  • 从entry里配置的module开始递归解析entry依赖的所有module
  • 每找到一个module,就会根据配置的loader去找对应的转换规则
  • 对module进行转换后,再解析出当前module依赖的module
  • 这些模块会以entry为单位分组,一个entry和其所有依赖的module被分到一个组Chunk
  • 最后webpack会把所有Chunk转换成文件输出
  • 在整个流程中webpack会在恰当的时机执行plugin里定义的逻辑

webpack打包原理

将所有依赖打包成一个bundle.js,通过代码分割成单元片段按需加载

什么是webpack,与gulp,grunt有什么区别

  • webpack是一个模块打包工具,可以递归地打包项目中的所有模块,最终生成几个打包后的文件。
  • 区别:webpack支持代码分割,模块化(AMD,CommonJ,ES2015),全局分析

什么是entry,output?

  • entry 入口,告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
  • output 出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist

什么是loader,plugins?

  • loader是用来告诉webpack如何转换某一类型的文件,并且引入到打包出的文件中。
  • plugins(插件)作用更大,可以打包优化,资源管理和注入环境变量

什么是bundle,chunk,module?

bundle是webpack打包出来的文件,chunk是webpack在进行模块的依赖分析的时候,代码分割出来的代码块。module是开发中的单个模块

如何自动生成webpack配置?

可以用一些官方脚手架

  • webpack-cli
  • vue-cli
// 首先安装
npm install -g @vue/cli
// 新建项目hello
vue create hello

nuxt-cli

// 确保安装了npx,npx在npm5.2.0默认安装了
// 新建项目hello
npx create-nuxt-app hello

webpack如何配置单页面和多页面的应用程序?

单个页面
module.exports = {
    entry: './path/to/my/entry/file.js'
}
### 多页面应用程序
module.entrys = {
    entry: {
        pageOne: './src/pageOne/index.js',
        pageTwo: './src/pageTwo/index.js'
    }
}

几个常见的loader

  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
  • url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试
  • image-loader:加载并且压缩图片文件
  • babel-loader:把 ES6 转换成 ES5
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码

几个常见的plugin

  • define-plugin:定义环境变量
  • terser-webpack-plugin:通过TerserPlugin压缩ES6代码
  • html-webpack-plugin 为html文件中引入的外部资源,可以生成创建html入口文件
  • mini-css-extract-plugin:分离css文件
  • clean-webpack-plugin:删除打包文件
  • happypack:实现多线程加速编译
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     
    ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.