美文网首页
web知识点-记录

web知识点-记录

作者: wwmin_ | 来源:发表于2017-05-01 09:14 被阅读82次

    技术点: 不定期更新补充

    • 页面引用svg symbol标签创建icon
    • p:nth-child(2) 与 p:nth-of-type(2)的作用不完全相同:同属于伪类,还有:first-of-type, :last-of-type, :nth-last-of-type 以及 :only-of-type等,参考nth-child和nth-of-type
    • charCodeAt,String.fromCharCode:将字符转为unicode码值和从unicode码值转为字符串."wwmin".charCodeAt(0);//119;,String.fromCharCode(119)//w.一般的charAt(i) 返回在指定位置的字符.
    • 刷新页面window.location.reload()
    • form表单 input type[text, search, url, telephone, email, password, date pickers, number, checkbox, radio 以及 file],required="required",为必填
    • vue中<input v-model="something">仅仅是<input v-bind:value="something" v-on:input="something = $event.target.value">的语法糖. @input 事件触发.
    • async await方式异步方法的同步写法
    • html figure 标签用于显示图片<figure><p>黄浦江上的的卢浦大桥</p>[图片]</figure>
    • 文字显示包裹,超出时用...省略号显示 css:
      .ellipsis{
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
      }
    
    • contentEditable=true在chrme控制台中输入此命令可使该元素可编辑(文字)
    • Vue中img的src属性绑定与static文件夹:在.vue中添加时src的路径是相对路径,可以直接写相对路径.如果想使用此路径需要把图片放到static路径下面,不能直接引用assets路径,如果想引用assets路径下的资源,就需要传入图片编码,即:imgUrl = require('./assets/logo.png'),这样就可以读到项目路径下的图片.
    • 在元素上添加pointer-events: none;可是此元素失去鼠标事件,即可穿透改元素
    • vue中鼠标事件有@click ,同理有@mouseover @mouseout @mouseenter
    • ajax请求时cache默认为true,只有在IE浏览器下支持,chrome,safari等不支持,故应将ajax的cache显式指为false,防止ie浏览器第二次请求从cache获取.
    • c#中Session将数据保存至服务器端(可用redis代替此方案)
    • css知识:transition: all .1s ease;将所有变换添加动画
    • rem单位是root em的缩写,em用来自适应用户所使用的字体,1em相当于当前的字体尺寸(font-size属性),2em相当于当前字体尺寸的2倍。可见em用作特定字体的相对大小。字面上指的是根元素的em大小。在Web文档的上下文中,根元素就是你的html元素。如果没有重置,html默认font-size:16px。
    • justify-content内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐。justify-content: flex-start | flex-end | center | space-between | space-around
    • transform: scale(1.1);扩大元素 transform:rotate(7deg)旋转元素 translate(x,y) skew(x-angle,y-angle)
    • text-transform: uppercase;将小写字母转换成大写:capitalize首字母大写:lowercase转换成小写
    • word-spacing:1em单词之间的间隔.letter-spacing:1em字母之间的间隔
    • document.querySelector(div[data-key="1"]).classList.add('playing'),原生dom查找方式并添加class.click点击事件获取的dom=>e.target.classList.remove('playing')
    • 添加监听,并监听trasition事件(在css中定义的transition属性在js中监听结束事件)
    const keys = Array.from(document.querySelectorAll('.key'));
      keys.forEach(key => key.addEventListener('transitionend', removeTransition));
    
    • css3原生变量var的使用关于css3var
      CSS中原生的变量定义语法是:--*,变量使用语法是:var(--*),其中*表示我们的变量名称
    :root { --color: purple; }
    div { --color: green; }
    #alert { --color: red; }
    * { color: var(--color); }
    body {
      --size: 20;   
      font-size: calc(var(--size) * 1px);
    }
    
    选择器 例子 例子描述 CSS
    .class .intro 选择 class="intro" 的所有元素。 1
    #id #firstname 选择 id="firstname" 的所有元素。 1
    * * 选择所有元素。 2
    element p 选择所有 <p> 元素。 1
    element,element div,p 选择所有 <div> 元素和所有 <p> 元素。 1
    element element div p 选择 <div> 元素内部的所有 <p> 元素。 1
    element>element div>p 选择父元素为 <div> 元素的所有 <p> 元素。 2
    element+element div+p 选择紧接在 <div> 元素之后的所有 <p> 元素。 2
    [attribute] [target] 选择带有 target 属性所有元素。 2
    [attribute=value] [target=_blank] 选择 target="_blank" 的所有元素。 2
    [attribute~=value] [title~=flower] 选择 title 属性包含单词 "flower" 的所有元素。 2
    [attribute|=value] [lang|=en] 选择 lang 属性值以 "en" 开头的所有元素。 2
    :link a:link 选择所有未被访问的链接。 1
    :visited a:visited 选择所有已被访问的链接。 1
    :active a:active 选择活动链接。 1
    :hover a:hover 选择鼠标指针位于其上的链接。 1
    :focus input:focus 选择获得焦点的 input 元素。 2
    :first-letter p:first-letter 选择每个 <p> 元素的首字母。 1
    :first-line p:first-line 选择每个 <p> 元素的首行。 1
    :first-child p:first-child 选择属于父元素的第一个子元素的每个 <p> 元素。 2
    :before p:before 在每个 <p> 元素的内容之前插入内容。 2
    :after p:after 在每个 <p> 元素的内容之后插入内容。 2
    :lang(language) p:lang(it) 选择带有以 "it" 开头的 lang 属性值的每个 <p> 元素。 2
    element1~element2 p~ul 选择前面有 <p> 元素的每个 <ul> 元素。 3
    [attribute^=value] a[src^="https"] 选择其 src 属性值以 "https" 开头的每个 <a> 元素。 3
    [attribute$=value] a[src$=".pdf"] 选择其 src 属性以 ".pdf" 结尾的所有 <a> 元素。 3
    [attribute*=value] a[src*="abc"] 选择其 src 属性中包含 "abc" 子串的每个 <a> 元素。 3
    :first-of-type p:first-of-type 选择属于其父元素的首个 <p> 元素的每个 <p> 元素。 3
    :last-of-type p:last-of-type 选择属于其父元素的最后 <p> 元素的每个 <p> 元素。 3
    :only-of-type p:only-of-type 选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。 3
    :only-child p:only-child 选择属于其父元素的唯一子元素的每个 <p> 元素。 3
    :nth-child(n) p:nth-child(2) 选择属于其父元素的第二个子元素的每个 <p> 元素。 3
    :nth-last-child(n) p:nth-last-child(2) 同上,从最后一个子元素开始计数。 3
    :nth-of-type(n) p:nth-of-type(2) 选择属于其父元素第二个 <p> 元素的每个 <p> 元素。 3
    :nth-last-of-type(n) p:nth-last-of-type(2) 同上,但是从最后一个子元素开始计数。 3
    :last-child p:last-child 选择属于其父元素最后一个子元素每个 <p> 元素。 3
    :root :root 选择文档的根元素。 3
    :empty p:empty 选择没有子元素的每个 <p> 元素(包括文本节点)。 3
    :target #news:target 选择当前活动的 #news 元素。 3
    :enabled input:enabled 选择每个启用的 <input> 元素。 3
    :disabled input:disabled 选择每个禁用的 <input> 元素 3
    :checked input:checked 选择每个被选中的 <input> 元素。 3
    :not(selector) :not(p) 选择非 <p> 元素的每个元素。 3
    ::selection ::selection 选择被用户选取的元素部分。 3
    • 与A B的区别在于,A B选择所有后代元素,而A>B只选择一代,A+B表示HTML中紧随A的B元素,nth-child是个伪类的用法,如p:nth-child(2)就表示在p的父元素中选择位居第二位的p
    • text-decoration: none;
    • panel class下的第一个元素.panel > *:first-child,panel class下的第二个p元素.panel p:nth-child(2),panel class下的最后一个元素.panel > *:last-child,panel class下的奇数项.panel > *:nth-child(odd),panel class下的偶数项.panel > *:nth-child(even)
    • transition: transform 0.5s;将transform进行转换动画transform: translateY(-100%);
    • "12ab34".match(/\d+/gi)//["12","34"]
    • js中forEachmap,forEach没有返回值,对原数组没有影响,map返回什么那个项就是什么,返回新的数组;
    • array 数组方法spliceslice的区别:splice(index,howmany,item1,...,item2)其中index和howmany都是必须,item是要替换的项可省略,返回被删除的的项,对原数组进行修改.slice(start,end)其中start必须,end可选.可从已有的数组中返回新数组.两个方法都支持负向查找.
    • :before或:after添加内容方法:使用content
    .plates input + label:before {
       content: '⬜️'
       margin-right: 10px;
       }
    .plates input:checked + label:before {
       content: '🌮';
       }
    
    • this.querySelector('[name=item]')获取name=item元素
    • localstorage和sessionstorage:
    localstorage.setItem("key","value");
    localstorage.getItem("key");
    localstorage.removeItem("key");//删除键
    localstorage.clear();//清除所有键值对
    localstorage.key(index);//获取localstorage的属性名称
    localstorage.length;//localstorage键值对数量
    
    • ES6const const {a:a,b:b}={a:"aaa",b:"bbb",c:"ccc"};===const {a,b}={a:"aaa",b:"bbb",c:"ccc"};
    • ul样式:list-style: inside square;在内部且标记为方块
    • webpack同步代码编写脚本:
      添加package.json文件,内容为
    {
      "name": "gum",
      "version": "1.0.0",
      "description": "",
      "main": "scripts.js",
      "scripts": {
        "start" : "browser-sync start --server --files '*.css, *.html, *.js'"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "browser-sync": "^2.12.5"
      }
    }
    
    • position:fexed;固定位置
    • npoi导出excel表问题,当创建的窗格cell比较多时,如果每个cell都设置调用了一次createFont()函数,将导致打开excel表时警告或报错,解决方案:将用到的字体按类别创建几个,然后设置字体时只调用生成的cellstyle变量即可.
    • dom事件的捕获,以及事件只触发一次的方法
    const divs = document.querySelectorAll('div');
      const button = document.querySelector('button');
    
      function logText(e) {
        console.log(this.classList.value);
        // e.stopPropagation(); // stop bubbling!
        // console.log(this);
      }
    
      divs.forEach(div => div.addEventListener('click', logText, {
        capture: false,
        once: false
      }));
    
      button.addEventListener('click', () => {
        console.log('Click!!!');
      }, {
        once: true
      });
    
    • css属性变换显示transition 方法提高渲染速度的方案:will-change:transform;
    • css移动一个div可以用transform:translateY(100px);transform: translate(313.225px, 80px);方案实现.
    • transition对transform的移动有动画效果,对top,left移动位置没有效果.
    • transition对opacity显示有效果,对display:none,block没有效果
    • box-shadow: h-shadow v-shadow blur spread color inset;也可添加多个,用逗号隔开
    • transform-origin 属性允许您改变被转换元素的位置。transform-origin: -15% 100%;transform-origin: 50% 50% 100px;
    • css属性模糊匹配选择<a class="button" href="http://twitter.com/wesbos">Twiter</a>css.button[href*=twitter] { background: #019FE9; } , 匹配开头css.button[href^=twitter] { background: #019FE9; }
    • nav>ul只选择nav下一级里面的ul元素。nav ul选择nav内所包含的所有ul元素。
      nav>ulnav ul限定更严格,必须后面的元素只比前面的低一个级别。
    • 用after添加内容的方法
    .hole:after {
      display: block;
      background: url(dirt.svg) bottom center no-repeat;
      background-size:contain;
      content:'';
      width: 100%;
      height:70px;
      position: absolute;
      z-index: 2;
      bottom:-30px;
    }
    
    • async defer 异步加载script 并在加载完之后执行方法的方式:<script async src="js/gauge.js" onload="initScriptedGauges()"></script>另一种是用defer,区别在于执行时机,都是在dom加载完之后在加载script,但是defer按顺序加载,所有多个script有依赖的话需要将依赖用defer并放到上面先加载
    • callee arguments.callee相当于重新调用了函数,多用于递归
    function chen(x){
     if(x<=1)return 1;
     else arguments.callee(x-1); //此处相当于else chen(x-1);
    
    • caller 是函数对象的一个属性,该属性保存着调用当前函数的函数的引用(指向当前函数的直接父函数)
    (function a(){
      b();
     })();
    function b(){
    console.log(arguments.callee.caller); //相当于b.caller ==>输出函数a
    };
    
    • text-indent段落首行缩进控制.p{text-indent:2em}
    • scss 中&的用法 &代表父级
    nav a{
         color:red;
       }
    head nav a{
          color:green;
     }
    head nav a + a{
        color:black;
    }
    

    scss:

    nav {
        a{
            color:red;
            head & { //&代表父级
                color:green;
                head & + a{ //+ 代表下一个
                    color:black;
                }
            }
        }
    }
    
    • 执行n次的hack一点的方法:Array.apply(null,{length:20}).map(()=>console.log('1'));

    • 规定段落中的文本不进行换行:设置如何处理元素内的空白。

    p  {  white-space: nowrap  }
    normal  默认。空白会被浏览器忽略。
    pre 空白会被浏览器保留。其行为方式类似 HTML 中的 <pre> 标签。
    nowrap  文本不会换行,文本会在在同一行上继续,直到遇到 <br> 标签为止。
    pre-wrap    保留空白符序列,但是正常地进行换行。
    pre-line    合并空白符序列,但是保留换行符。
    inherit 规定应该从父元素继承 white-space 属性的值。
    
    • javascript 正则表达式中的g修饰符,会导致两次执行reg.test(string)结果不一样,原因是lastIndex的问题导致的,解决方法是可以把reg的g修饰符去除 或者第二次及之后test前执行reg.lastIndex =0
    var reg = /^https?:\/\/[a-zA-Z0-9-._\/]+/gi;
    reg.test("http://www.baidu.com");//true
    reg.test("http://www.baidu.com");//false
    //方法一:去掉g
    var reg = /^https?:\/\/[a-zA-Z0-9-._\/]+/i;
    //方法二: test之后,执行reg.lastIndex=0
    reg.test("http://www.baidu.com");//true
    reg.lastIndex=0;
    
    • 页面下载资源方法
      动态插入dom法
    let elemIF = document.createElement("iframe");
                            elemIF.src = 'http://a.b.com/1.';
                            elemIF.style.display = "none";
                            document.body.appendChild(elemIF);
    

    a标签的href 加上download属性方式:

    <a href="/images/myw3schoolimage.jpg" download="w3logo">
    

    URL.createObjectURL的参数是File对象或者Blob对象,File对象也就是通过input[type=file]选择的文件,Blob对象是二进制大对象

    function downloadFile(fileName, content){
        var aLink = document.createElement('a');
        var blob = new Blob([content]);
        //创建点击事件
        var evt = document.createEvent("HTMLEvents");
        evt.initEvent("click", false, false);//initEvent 不加后两个参数在FF下会报错
        aLink.download = fileName;
        aLink.href = URL.createObjectURL(blob);
        aLink.dispatchEvent(evt);
    }
    
    • 汉字和unicode相互转换
    function tounicode(data) {
      if (data == '') return '请输入汉字';
      var str = '';
      for (var i = 0; i < data.length; i++) {
        str += "\\u" + parseInt(data[i].charCodeAt(0), 10).toString(16);
      }
      return str;
    }
    function tohanzi(data) {
      if (data == '') return '请输入十六进制unicode';
      data = data.split("\\u");
      var str = '';
      for (var i = 0; i < data.length; i++) {
        str += String.fromCharCode(parseInt(data[i], 16).toString(10));
      }
      return str;
    }
    
    • scroll js 事件会受到css height:100%;overflow:auto;影响,监听不到scroll事件.
      可以单独监听div,只操作该div的偏移量即可,完整组件见下(修复了双击事件的bug):
    <template>
      <transition :name="transitionName">
        <div class="back-to-top" @click="backToTop" v-show="visible" :style="customStyle" title="返回顶部">
          <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg"
               class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
            <title>回到顶部</title>
            <g>
              <path
                d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z"
                fill-rule="evenodd"></path>
            </g>
          </svg>
        </div>
      </transition>
    </template>
    <script>
      let dom = null;//定义dom 默认为window
      let isWindow = false;//判断是否为window
      export default {
        name: 'BackToTop',
        props: {
          //dom id , 如果不给值,则整个默认为window
          domID: {
            type: String,
            default: ""
          },
          visibilityHeight: {
            type: Number,
            default: 300
          },
          backPosition: {
            type: Number,
            default: 0
          },
          customStyle: {
            type: Object,
            default: () => ({
              right: '50px',
              bottom: '50px',
              width: '40px',
              height: '40px',
              'border-radius': '4px',
              'line-height': '45px',
              background: '#e7eaf1'
            })
          },
          transitionName: {
            type: String,
            default: 'fade'
          }
        },
        data() {
          return {
            visible: false,
            interval: null
          }
        },
        mounted() {
          //判断是否为window 后面会分别采用不同的方法
          let d = document.getElementById(this.domID);
          if (!!d) {
            dom = d;
            isWindow = false;
          } else {
            isWindow = true;
            dom = window;
          }
          dom.addEventListener('scroll', this.handleScroll)
        },
        beforeDestroy() {
          dom.removeEventListener('scroll', this.handleScroll);
          if (this.interval) {
            clearInterval(this.interval);
            this.interval = null;
          }
        },
        methods: {
          handleScroll(e) {
            this.visible = isWindow ? dom.pageYOffset > this.visibilityHeight : dom.scrollTop > this.visibilityHeight;
          },
          backToTop() {
            if (this.interval !== null) return;
            const start = isWindow ? window.pageYOffset : dom.scrollTop;
            let i = 0;
            this.interval = setInterval(() => {
              const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 200));
              if (next <= this.backPosition) {
                isWindow ? window.scrollTo(0, this.backPosition) : dom.scrollTop = this.backPosition;
                clearInterval(this.interval);
                this.interval = null;
              } else {
                isWindow ? window.scrollTo(0, next) : dom.scrollTop = next;
              }
              i++
            }, 16.7);
          },
          easeInOutQuad(t, b, c, d) {
            if ((t /= d / 2) < 1) return c / 2 * t * t + b;
            return -c / 2 * (--t * (t - 2) - 1) + b
          }
        }
      }
    </script>
    <style scoped>
      .back-to-top {
        position: fixed;
        display: inline-block;
        text-align: center;
        cursor: pointer;
      }
      .back-to-top:hover {
        background: #d5dbe7;
      }
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity .5s;
      }
      .fade-enter,
      .fade-leave-to {
        opacity: 0
      }
      .back-to-top .Icon {
        fill: #9aaabf;
        background: none;
      }
    </style>
    
    
    • JavaScript的双重按位非运算符~~巧用 , 效果等同与Math.floor()
    ~~true === 1
    ~~false === 0
    ~~"" === 0
    ~~[] === 0
    ~~undefined === 0
    ~~!undefined === 1
    ~~null === 0
    ~~!null === 1
    ~~4.9===4
    
    • 取整 | 0
    1.3 | 0         // 1
    -1.9 | 0        // -1
    
    • 判断奇偶数 & 1
    const num=3;
    !!(num & 1)                 // true
    !!(num % 2)                 // true
    
    • JavaScript数组(基础值型)扁平化简单方法
    var a=[1,2,[1,2,3],[2,3,[2,3,4]]];
    var result=a.toString().split(',');// ["1", "2", "1", "2", "3", "2", "3", "2", "3", "4"]
    
    function flatten(arr){
        return arr.reduce(function(prev,item){
            return prev.concat(Array.isArray(item)?flatten(item):item);
        },[]);
    }
    
    function flatten(arr){
        while(arr.some(item=>Array.isArray(item)){
            arr = [].concat(...arr);
        }
        return arr;
    }
    
    • JavaScript数组平铺到指定深度
    const flatten = (arr, depth = 1) =>
      depth != 1
        ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])
        : arr.reduce((a, v) => a.concat(v), []);
    flatten([1, [2], 3, 4]);                             // [1, 2, 3, 4]
    flatten([1, [2, [3, [4, 5], 6], 7], 8], 2);           // [1, 2, 3, [4, 5], 6, 7, 8]
    
    • sleep 方法
    function sleep(delay){
      return new Promise(reslove=>{
               setTimeout(reslove,delay)
        })
    }
    !async function test(){
        const t1=+new Date();
        await sleep(3000);
        const t2=+new Date()
        console.log(t2-t1);
    }()
    
    • 获取时间戳
    +new Date() ;//最简洁
    ToNumber(new Date());
    new Date().getTime();
    
    • 数组去重
    var a=[1,1,'1','2',1];
    const unique=a=>[...new Set(a)];
    
    • 数字格式化 如1234567 -> 1,234,567
    const a=1234567;
    //正则方式
    function formatNumber(str){
        return str.replace(/\B(?=(\d{3})+(?!\d))/g,',')
    }
    //api版
    a.toLocaleString('en-US');
    a.toLocaleString(10);
    
    • 交换两个数
    var a=1,b=2;
    [a,b]=[b,a];
    
    • 代理:
      正向代理: 代理端代理的是客户端,服务端认代理不认客户端
      反向代理: 代理端代理的服务端,客户端认代理端不认服务端

    • 生成6位的数字验证码

    let qrcode=('000000' + Math.floor(Math.random() * 999999)).slice(-6);
    
    • 大/小驼峰命名转下划线/连接符命名
    'componentMapModelRegistry'.match(/^[a-z][a-z0-9]+|[A-Z][a-z0-9]*/g).join('_').toLowerCase();  
    //component_map_model_registry
    
    • url参数转换为json
    //query("?a=1&b=2") ==> {a:"1",b:"2"}
    const query = (search = '') => ((querystring = '') => (q => (querystring.split('&').forEach(item => (kv => kv[0] && (q[kv[0]] = kv[1]))(item.split('='))), q))({}))(search.split('?')[1])
    //去掉箭头函数写法
    const qeury = function (search = '') {
      return function (querystring = '') {
        return function (q) {
          return querystring.split('&').forEach(function (item) {
            return function (kv) {
              return kv[0] && (q[kv[0]] = kv[1])
            }(item.split('='))
          }), q
        }({})
      }(search.split('?')[1])
    };
    
    • 计算直角三角形斜边
    //Math.hypot([x[,y[,…]]])函数返回它的所有参数的平方和的平方根
    Math.hypot(3,4) //=> 5
    
    • js 中 数组和字符串都可以用indexOf搜索
    //字符串
    var s="abc";
    s.indexOf("a");  //0
    //数组
    var a=["aa","bb","cc"];
    a.indexOf("aa");//0
    
    • 位移运算<< , >>
    // 1. <<
    1<<1  // 2
    1<<2 //4
    1<<3 //8
    ...
    1<<n //等价于=> 1*2^n
    
    // 2.>>
    8>>1 //4
    8>>2 //2
    8>>3 //1
    ...
    8>>n // 等级于 => 8%2^n
    
    • 对象object属性遍历方法
    var person={name:"aaa",age:1};
    Object.keys(person);
    Object.getOwnPropertyNames(person);
    Reflect.ownKeys(person);
    for(let iten in person){console.log(item)};
    Object.getOwnPropertySymbols(person);//获取对象的symbol键值
    
    • Array数组中遍历空值情况
      Array中forEach ,map ,produce,filter,every,some,不会遍历null或empty空值(如new Array(2)定义出的数组) 元素 (undefined仍会遍历)
      find,findIndex 会遍历null,empty空值,
      includes,indexOf不遍历数组
      Array.entries() 的next() 方法会遍历null及empty空值
    var a=new Array(4);
    a.forEach(p=>console.log(p));//没有打印
    a=[1, null, NaN, empty];
    var ae=a.entries();
    ae.next().value; //[0,1];
    ae.next().value; //[1,null];
    ae.next().value; //[2,NaN];
    ae.next().value; //[3,undefined];
    
    • JavaScript种子随机数(得到的随机数为同一组随机数)
      Math.seed = 5;
      Math.seededRandom = function (max, min) {
        max = max || 1;
        min = min || 0;
        Math.seed = (Math.seed * 9301 + 49297) % 233280;
        var rnd = Math.seed / 233280.0;
        return min + rnd * (max - min);
      };
      for (var i = 0; i < 5; i++) {
        console.log(Math.seededRandom());
      }
    //结果如下
      0.4106738683127572
      0.8889703360768175
      0.5244170096021948
      0.8139274691358025
      0.5507115912208504
    
    • css实现hover显示菜单选项.
    <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
      <title> 页面名称 </title>
      <style type="text/css">
        .main dd {
          display: none;
        }
        .main dt:hover+dd, .main dd:hover {
          display: block;
        }
      </style>
    </head>
    <body>
    <div class="main">
      <dt><a href="#">中心信息</a></dt>
      <dd><a href="#">中心介绍</a>
        <a href="#" >荣誉奖项</a>
        <a href="#" >中心环境</a>
        <a href="#" >中心地址</a>
        <a href="#" >联系我们</a> </dd>
    </div>
    </body>
    </html>
    
    • padding和width的关系
      盒子大小最为重要的2个部分就是padding和内容content。当我们设置width是在设置content的大小,百分比的时候它参照的是父元素的content的大小。父元素content的大小(即width)为100px,子元素用百分比的时候100%就是100px。如果父元素width设置为100%刚好撑满整个设备屏幕,如果这个时候子元素width还是设置为100%;同时,父元素用了padding,此时会有横向滚动条或者整个元素的边界扩张了。
      想用padding来限制内容大小或者子元素的时候,父元素不要设置width,如果width设置了就意味着content肯定是不变的,完全和我们的想法矛盾了,所以父元素自身设置好padding就行了,里面子元素的宽度设置为100%。

    • 动态添加显示内容到html

      var logger = value => {
        if (Object.prototype.toString.call(value) !== "[object String]") {
          value = JSON.stringify(value);
        }
        let div = document.createElement("div");
        div.innerText = value;
        document.body.appendChild(div);
      };
    
    • Vue 数据劫持原理
      // 定义一个observe方法
      function defineReactive(data, key, val) {
        Object.defineProperty(data, key, {
          enumerable: true,
          configurable: true,
          get: function defineGet() {
            console.log(`get key: ${key} val: ${val}`);
            return val
          },
          set: function defineSet(newVal) {
            console.log(`set key: ${key} val: ${newVal}`);
            // 此处将新的值赋给val,保存在内存中,从而达到赋值的效果
            val = newVal
          }
        })
      }
    
      // 遍历对象的属性,使之观察每个数值值
      function observe(data) {
        Object.keys(data).forEach(key => {
          defineReactive(data, key, data[key]);
        })
      }
    
    var person={name:"wwmin"};
    observe(person);
    person.name="hello world.";// => set key: name val: hello world.
    
    • 2进制 8进制 10进制 16进制 -- 相互转换
    //十进制转其他  
    var x=110;  
    console.log(x);    //110
    console.log(x.toString(8));  //156
    console.log(x.toString(32));  //3e
    console.log(x.toString(16));  //6e
    //其他转十进制  
    var x='110';  
    console.log(parseInt(x,2));  //6
    console.log(parseInt(x,8));  //72
    console.log(parseInt(x,16));  //272
    //其他转其他  
    //先用parseInt转成十进制再用toString转到目标进制  
    console.log(String.fromCharCode(parseInt(141,8))) ; //a
    console.log(parseInt('ff',16).toString(2)); //11111111
    
    • Map对象--> 键/值对的集合
    var m=new Map();
    //或者直接初始话
    var m=new Map([[1,"a"],[2,"b"],[3,"c"]]);
    m.constructor===Map;//true
    //Map属性和方法
    m.set(1,"aa");
    m.set(1,"a");//会覆盖上面的键值
    m.set(2,"b");
    m.set(3,"c");
    m.size;//3
    m.get(1);//a
    m.has(1);//true
    m.keys();//MapIterator {1, 2, 3}
    console.log([...m.keys()]);//[1,2,3]  ,转换成标准数组
    m.values();//MapIterator {"a", "b", "c"}
    console.log([...m.values()]);//["a", "b", "c"]
    m.entries();//MapIterator {1 => "a", 2 => "b", 3 => "c"}
    console.log([...m.entries()]);//[[1, "a"], [2, "b"], [3, "c"]]
    m.forEach((v,k,p)=>console.log(v,k,p));//a 1 Map(3) {1 => "a", 2 => "b", 3 => "c"},b 2 Map(3) {1 => "a", 2 => "b", 3 => "c"},c 3 Map(3) {1 => "a", 2 => "b", 3 => "c"}
    m.delete(1);//true;
    m.has(1);//false
    m.clear();
    
    • Set 集合 和Map 类似,但是没有value
    var s=new Set();
    //或者直接初始化
    var s=new Set([1,2,3]);
    s.constructor===Set;//true
    s.add(1);
    s.size;//3
    s.has(1);//true
    s.keys();//SetIterator {1, 2, 3}
    console.log([...s.keys()]);//[1,2,3]
    s.values();//等同于s.keys();
    s.entries();//SetIterator {1, 2, 3}
    console.log([...m.entries()]);//[[1, 1], [2, 2], [3, 3]]
    s.forEach((v,k,p)=>console.log(v,k,p));//1 1 Set(3){1,2,3},2 2 Set(3){1,2,3},3 4 Set(3){1,2,3}
    s.delete(1);//true
    s.has(1);//false
    s.clear();
    
    • 数组对象解构
    const s = '1997,John Doe,US,john@doe.com,New York';
    const {2:country,4:state}=s.split(","); //2为split之后的数组下标,country为指定的变量
    console.log(country);//US
    console.log(state);//New York
    
    • 使用解构删除不必要属性
    let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
    
    console.log(cleanObject);                         // {el1: '1', el2: '2', el3: '3'}
    
    • 合并对象
    let object1 = { a:1, b:2,c:3 }
    let object2 = { b:30, c:40, d:50}
    let merged = {…object1, …object2} //spread and re-add into merged
    console.log(merged) // {a:1, b:30, c:40, d:50}
    

    注意:第二个对象中的属性 b 和 c 的值把第一个对象中属性 b 与 c 的值覆盖掉了

    • 在函数参数中使用嵌套对象解构
    var car = {
      model: 'bmw 2018',
      engine: {
        v6: true,
        turbo: true,
        vin: 12345
      }
    }
    const modelAndVIN = ({model, engine: {vin}}) => {
      console.log(`model: ${model} vin: ${vin}`);
    }
    modelAndVIN(car); // => model: bmw 2018  vin: 12345
    
    • switch语句中使用范围
    function getWaterState(tempInCelsius) {
      let state;
      switch (true) {
        case (tempInCelsius <= 0): 
          state = 'Solid';
          break;
        case (tempInCelsius > 0 && tempInCelsius < 100): 
          state = 'Liquid';
          break;
        default: 
          state = 'Gas';
      }
      return state;
    }
    
    • await 多个 async 函数
    //await 多个 async 函数并等待他们执行完成,我们可以使用 Promise.all:
    await Promise.all([anAsyncCall(), thisIsAlsoAsync(), oneMore()])
    
    • 创建纯对象
      你可以创建一个 100% 的纯对象,这个对象不会继承 Object 的任何属性和方法(比如 constructor,toString() 等):
    const pureObject = Object.create(null);
    console.log(pureObject); //=> {}
    console.log(pureObject.constructor); //=> undefined
    console.log(pureObject.toString); //=> undefined
    console.log(pureObject.hasOwnProperty); //=> undefined
    
    • 格式化 JSON 代码
    const obj = { 
     foo: { bar: [11, 22, 33, 44], baz: { bing: true, boom: 'Hello' } } 
    };
    
    // 第三个参数为格式化需要的空格数目
    JSON.stringify(obj, null, 4); 
    // =>"{
    // =>    "foo": {
    // =>        "bar": [
    // =>            11,
    // =>            22,
    // =>            33,
    // =>            44
    // =>        ],
    // =>        "baz": {
    // =>            "bing": true,
    // =>            "boom": "Hello"
    // =>        }
    // =>    }
    // =>}"
    
    • 使用对象解构模拟命名参数
    //对象解构,且有默认值,并且参数可选
    function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 } = {}) {
      // ...
    }
    

    注意,传入参数为undefined或者不传入的时候会使用默认参数,但是传入null还是会覆盖默认参数。

    • 接收函数返回的多个结果
    async function getFullPost(){
      return await Promise.all([
         fetch('/post'),
         fetch('/comments')
      ]);
    }
    const [post, comments] = getFullPost();
    
    • 强制参数
    mandatory = ( ) => {
      throw new Error('Missing parameter!');
    }
    foo = (bar = mandatory( )) => {            // 这里如果不传入参数,就会执行manadatory函数报出错误
      return bar;
    }
    
    • 隐式返回值,返回对象写法
    function a(n){
      return {value:n}
    }
    //简写为
    let a=n=>({value:n})
    
    • 惰性载入函数
    function foo(){
        if(a !== b){
            console.log('aaa')
        }else{
            console.log('bbb')
        }
    }
    
    // 优化后
    function foo(){
        if(a != b){
            foo = function(){
                console.log('aaa')
            }
        }else{
            foo = function(){
                console.log('bbb')
            }
        }
        return foo();
    }
    
    • 一次性函数
    var sca = function() {
        console.log('msg')
        sca = function() {
            console.log('foo')
        }
    }
    sca()        // msg
    sca()        // foo
    sca()        // foo
    
    • input type="number"maxlength="3"不起作用解决方法
      在html5中input新增类型:color, date, datetime, datetime-local, month, week, time, email, number, range, search, tel , url.
    <input type="text" placeholder="请输入手机号码" maxlength="11" />
    

    上面的maxlength是有效的,但是将type="number"后将失去效果,此时可以使用type="tel" 解决

    <input type="tel" placeholder="请输入手机号码" maxlength="11" />
    

    不过此时数字键盘会存在一个'-'的固话符号,此影响较小可忽略,如果为了可拓展性,可用input事件写JavaScript取解决,即在oninput onpropertychange事件中取截取字符串长度即可.

    • input file选择图片后显示(FileReader)
     <input value="上传图片" type="file" id="file" name="file" onchange="show(this.files)" />
     <br />
     <img height="50" width="50" id="img"  />
    
        function show(f) {
            var str = "";
            for (var i = 0; i < f.length; i++) {
                var reader = new FileReader();
                reader.readAsDataURL(f[i]);
                reader.onload = function (e) {
                    str += "<img  height='50' width='50' id='img' src='" + e.target.result + "'/>";
                    $("#img")[0].outerHTML = str;
                }
            }        
        }
    
    • 数字转换
    '12' * 1            // 12
    'aa' * 1            // NaN
    null * 1            // 0
    undefined * 1    // NaN
    1  * { valueOf: ()=>'2' }        // 2
    + '12'            // 12
    + 'aa'               // NaN
    + ''                    // 0
    + null              // 0
    + undefined    // NaN
    + { valueOf: ()=>'2' }    // 2
    '' + {toString:()=>'S',valueOf:()=>'J'}// J  //toString()和valueOf同时存在则用valueOf()
    
    • 使用Boolean过滤数组中的所有假值
      JS中有一些假值:false,null,0,"",undefined,NaN
    const compact = arr => arr.filter(Boolean);
    compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34])             // [ 1, 2, 3, 'a', 's', 34 ]
    
    • 精确到指定位数的小数
      原理:先将小数扩大10*decimals倍并取整,然后在将整数取小数即除10*decimals
    const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)
    round(1.345, 2)                 // 1.35
    round(1.345, 1)                 // 1.3
    
    • 统计数组中相同项的个数
    var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];
    var carsObj = cars.reduce(function (obj, name) {
      obj[name] = obj[name] ? ++obj[name] : 1;
      return obj;
    }, {});
    carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }
    
    • 位数不足两位补零
    const addZero = (num, len = 2) => (`0${num}`).slice(-len);
    
    • 使用"reduce"来判断括号是否匹配
      常规的做法是使用栈来匹配,但是这里我们使用reduce 就可以做到,我们只需要一个变量 counter ,这个变量的初始值是0, 当遇到 ( 的时候,counter ++ 当遇到 ) 的时候, counter -- 。 如果括号是匹配的,那么这个 counter 最终的值是0
    //Returns 0 if balanced.
    const isParensBalanced = (str) => {
      return str.split('').reduce((counter, char) => {
        if(counter < 0) { //matched ")" before "("
          return counter;
        } else if(char === '(') {
          return ++counter;
        } else if(char === ')') {
          return --counter;
        }  else { //matched some other char
          return counter;
        }
        
      }, 0); //<-- starting value of the counter
    }
    isParensBalanced('(())') // 0 <-- balanced
    isParensBalanced('(asdfds)') //0 <-- balanced
    isParensBalanced('(()') // 1 <-- not balanced
    isParensBalanced(')(') // -1 <-- not balanced
    
    • 计算数组中元素出现的次数(将数组转为对象)
      如果你想计算数组中元素出现的次数或者想把数组转为对象,那么你可以使用 reduce 来做到。
    var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];
    var carsObj = cars.reduce(function (obj, name) { 
       obj[name] = obj[name] ? ++obj[name] : 1;
      return obj;
    }, {});
    carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }
    
    • js 实现 linq中groupBy方法
    /**
     * js 实现 linq groupBy
     *
     * @param {*} array
     * @param {*} f =>item.name || f=>[item.name,item.Average]
     * @returns
     */
    function groupBy(array, f) {
      let groups = {};
      array.forEach(o => {
        let group = JSON.stringify(f(o));
        groups[group] = groups[group] || [];
        groups[group].push(o);
      });
      return Object.keys(groups).map(group => groups[group])
    }
    
    // 使用
    let list = [
    { "name": "John", "Average": 10, "High": 10, "DtmStamp": 1358226000000 },
    {"name": "Jane","Average":10,"High":92,"DtmStamp":1358226000000},
    {"name": "Jane","Average":10,"High":45,"DtmStamp":1358226000000},
    {"name": "John","Average":10,"High":87,"DtmStamp":1358226000000},
    {"name": "Jane","Average":10,"High":10,"DtmStamp":1358226060000},
    {"name": "John","Average":15,"High":87,"DtmStamp":1358226060000},
    {"name": "John","Average":15,"High":45,"DtmStamp":1358226060000},
    {"name": "Jane","Average":15,"High":92,"DtmStamp":1358226060000}
    ];
    // 使用1
    let sort1 = groupBy(list, item => {
      return [item.name, item.Average];
    })
    // 结果
    /** 
    [ [ { name: 'John', Average: 10, High: 10, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'John', Average: 10, High: 87, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'John', Average: 15, High: 87, DtmStamp: 1358226060000 },​​​​​
    ​​​​​    { name: 'John', Average: 15, High: 45, DtmStamp: 1358226060000 } ],​​​​​
    ​​​​​  [ { name: 'Jane', Average: 10, High: 92, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'Jane', Average: 10, High: 45, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'Jane', Average: 10, High: 10, DtmStamp: 1358226060000 },​​​​​
    ​​​​​    { name: 'Jane', Average: 15, High: 92, DtmStamp: 1358226060000 } ] ]​​​​​
    **/
    
    // 使用2
    let sort2 = groupBy(list, item => {
      return item.name;
    })
    // 结果
    /** 
    [ [ { name: 'John', Average: 10, High: 10, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'John', Average: 10, High: 87, DtmStamp: 1358226000000 } ],​​​​​
    ​​​​​  [ { name: 'Jane', Average: 10, High: 92, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'Jane', Average: 10, High: 45, DtmStamp: 1358226000000 },​​​​​
    ​​​​​    { name: 'Jane', Average: 10, High: 10, DtmStamp: 1358226060000 } ],​​​​​
    ​​​​​  [ { name: 'John', Average: 15, High: 87, DtmStamp: 1358226060000 },​​​​​
    ​​​​​    { name: 'John', Average: 15, High: 45, DtmStamp: 1358226060000 } ],​​​​​
    ​​​​​  [ { name: 'Jane', Average: 15, High: 92, DtmStamp: 1358226060000 } ] ]​​​​​
    **/
    
    • 在移动端禁用长按选中文本功能
    * {
    -webkit-touch-callout:none;
    -webkit-user-select:none;
    -khtml-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    }
     input {      
       -webkit-user-select:auto; /*webkit浏览器*/     
    }  
    
    • try catch finally
     try { 
            if(x == "")  throw "为空";
        }catch(err) {
            message.innerHTML = "输入的值 " + err;
        }finally {//总是会会执行到此处
            document.getElementById("demo").value = "";
        }
    
    • 数组求和
      reduce
    let a=[1,2,3];
    let sum=a.reduce((p,t)=>p+t,0);
    

    eval

    let a=[1,2,3];
    let sum=eval(a.join('+'));
    
    • 获取文件后缀名
    function getExt(fileName){
      return fileName.substring(fileName.lastIndexOf('.')+1);
    }
    
    • 生成GUID
    // 生成guid,主要用于生成随机文件名
    function newGuid() {
        function S4() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }
    
    • 字符串首字母大写
    const firstUpperCase = ([first, ...rest]) => first.toUpperCase() + rest.join('');
    
    • css3 :empty
    <ul></ul>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
    </ul>
    <style lang="scss">
    ul {
      &:empty {
        width: 140px;
        height: 226px;
        background: url(https://ws3.sinaimg.cn/large/006tNbRwly1fwln1ad006g303w04sdlq.gif) no-repeat;
        background-size: cover; 
      }
    }
    </style>
    
    • 获取括号内内容
      matchParenthesisValue(string: string, size: "small" | "middle" | "large" = "small"): Array<string> {
        var regex1 = /\((.+?)\)/g;   // () 小括号
        var regex2 = /\[(.+?)\]/g;   // [] 中括号
        var regex3 = /\{(.+?)\}/g;  // {} 花括号,大括号
        switch (size) {
          case "small":
            return string.match(regex1).map(p => p.replace(/[\(|\)]/ig, ''));
          case "middle":
            return string.match(regex2).map(p => p.replace(/[\[|\\]/ig, ''));
          case "large":
            return string.match(regex3).map(p => p.replace(/[\{|\}]/ig, ''));
          default:
            return [];
        }
      }
    
    • 获取当天日期的前后天数日期
     /**
       *获取addDateCount前后的日期
       *
       * @param {number} addDateCount 日期天数,正值为之后天数,负值为之前天数
       * @returns date string
       */
      getFrontBackDate(addDateCount: number) {
        let date = new Date();
        date.setDate(date.getDate() + addDateCount);//获取addDayCount天后的日期
        return this.formatDate(date);
      },
     /**
       *格式化时间 型为: 2017-01-01
       *
       * @param {(string | Date)} date
       * @returns {string}
       */
      formatDate(date: string | Date): string {
        if (!date) return "";
        if (typeof date === "string") date = date.replace("T", " "); // 服务器返回的时间中含有T,部分浏览器解释不正确
        date = new Date(date);
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        return [year, month, day].map(this.formatNumber).join("-");
      },
      /**
       *将个位数补上0
       *
       * @param {*} n
       * @returns
       */
      formatNumber(n) {
        n = n.toString();
        return n[1] ? n : "0" + n;
      },
    
    • chrome dev tools
      $0,$1,$2,$3,$4 ,获取选中后的节点,$0为当前选中$1为前一次,$2...依此类推
      $,$$,$console中是冗长的函数document.querySelector的一个别名。$$能节省更多的时间,因为它不仅仅执行document.QuerySelectorAll并且返回的是一个节点的数组,而不是一个Node list,从本质上说:Array.from(document.querySelectorAll('div')) === $$('div'),但是$$('div')要简短太多了!
      $_变量是关联上次执行的结果。
      copy:拷贝资源
      设置全局变量,只需要右击变量,并且选择"Store as global variable"
      console.assert:console.assert(assertion,obj1[,obj2,...,objN]);
      console.table: 数组(或者是类数组的对象,或者就是一个对象)使用console.table方法可以将它以一个漂亮的表格的形式打印出来.当列太多的时候,使用第二个参数,传入你想要展示的列对应的名字
      console.dir:用直接的表现形式来展示你的数据

    • vue自动注册组件,使用webpack require.context

    import Vue from 'vue'
    import upperFirst from 'lodash/upperFirst'
    import camelCase from 'lodash/camelCase'
     
    // Require in a base component context
    const requireComponent = require.context(
     './components', false, /base-[\w-]+\.vue$/
    )
     
    requireComponent.keys().forEach(fileName => {
     // Get component config
     const componentConfig = requireComponent(fileName)
     
     // Get PascalCase name of component
     const componentName = upperFirst(
      camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
     )
     
     // Register component globally
     Vue.component(componentName, componentConfig.default || componentConfig)
    })
    
    import auth from './modules/auth'
    import posts from './modules/posts'
    import comments from './modules/comments'
    // ...
     
    export default new Vuex.Store({
     modules: {
      auth,
      posts,
      comments,
      // ...
     }
    })
    

    精简的做法和上面类似,也是运用 require.context()读取文件,代码如下:

    import camelCase from 'lodash/camelCase'
    const requireModule = require.context('.', false, /\.js$/)
    const modules = {}
    requireModule.keys().forEach(fileName => {
     // Don't register this file as a Vuex module
     if (fileName === './index.js') return
     
     const moduleName = camelCase(
      fileName.replace(/(\.\/|\.js)/g, '')
     )
     modules[moduleName] = {
            namespaced: true,
            ...requireModule(fileName),
           }
    })
    export default modules
    

    这样我们只需如下代码就可以了:

    import modules from './modules'
    export default new Vuex.Store({
     modules
    })
    
    • 原型链
      实例的__proto__属性(原型)等于其构造函数的prototype属性。
    function Person(name) {
        this.name = name;
    }
    let p = new Person('Tom');
    //问题:
    p.__proto__===Person.prototype //true
    Person.__proto__===Function.prototype ;//true
    
    var foo={};
    var F=function(){};
    Object.prototype.a='value a';
    Function.prototype.b = 'value b';
    
    console.log(foo.a)   ;//value a
    console.log(foo.b)    ;//undefined
    console.log(F.a)     ;//value a
    console.log(F.b)    ;//value b
    
    • 构造函数
      构造函数不需要显示的返回值。使用new来创建对象(调用构造函数)时,如果return的是非对象(数字、字符串、布尔类型等)会忽略返回值;如果return的是对象,则返回该对象(注:若return null也会忽略返回值)。
    function Person(name) {
        this.name = name
        return name;
    }
    let p = new Person('Tom');//{name: 'Tom'}
    //若改为:
    function Person(name) {
        this.name = name
        return {}
    }
    let p = new Person('Tom');//{}
    
    • typeof和instanceof的区别
      typeof :在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”.
      instanceof : 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
      语法:object instanceof constructor
      参数:object(要检测的对象.)constructor(某个构造函数)
      描述:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
    function Person (name) {
        this.name = name;
    }
    function Student () {}
    Student.prototype = Person.prototype;
    Student.prototype.constructor = Student;
    let s = new Student('Tom');
    console.log(s instanceof Person); // 返回 true
    
    • new和instanceof的内部机制
      创建一个新对象,同时继承对象类的原型,即Person.prototype;
      执行对象类的构造函数,同时该实例的属性和方法被this所引用,即this指向新构造的实例;
      如果构造函数return了一个新的“对象”,那么这个对象就会取代整个new出来的结果。如果构造函数没有return对象,那么就会返回步骤1所创建的对象,即隐式返回this。(一般情况下构造函数不会返回任何值,不过在一些特殊情况下,如果用户想覆盖这个值,可以选择返回一个普通的对象来覆盖。)
    // let p = new Person()
    let p = (function () {
        let obj = {};
        obj.__proto__ = Person.prototype;
        // 其他赋值语句...
        return obj;
    })(); //p={}
    

    下面通过代码阐述instanceof的内部机制,假设现在有x instanceof y一条语句,则其内部实际做了如下判断:

    while(x.__proto__!==null) {
        if(x.__proto__===y.prototype) {
            return true;
            break;
        }
        x.__proto__ = x.__proto__.proto__;
    }
    if(x.__proto__==null) {return false;}
    

    x会一直沿着隐式原型链proto向上查找直到x.proto.proto......===y.prototype为止,如果找到则返回true,也就是x为y的一个实例。否则返回false,x不是y的实例。

    function F() {}
    function O() {}
    
    O.prototype = new F();
    var obj = new O();
    
    console.log(obj instanceof O); // true
    console.log(obj instanceof F); // true
    console.log(obj.__proto__ === O.prototype); // true
    console.log(obj.__proto__.__proto__ === F.prototype); // true
    

    根据new 的内部机制改写上面代码

    function F() {}
    function O() {}
    var obj = (function () {
        var obj1 = {};
        obj1.__proto__ = F.prototype; // new F();
        O.prototype = obj1; // O.prototype = new F();
        obj.__proto__ = O.prototype; // new O();
        obj.__proto__ = obj1;
        return obj;
    })
    

    结合instanceof内部机制很容易得出正确答案。
    如果稍微调整一下代码顺序,结果将迥然不同

    function F() {};
    function O() {};
    
    var obj = new O();
    O.prototype = new F();
    
    console.log(obj instanceof O); // false
    console.log(obj instanceof F); // false
    console.log(obj.__proto__ === O.prototype); // false
    console.log(obj.__proto__.__proto__ === F.prototype); // false
    

    上个图,压压惊:


    prototype
    • for...in... 和for...of...
      for..of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句.
      for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法:
    for (var key of Object.keys(someObject)) {
      console.log(key + ": " + someObject[key]);
    }
    

    遍历map对象时适合用解构,例如;

    for (var [key, value] of phoneBookMap) {
       console.log(key + "'s phone number is: " + value);
    }
    

    当你为对象添加myObject.toString()方法后,就可以将对象转化为字符串,同样地,当你向任意对象添加myObject[Symbol.iterator]方法,就可以遍历这个对象了。
    for...of的步骤
    for-of循环首先调用集合的Symbol.iterator方法,紧接着返回一个新的迭代器对象。迭代器对象可以是任意具有.next()方法的对象;for-of循环将重复调用这个方法,每次循环调用一次。举个例子

    var zeroesForeverIterator = {
     [Symbol.iterator]: function () {
       return this;
      },
      next: function () {
      return {done: false, value: 0};
     }
    };
    
    • Generator
      Generator 有什么用? 它能够中断执行代码的特性,可以帮助我们来控制异步代码的执行顺序:
      定义了一个这样的 Generator 叫做 gen
    function* gen() {
      yield 1;
      yield 2;
      yield 3;
      yield 4;
    }
    

    打印这个函数后发现了一个熟悉的函数,next() 方法,我们把 gen 实例化一下,执行一下它的 next() 来看看结果:

    let g=gen();
    g.next();// => {value: 1, done: false}
    g.next();// => {value: 2, done: false}
    g.next();// => {value: 3, done: false}
    g.next();// => {value: 4, done: false}
    g.next();// => {value: undefined, done: true
    

    到这里,我们已经知道,Generator 可以实例化出一个 iterator ,并且这个 yield 语句就是用来中断代码的执行的,也就是说,配合 next() 方法,每次只会执行一个 yield 语句。

    • macrotask 和 microtask
    console.log('a');
    setTimeout(() => {
        console.log('b');
    }, 0);
    console.log('c');
    Promise.resolve().then(() => {
        console.log('d');
    })
    .then(() => {
        console.log('e');
    });
    
    console.log('f');
    //=> acfdeb
    
    macrotask|microtask
    • Http请求中的keep-alive
      在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。
      使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。
      但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。

    相关文章

      网友评论

          本文标题:web知识点-记录

          本文链接:https://www.haomeiwen.com/subject/txsftxtx.html