zoukankan      html  css  js  c++  java
  • 【前端面试】同学,你会手写代码吗?

    CSS 部分

    两栏布局

    要求:垂直两栏,左边固定右边自适应。

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
        .outer {
            height: 100px;
            margin-bottom: 10px;
        }
        .left {
            background: tomato;
            height: 100px;
        }
        .right {
            background: gold;
            height: 100px;
        }
        /* 浮动 */
        .outer1 .left {
             200px;
            float: left;
        }
        .outer1 .right {
             auto;
            margin-left: 200px;
        }
        /* flex */
        .outer2 {
            display: flex;
        }
        .outer2 .left {
            flex-grow: 0;
            flex-shrink: 0;
            flex-basis: 200px;
        }
        .outer2 .right {
            flex: auto; /* 1 1 auto */
        }
        /* position */
        .outer3 {
            position: relative;
        }
        .outer3 .left {
            position: absolute;
             200px;
        }
        .outer3 .right {
            margin-left: 200px;
        }
        /* position again */
        .outer4 {
            position: relative;
        }
        .outer4 .left {
             200px;
        }
        .outer4 .right {
            position: absolute;
            top: 0;
            left: 200px;
            right: 0;
        }
        </style>
    </head>
    <!-- 左右两栏,左边固定,右边自适应 -->
    <body>
        <div class="outer outer1">
            <div class="left">1-left</div>
            <div class="right">1-right</div>
        </div>
        <div class="outer outer2">
            <div class="left">2-left</div>
            <div class="right">2-right</div>
        </div>
        <div class="outer outer3">
            <div class="left">3-left</div>
            <div class="right">3-right</div>
        </div>
        <div class="outer outer4">
            <div class="left">4-left</div>
            <div class="right">4-right</div>
        </div>
    </body>
    </html>

    三栏布局

    要求:垂直三栏布局,左右两栏宽度固定,中间自适应

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            .outer, .left, .middle, .right {
                height: 100px;
                margin-bottom: 5px;
            }
            .left {
                background: tomato;
            }
            .middle {
                background: lightgreen;
            }
            .right {
                background: gold;
            }
            /* 左右分别设置绝对定位 中间设置外边距 */
            .outer1 {
                position: relative;
            }
            .outer1 .left {
                position: absolute;
                 100px;
            }
            .outer1 .middle {
                margin: 0 200px 0 100px;
            }
            .outer1 .right {
                position: absolute;
                 200px;
                top: 0;
                right: 0;
            }
            /* flex 布局 */
            .outer2 {
                display: flex;
            }
            .outer2 .left {
                flex: 0 0 100px;
            }
            .outer2 .middle {
                flex: auto;
            }
            .outer2 .right {
                flex: 0 0 200px;
            }
            /* 浮动布局 但是 html 中 middle要放到最后 */
            .outer3 .left {
                float: left;
                 100px;
            }
            .outer3 .right {
                float: right;
                 200px;
            }
            .outer3 .middle {
                margin: 0 200px 0 100px;
            }
        </style>
    </head>
    <!-- 三栏布局 左右固定 中间自适应 -->
    <body>
        <div class="outer outer1">
            <div class="left">1-left</div>
            <div class="middle">1-middle</div>
            <div class="right">1-right</div>
        </div>
        <div class="outer outer2">
            <div class="left">2-left</div>
            <div class="middle">2-middle</div>
            <div class="right">2-right</div>
        </div>
        <div class="outer outer3">
            <div class="left">3-left</div>
            <div class="right">3-right</div>
            <div class="middle">3-middle</div>
        </div>
    </body>
    </html>

    圣杯布局 和 双飞翼布局

    和三栏布局要求相同,不过中间列要写在前面保证优先渲染。

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            .outer, .left, .middle, .right {
                height: 100px;
                margin-bottom: 5px;
            }
            .left {
                background: tomato;
            }
            .middle {
                background: lightgreen;
            }
            .right {
                background: gold;
            }
            /* 圣杯布局 通过浮动和负边距实现 */
            .outer1 {
                padding: 0 200px 0 100px;
            }
            .outer1 .middle {
                 100%;
                float: left;
            }
            .outer1 .left {
                 100px;
                float: left;
                margin-left: -100%;
                position: relative;
                left: -100px;
            }
            .outer1 .right {
                 200px;
                float: left;
                margin-left: -200px;
                position: relative;
                left: 200px;
            }
            /* 双飞翼布局 */
            .outer2 .middle-wrapper {
                 100%;
                float: left;
            }
            .outer2 .middle {
                margin: 0 200px 0 100px;
            }
            .outer2 .left {
                 100px;
                float: left;
                margin-left: -100%;
            }
            .outer2 .right {
                 200px;
                float: left;
                margin-left: -200px;
            }
        </style>
    </head>
    <!-- 三栏布局 左右固定 中间自适应 -->
    <body>
        <!-- 圣杯布局 middle 最先 -->
        <div class="outer outer1">
            <div class="middle">圣杯-middle</div>
            <div class="left">圣杯-left</div>
            <div class="right">圣杯-right</div>
        </div>
        <!-- 双飞翼布局 middle 最先 多一层 div -->
        <div class="outer outer2">
            <div class="middle-wrapper">
                <div class="middle">双飞翼布局-middle</div>
            </div>
            <div class="left">双飞翼布局-left</div>
            <div class="right">双飞翼布局-right</div>
        </div>
    </body>
    </html>
     

    三角形

    实现一个三角形

    常见题目,通过 border 实现

    查看代码
    <!DOCTYPE html>
    <html>
    <head>
      <title>三角形</title>
      <style type="text/css">
        .box1, .box2, .box3, .box4 {
          height: 0px;
           0px;
          float: left;
          border-style: solid;
          margin: 10px;
        }
        .box1 { /* 等腰直角 */
          border- 100px;
          border-color: tomato transparent transparent transparent;
        }
        .box2 { /* 等边 */
          border- 100px 173px;
          border-color: transparent tomato transparent transparent;
        }
        .box3 { /* 等腰 */
          border- 100px 80px;
          border-color: transparent transparent tomato transparent;
        }
        .box4 { /* 其他 */
          border- 100px 90px 80px 70px;
          border-color: transparent transparent transparent tomato;
        }
      </style>
    </head>
    <body>
      <div class="box1"></div>
      <div class="box2"></div>
      <div class="box3"></div>
      <div class="box4"></div>
    </body>
    </html>

    正方形

    使用 css 实现一个宽高自适应的正方形

    查看代码
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title></title>
            <style>
                /* 都是像对于屏幕宽度的比例 */
                .square1 {
                     10%;
                    height: 10vw;
                    background: red;
                }
                /* margin/padding 百分比是相对父元素 width 的 */
                .square2 {
                     20%;
                    height: 0;
                    padding-top: 20%;
                    background: orange;
                }
                /* 通过子元素 margin */
                .square3 {
                     30%;
                    overflow: hidden; /* 触发 BFC */
                    background: yellow;
                }
                .square3::after {
                    content: '';
                    display: block;
                    margin-top: 100%; /* 高度相对于 square3 的 width */
                }
            </style>
        </head>
        <!-- 画一个正方形 -->
        <body>
            <div class="square1"></div>
            <div class="square2"></div>
            <div class="square3"></div>
        </body>
    </html>
    复制代码

    扇形

    实现一个 1/4 圆、任意弧度的扇形

    有多种实现方法,这里选几种简单方法(我看得懂的)实现。

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
        /* 通过 border 和 border-radius 实现 1/4 圆 */
        .sector1 {
            height: 0;
             0;
            border: 100px solid;
            border-radius: 50%;
            border-color: turquoise tomato tan thistle;
        }
        /* 类似三角形的做法加上父元素 overflow: hidden; 也可以实现任意弧度圆 */
        .sector2 {
            height: 100px;
             200px;
            border-radius: 100px 100px 0 0;
            overflow: hidden;
        }
        .sector2::after {
            content: '';
            display: block;
            height: 0;
             0;
            border-style: solid;
            border- 100px 58px 0;
            border-color: tomato transparent;
            transform: translate(42px,0);
        }
        /* 通过子元素 rotateZ 和父元素 overflow: hidden 实现任意弧度扇形(此处是60°) */
        .sector3 {
            height: 100px;
             100px;
            border-top-right-radius: 100px;
            overflow: hidden;
            /* background: gold; */
        }
        .sector3::after {
            content: '';
            display: block;
            height: 100px;
             100px;
            background: tomato;
            transform: rotateZ(-30deg);
            transform-origin: left bottom;
        }
        /* 通过 skewY 实现一个60°的扇形 */
        .sector4 {
            height: 100px;
             100px;
            border-top-right-radius: 100px;
            overflow: hidden;
        }
        .sector4::after {
            content: '';
            display: block;
            height: 100px;
             100px;
            background: tomato;
            transform: skewY(-30deg);
            transform-origin: left bottom;
        }
        /* 通过渐变设置60°扇形 */
        .sector5 {
            height: 200px;
             200px;
            background: tomato;
            border-radius: 50%;
            background-image: linear-gradient(150deg, transparent 50%, #fff 50%),
            linear-gradient(90deg, #fff 50%, transparent 50%);
        }
        </style>
    </head>
    <body>
        <div style="display: flex; justify-content: space-around;">
            <div class="sector1"></div>
            <div class="sector2"></div>
            <div class="sector3"></div>
            <div class="sector4"></div>
            <div class="sector5"></div>
        </div>
    </body>
    </html>
    

    水平垂直居中

    实现子元素的水平垂直居中

    查看代码
    <!DOCTYPE html>
    <html>
    <head>
      <title>水平垂直居中</title>
      <style type="text/css">
        .outer {
          height: 200px;
           200px;
          background: tomato;
          margin: 10px;
          float: left;
          position: relative;
        }
        .inner {
          height: 100px;
           100px;
          background: black;
        }
        /* 
         * 通过 position 和 margin 居中 
         * 缺点:需要知道 inner 的长宽
         */
        .inner1 {
          position: absolute;
          top: 50%;
          left: 50%;
          margin-top: -50px;
          margin-left: -50px;
        }
        /*
         * 通过 position 和 margin 居中 (2
         */
        .inner2 {
          position: absolute;
          top: 0;
          right: 0;
          bottom: 0;
          left: 0;
          margin: auto;
        }
        /*
         * 通过 flex 进行居中
         */
        .outer3 {
          display: flex;
          justify-content: center;
          align-items: center;
        }
        /**
         * 通过 position 和 transform 居中
         */
        .inner4 {
          top: 50%;
          left: 50%;
          transform: translate(-50%,-50%);
          position: absolute;
        }
      </style>
    </head>
    <body>
      <div class="outer outer1">
        <div class="inner inner1"></div>
      </div>
      <div class="outer outer2">
        <div class="inner inner2"></div>
      </div>
      <div class="outer outer3">
        <div class="inner inner3"></div>
      </div>
      <div class="outer outer4">
        <div class="inner inner4"></div>
      </div>
    </body>
    </html>
    

    清除浮动

    要求:清除浮动

    可以通过 clear:both 或 BFC 实现

    查看代码
    <!DOCTYPE html>
    <html>
    <head>
      <title>清除浮动</title>
      <style type="text/css">
        .outer {
           200px;
          background: tomato;
          margin: 10px;
          position: relative;
        }
        .inner {
          height: 100px;
           100px;
          background: pink;
          margin: 10px;
          float: left;
        }
        /* 伪元素 */
        .outer1::after {
          content: '';
          display: block;
          clear: both;
        }
        /* 创建 BFC */
        .outer2 {
          overflow: hidden;
        }
      </style>
    </head>
    <body>
      <div class="outer outer1">
        <div class="inner"></div>
      </div>
      <div class="outer outer2">
        <div class="inner"></div>
      </div>
    </body>
    </html>

    弹出框

    使用 CSS 写一个弹出框效果

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            .bg {
                height: 666px;
                 100%;
                font-size: 60px;
                text-align: center;
            }
            .dialog {
                z-index: 999;
                position: fixed;
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                background: rgba(0, 0, 0, 0.5);
            }
            .dialog .content {
                min-height: 300px;
                 600px;
                background: #fff;
                border-radius: 5px;
                border: 1px solid #ebeef5;
                box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
            }
        </style>
    </head>
    <body>
        <div class="bg">
            页面内容
        </div>
        <div class="dialog">
            <div class="content">
                弹出框
            </div>
        </div>
    </body>
    </html>

    导航栏

    要求:一个 div 内部放很多水平 div ,并可以横向滚动。

    查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=div, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            body,html {
                margin: 0;
                padding: 0;
            }
            /* flex 实现 */
            /* .nav {
                display: flex;
                height: 30px;
                border: 1px solid #000;
                padding: 3px;
                overflow-x: auto;
            }
            .nav::-webkit-scrollbar {
                display: none;
            }
            .item {
                flex: 0 0 200px;
                height: 30px;
                margin-right: 5px;
                background: gray;
            } */
            /* inline-block 和 white-space: nowrap; 实现 */
            .nav {
                height: 30px;
                padding: 3px;
                border: 1px solid #000;
                overflow-x: auto;
                white-space: nowrap;
            }
            .nav::-webkit-scrollbar {
                display: none;
            }
            .item {
                display: inline-block;
                 200px;
                height: 30px;
                margin-right: 5px;
                background: gray;
            }
        </style>
    </head>
    <!-- 水平滚动导航栏 -->
    <body>
        <div class="nav">
            <div class="item">item1</div>
            <div class="item">item2</div>
            <div class="item">item3</div>
            <div class="item">item4</div>
            <div class="item">item5</div>
            <div class="item">item6</div>
            <div class="item">item7</div>
            <div class="item">item8</div>
            <div class="item">item9</div>
        </div>
    </body>
    </html>

    CSS 部分完,总结,Flex 无敌。

    JavaScript 部分

    手写 bind、call 和 apply

    Function.prototype.bind = function(context, ...bindArgs) {
      // func 为调用 bind 的原函数
      const func = this;
      context = context || window;
      
      if (typeof func !== 'function') {
        throw new TypeError('Bind must be called on a function');
      }
      // bind 返回一个绑定 this 的函数
      return function(...callArgs) {
        let args = bindArgs.concat(callArgs);
        if (this instanceof func) {
          // 意味着是通过 new 调用的 而 new 的优先级高于 bind
          return new func(...args);
        }
        return func.call(context, ...args);
      }
    }
    
    // 通过隐式绑定实现
    Function.prototype.call = function(context, ...args) {
      context = context || window;
      context.func = this;
    
      if (typeof context.func !== 'function') {
        throw new TypeError('call must be called on a function');
      }
    
      let res = context.func(...args);
      delete context.func;
      return res;
    }
    
    Function.prototype.apply = function(context, args) {
      context = context || window;
      context.func = this;
    
      if (typeof context.func !== 'function') {
        throw new TypeError('apply must be called on a function');
      }
    
      let res = context.func(...args);
      delete context.func;
      return res;
    }

    实现一个继承

    // 参考 You Dont Know JavaScript 上卷
    // 基类
    function Base() {
    }
    // 派生类
    function Derived() {
        Base.call(this);
    }
    // 将派生类的原型的原型链挂在基类的原型上
    Object.setPrototypeOf(Derived.prototype, Base.prototype);

    实现一个 new

    // 手动实现一个 new 关键字的功能的函数 _new(fun, args) --> new fun(args)
    function _new(fun, ...args) {
        if (typeof fun !== 'function') {
            return new Error('参数必须是一个函数');
        }
        let obj = Object.create(fun.prototype);
        let res = fun.call(obj, ...args);
        if (res !== null && (typeof res === 'object' || typeof res === 'function')) {
            return res;
        }
        return obj;
    }
     

    实现一个 instanceof

    // a instanceof b
    function _instanceof(a, b) {
        while (a) {
            if (a.__proto__ === b.prototype) return true;
            a = a.__proto__;
        }
        return false;
    }

    手写 jsonp 的实现

    // foo 函数将会被调用 传入后台返回的数据
    function foo(data) {
        console.log('通过jsonp获取后台数据:', data);
        document.getElementById('data').innerHTML = data;
    }
    /**
     * 通过手动创建一个 script 标签发送一个 get 请求
     * 并利用浏览器对 <script> 不进行跨域限制的特性绕过跨域问题
     */
    (function jsonp() {
        let head = document.getElementsByTagName('head')[0]; // 获取head元素 把js放里面
        let js = document.createElement('script');
        js.src = 'http://domain:port/testJSONP?a=1&b=2&callback=foo'; // 设置请求地址
        head.appendChild(js); // 这一步会发送请求
    })();
    
    // 后台代码
    // 因为是通过 script 标签调用的 后台返回的相当于一个 js 文件
    // 根据前端传入的 callback 的函数名直接调用该函数
    // 返回的是 'foo(3)'
    function testJSONP(callback, a, b) {
      return `${callback}(${a + b})`;
    }

    ajax 的实现

    感觉这个有点无聊了……

    查看代码
    // Asynchronous Javascript And XML
    function ajax(options) {
      // 选项
      var method = options.method || 'GET',
          params = options.params,
          data = options.data,
          url = options.url + (params ? '?' + Object.keys(params).map(key => key + '=' + params[key]).join('&') : ''),
          async = options.async === false ? false : true,
          success = options.success,
          headers = options.headers;
    
      var request;
      if (window.XMLHttpRequest) {
        request = new XMLHttpRequest();
      } else {
        request = new ActiveXObject('Microsoft.XMLHTTP');
      }
    
      request.onstatechange = function() {
        /**
        readyState:
          0: 请求未初始化
          1: 服务器连接已建立
          2: 请求已接收
          3: 请求处理中
          4: 请求已完成,且响应已就绪
    
        status: HTTP 状态码
        **/
        if (request.readyState === 4 && request.status === 200) {
          success && success(request.responseText);
        }
      }
    
      request.open(method, url, async);
      if (headers) {
        Object.keys(headers).forEach(key => request.setRequestHeader(key, headers[key]));
      }
      method === 'GET' ? request.send() : request.send(request.data);
    }
    // e.g.
    ajax({
      method: 'GET',
      url: '...',
      success: function(res) {
        console.log('success', res);
      },
      async: true,
      params: {
        p: 'test',
        t: 666
      },
      headers: {
        'Content-Type': 'application/json'
      }
    })

    reduce 的实现

    function reduce(arr, callback, initial) {
        let i = 0;
        let acc = initial === undefined ? arr[i++] : initial;
        for (; i < arr.length; i++) {
            acc = callback(acc, arr[i], i, arr);
        }
        return acc;
    }

    实现 generator 的自动执行器

    要求是 yield 后面只能是 PromiseThunk 函数,详见 es6.ruanyifeng.com/#docs/gener…

    function run(gen) {
      let g = gen();
    
      function next(data) {
        let result = g.next(data);
        if (result.done) return result.value;
        if (result.value instanceof Promise) {
          result.value.then(data => next(data));
        } else {
          result.value(next);
        }
      }
    
      return next();
    }
    
    // ======== e.g. ==========
    
    function func(data, cb) {
      console.log(data);
      cb();
    }
    
    function *gen() {
      let a = yield Promise.resolve(1);
      console.log(a);
      let b = yield Promise.resolve(2);
      console.log(b);
      yield func.bind(null, a + b);
    }
    run(gen);
    /** 
    output:
    1
    2
    3
    **/
     

    节流

    老生常谈了,感觉没必要写太复杂

    /**
     * 节流函数 限制函数在指定时间段只能被调用一次
     * 用法 比如防止用户连续执行一个耗时操作 对操作按钮点击函数进行节流处理
     */
    function throttle(func, wait) {
      let timer = null;
      return function(...args) {
        if (!timer) {
          func(...args);
          timer = setTimeout(() => {
            timer = null;
          }, wait);
        }
      }
    }

    防抖

    /**
     * 函数调用后不会被立即执行 之后连续 wait 时间段没有调用才会执行
     * 用法 如处理用户输入
     */
    function debounce(func, wait) {
      let timer = null;
      
      return function(...args) {
        if (timer) clearTimeout(timer); // 如果在定时器未执行期间又被调用 该定时器将被清除 并重新等待 wait 秒
        timer = setTimeout(() => {
          func(...args);
        }, wait);
      }
    }

    手写 Promise

    简单实现,基本功能都有了。

    const PENDING = 1;
    const FULFILLED = 2;
    const REJECTED = 3;
    
    function MyPromise(executor) {
        let self = this;
        this.resolveQueue = [];
        this.rejectQueue = [];
        this.state = PENDING;
        this.val = undefined;
        function resolve(val) {
            if (self.state === PENDING) {
                setTimeout(() => {
                    self.state = FULFILLED;
                    self.val = val;
                    self.resolveQueue.forEach(cb => cb(val));
                });
            }
        }
        function reject(err) {
            if (self.state === PENDING) {
                setTimeout(() => {
                    self.state = REJECTED;
                    self.val = err;
                    self.rejectQueue.forEach(cb => cb(err));
                });
            }
        }
        try {
            // 回调是异步执行 函数是同步执行
            executor(resolve, reject);
        } catch(err) {
            reject(err);
        }
    }
    
    MyPromise.prototype.then = function(onResolve, onReject) {
        let self = this;
        // 不传值的话默认是一个返回原值的函数
        onResolve = typeof onResolve === 'function' ? onResolve : (v => v); 
        onReject = typeof onReject === 'function' ? onReject : (e => { throw e });
        if (self.state === FULFILLED) {
            return new MyPromise(function(resolve, reject) {
                setTimeout(() => {
                    try {
                        let x = onResolve(self.val);
                        if (x instanceof MyPromise) {
                            x.then(resolve);
                        } else {
                            resolve(x);
                        }
                    } catch(e) {
                        reject(e);
                    }
                });
            });
        }
    
        if (self.state === REJECTED) {
            return new MyPromise(function(resolve, reject) {
                setTimeout(() => {
                    try {
                        let x = onReject(self.val);
                        if (x instanceof MyPromise) {
                            x.then(resolve);
                        } else {
                            resolve(x);
                        }
                    } catch(e) {
                        reject(e);
                    }
                });
            });
        }
        
        if (self.state === PENDING) {
            return new MyPromise(function(resolve, reject) {
                self.resolveQueue.push((val) => {
                    try {
                        let x = onResolve(val);
                        if (x instanceof MyPromise) {
                            x.then(resolve);
                        } else {
                            resolve(x);
                        }
                    } catch(e) {
                        reject(e);
                    }
                });
                self.rejectQueue.push((val) => {
                    try {
                        let x = onReject(val);
                        if (x instanceof MyPromise) {
                            x.then(resolve);
                        } else {
                            resolve(x);
                        }
                    } catch(e) {
                        reject(e);
                    }
                });
            });
        }
    }
    
    MyPromise.prototype.catch = function(onReject) {
        return this.then(null, onReject);
    }
    
    MyPromise.all = function(promises) {
        return new MyPromise(function(resolve, reject) {
            let cnt = 0;
            let result = [];
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(res => {
                    result[i] = res;
                    if (++cnt === promises.length) resolve(result);
                }, err => {
                    reject(err);
                })
            }
        });
    }
    
    MyPromise.race = function(promises) {
        return new MyPromise(function(resolve, reject) {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(resolve, reject);
            }
        });
    }
    
    MyPromise.resolve = function(val) {
        return new MyPromise(function(resolve, reject) {
            resolve(val);
        });
    }
    
    MyPromise.reject = function(err) {
        return new MyPromise(function(resolve, reject) {
            reject(err);
        })
    }

    实现一个路由 - Hash

    实现原理就是监听 url 的哈希值变化了

    <!DOCTYPE html>
    <html>
    <head>
      <title>hash 路由</title>
    </head>
    <body>
      <header>
        <a href="#home">首页</a>
        <a href="#center">个人中心页</a>
        <a href="#help">帮助页</a>
      </header>
      <section id="content"></section>
      <script>
        window.addEventListener('hashchange', (e) => {
          let content = document.getElementById('content');
          content.innerText = location.hash;
        })
      </script>
    </body>
    </html>

    路由实现 - history

    <!DOCTYPE html>
    <html>
    <head>
      <title>history 路由</title>
    </head>
    <body>
      <header>
        <a onclick="changeRoute(this)" data-path="home">首页</a>
        <a onclick="changeRoute(this)" data-path="center">个人中心页</a>
        <a onclick="changeRoute(this)" data-path="help">帮助页</a>
      </header>
      <section id="content"></section>
      <script>
        function changeRoute(route) {
          let path = route.dataset.path;
          /**
           * window.history.pushState(state, title, url)
           * state:一个与添加的记录相关联的状态对象,主要用于popstate事件。该事件触发时,该对象会传入回调函数。
           *        也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。
           *        如果不需要这个对象,此处可以填 null。
           * title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。
           * url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
           */
          changePage(path);
          history.pushState({ content: path }, null, path);
        }
        /**
         * 调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。
         * 点击后退、前进按钮、或者在 js 中调用 history.back()、history.forward()、history.go() 方法会触发
         */ 
        window.addEventListener('popstate', (e) => {
          let content = e.state && e.state.content;
          changePage(content);
        });
    
        function changePage(pageContent) {
          let content = document.getElementById('content');
          content.innerText = pageContent;
        }
      </script>
    </body>
    </html>

    还有一些稍复杂的可以写,有时间再补。


    作者:我不吃饼干呀
    链接:https://juejin.im/post/5c9edb066fb9a05e267026dc
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    给网站添加图标: Font Awesome
    queue队列
    threading.Event
    信号量 semaphore
    rlock递归锁
    lock多线程锁
    threading
    BaseRequestHandler
    Socket网络编程
    文件传输 FTP
  • 原文地址:https://www.cnblogs.com/Antwan-Dmy/p/10714433.html
Copyright © 2011-2022 走看看