【前端面试】同学,你会手写代码吗?

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 {
        width: 200px;
        float: left;
    }
    .outer1 .right {
        width: 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;
        width: 200px;
    }
    .outer3 .right {
        margin-left: 200px;
    }
    /* position again */
    .outer4 {
        position: relative;
    }
    .outer4 .left {
        width: 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;
            width: 100px;
        }
        .outer1 .middle {
            margin: 0 200px 0 100px;
        }
        .outer1 .right {
            position: absolute;
            width: 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;
            width: 100px;
        }
        .outer3 .right {
            float: right;
            width: 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 {
            width: 100%;
            float: left;
        }
        .outer1 .left {
            width: 100px;
            float: left;
            margin-left: -100%;
            position: relative;
            left: -100px;
        }
        .outer1 .right {
            width: 200px;
            float: left;
            margin-left: -200px;
            position: relative;
            left: 200px;
        }
        /* 双飞翼布局 */
        .outer2 .middle-wrapper {
            width: 100%;
            float: left;
        }
        .outer2 .middle {
            margin: 0 200px 0 100px;
        }
        .outer2 .left {
            width: 100px;
            float: left;
            margin-left: -100%;
        }
        .outer2 .right {
            width: 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;
      width: 0px;
      float: left;
      border-style: solid;
      margin: 10px;
    }
    .box1 { /* 等腰直角 */
      border-width: 100px;
      border-color: tomato transparent transparent transparent;
    }
    .box2 { /* 等边 */
      border-width: 100px 173px;
      border-color: transparent tomato transparent transparent;
    }
    .box3 { /* 等腰 */
      border-width: 100px 80px;
      border-color: transparent transparent tomato transparent;
    }
    .box4 { /* 其他 */
      border-width: 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 {
                width: 10%;
                height: 10vw;
                background: red;
            }
            /* margin/padding 百分比是相对父元素 width 的 */
            .square2 {
                width: 20%;
                height: 0;
                padding-top: 20%;
                background: orange;
            }
            /* 通过子元素 margin */
            .square3 {
                width: 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;
        width: 0;
        border: 100px solid;
        border-radius: 50%;
        border-color: turquoise tomato tan thistle;
    }
    /* 类似三角形的做法加上父元素 overflow: hidden; 也可以实现任意弧度圆 */
    .sector2 {
        height: 100px;
        width: 200px;
        border-radius: 100px 100px 0 0;
        overflow: hidden;
    }
    .sector2::after {
        content: ‘‘;
        display: block;
        height: 0;
        width: 0;
        border-style: solid;
        border-width: 100px 58px 0;
        border-color: tomato transparent;
        transform: translate(42px,0);
    }
    /* 通过子元素 rotateZ 和父元素 overflow: hidden 实现任意弧度扇形(此处是60°) */
    .sector3 {
        height: 100px;
        width: 100px;
        border-top-right-radius: 100px;
        overflow: hidden;
        /* background: gold; */
    }
    .sector3::after {
        content: ‘‘;
        display: block;
        height: 100px;
        width: 100px;
        background: tomato;
        transform: rotateZ(-30deg);
        transform-origin: left bottom;
    }
    /* 通过 skewY 实现一个60°的扇形 */
    .sector4 {
        height: 100px;
        width: 100px;
        border-top-right-radius: 100px;
        overflow: hidden;
    }
    .sector4::after {
        content: ‘‘;
        display: block;
        height: 100px;
        width: 100px;
        background: tomato;
        transform: skewY(-30deg);
        transform-origin: left bottom;
    }
    /* 通过渐变设置60°扇形 */
    .sector5 {
        height: 200px;
        width: 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;
      width: 200px;
      background: tomato;
      margin: 10px;
      float: left;
      position: relative;
    }
    .inner {
      height: 100px;
      width: 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 {
      width: 200px;
      background: tomato;
      margin: 10px;
      position: relative;
    }
    .inner {
      height: 100px;
      width: 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;
            width: 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;
            width: 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;
            width: 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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/Antwan-Dmy/p/10714433.html

时间: 2024-10-02 20:25:37

【前端面试】同学,你会手写代码吗?的相关文章

.netER的未来路,关于基础是否重要和应该自己手写代码吗?

http://www.cnblogs.com/onepiece_wang/p/5558341.html#!comments 引用"基础知识的学习,一开始可能是背书,但是在后续若干年的工作过程中,在写代码时有没有想过为什么代码要写成这样子." 谁没有去想过呢?我深究过,但后来放弃了,原因很简单,因为我深究后发现,1+1等于2 苹果就是叫苹果.我去思考1+1为什么等于2 苹果为什么叫苹果.研究透后才发现只是多此一举,很浪费时间也没有实质性的作用.因为他就叫那个苹果名字,1+1就是等于2,我

UI到底应该用xib/storyboard完成,还是用手写代码来完成?

UI到底应该用xib/storyboard完成,还是用手写代码来完成? 文章来源:http://blog.csdn.net/libaineu2004/article/details/45488665 参考文章: <关于代码手写UI,xib和StoryBoard> http://blog.csdn.net/likendsl/article/details/38731333 <代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧> ht

我要好offer之 str/mem系列手写代码

1. str*系列手写代码 a. 一定要注意末尾'\0'的处理,切记切记 b. 一定要对输入做有效性判断,多用断言就是了 int Strlen(const char* str) { assert(str != NULL); const char* tmp = str; while (*tmp != '\0') { ++tmp; } return tmp - str; } char* Strcpy(char* dst, const char* src) { assert(dst != NULL &

如果选择构建ui界面方式,手写代码,xib和StoryBoard间的博弈

代码手写UI这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用. 大型多人合作项目使用代码构建UI,主要是看中纯代码在版本管理时的优势,检查追踪改动以及进行代码合并相对容易一些. 另外,代码UI可以说具有最好的代码重用性.如果你的目的是写一些可以高度重用的控件提供给其他开发者使用,那毫无疑问最好的选择应该是使用代码来完成UIView的子类.这样进一步的修改和其他开发者在使用时,都会方便不少.使用代码也是最为强大的,会有xib或者StoryBoard做不了的事情,但是使用代码最终一定能

手写代码UI,xib和StoryBoard间的的优劣比较

在UI制作方面,逐渐分化三种主要流派:使用代码手写UI:使用单个xib文件组织viewController或者view:使用StoryBoard来通过单个或很少的几个文件构建UI.三种方式各有优劣,也各有自己最适用的场合. 一.手写代码UI 1.优势 √  适合大型项目大规模使用,利于版本管理.追踪改动以及代码合并 √  最好的代码重用性 2.遗憾 √  慢,开发周期长,维护代码复杂 √  自动布局AutoLayout困难 二.xib文件组织viewController或者view 1.优势 √

iOS UICollectionView手写代码实现步骤

// //  ViewController.h //  collectionView手写代码 // //  Created by yangxiuying on 14/11/28. //  Copyright (c) 2014年 lanjiying. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController<UICollectionViewDataSource,U

手写代码自动实现自动布局,即Auto Layout的使用

手写代码自动实现自动布局,即Auto Layout的使用,有需要的朋友可以参考下. 这里要注意几点: 对子视图的约束,若是基于父视图,要通过父视图去添加约束. 对子视图进行自动布局调整,首先对UIView的一个属性设置,这是因为如果我们用Interface Builder,勾选Ues Autolayout,这时autoresizingMask就会被Auto Layout 取代,在手写代码时,我们就需要手动控制,代码如下 [_shadow setTranslatesAutoresizingMask

Appium初始化设置:手写代码连接手机、appium-desktop连接手机

一.包名获取的三种方式 1)找开发要2)mac使用命令:adb logcat | grep START win使用命令:adb logcat | findstr START 查看包名和入口如下: 3)通过aapt命令查看 cmd到你的android-sdk-windows\build-tools\28.0.3路径下,可以看到aapt 注意:mac使用ls,win使用dir命令 win使用命令  aapt dump badging C:\Users\Yangfan\Desktop\mobileqq

百度面试两板斧:手写算法问基础

阅读本文大概需要 4 分钟. 作者:黄小斜 17年7月份,我参加了百度的实习生面试,随后在百度开始了半年的实习生活,18年7月份,我参加了百度的校招提前批面试,由于可以同时参加百度多个部门的提前批面试,结果我前前后后面试了10多次,也算是一段比较奇葩的经历了. 当然,实习生面试是这里面最简单的一次了,三轮面试,前两轮都是在问基础,问的也不深入,第三轮面试则直接谈人生谈理想.其实百度的日常实习生面试难度确实比校招要来的容易,因为百度一年四季都在招实习生,反观阿里和腾讯,只有在春招期间招收实习生.