首页 文章详情

前端面试中常见的手写代码集合

前端达人 | 147 2021-02-12 13:04 0 0 0
UniSMS (合一短信)

来源 | https://juejin.im/post/5c9edb066fb9a05e267026dc

作者 | 我不吃饼干呀


CSS 部分

1、两栏布局

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

<!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>    <p class="outer outer1">        <p class="left">1-left</p>        <p class="right">1-right</p>    </p>    <p class="outer outer2">        <p class="left">2-left</p>        <p class="right">2-right</p>    </p>    <p class="outer outer3">        <p class="left">3-left</p>        <p class="right">3-right</p>    </p>    <p class="outer outer4">        <p class="left">4-left</p>        <p class="right">4-right</p>    </p></body></html>

2、三栏布局

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

<!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>    <p class="outer outer1">        <p class="left">1-left</p>        <p class="middle">1-middle</p>        <p class="right">1-right</p>    </p>    <p class="outer outer2">        <p class="left">2-left</p>        <p class="middle">2-middle</p>        <p class="right">2-right</p>    </p>    <p class="outer outer3">        <p class="left">3-left</p>        <p class="right">3-right</p>        <p class="middle">3-middle</p>    </p></body></html>

3、圣杯布局 和 双飞翼布局

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

<!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 最先 -->    <p class="outer outer1">        <p class="middle">圣杯-middle</p>        <p class="left">圣杯-left</p>        <p class="right">圣杯-right</p>    </p>    <!-- 双飞翼布局 middle 最先 多一层 p -->    <p class="outer outer2">        <p class="middle-wrapper">            <p class="middle">双飞翼布局-middle</p>        </p>        <p class="left">双飞翼布局-left</p>        <p class="right">双飞翼布局-right</p>    </p></body></html>

3、三角形

实现一个三角形

常见题目,通过 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>  <p class="box1"></p>  <p class="box2"></p>  <p class="box3"></p>  <p class="box4"></p></body></html>
4、正方形
使用 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>    <p class="square1"></p>    <p class="square2"></p>    <p class="square3"></p>  </body></html>
4、扇形
实现一个 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>    <p style="display: flex; justify-content: space-around;">        <p class="sector1"></p>        <p class="sector2"></p>        <p class="sector3"></p>        <p class="sector4"></p>        <p class="sector5"></p>    </p></body></html>
5、水平垂直居中
实现子元素的水平垂直居中
<!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>  <p class="outer outer1">    <p class="inner inner1"></p>  </p>  <p class="outer outer2">    <p class="inner inner2"></p>  </p>  <p class="outer outer3">    <p class="inner inner3"></p>  </p>  <p class="outer outer4">    <p class="inner inner4"></p>  </p></body></html>
6、清除浮动
要求:清除浮动
可以通过 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>  <p class="outer outer1">    <p class="inner"></p>  </p>  <p class="outer outer2">    <p class="inner"></p>  </p></body></html>
7、弹出框
使用 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>    <p class="bg">        页面内容    </p>    <p class="dialog">        <p class="content">            弹出框        </p>    </p></body></html>
8、导航栏
要求:一个 p 内部放很多水平 p ,并可以横向滚动。
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=p, 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>    <p class="nav">        <p class="item">item1</p>        <p class="item">item2</p>        <p class="item">item3</p>        <p class="item">item4</p>        <p class="item">item5</p>        <p class="item">item6</p>        <p class="item">item7</p>        <p class="item">item8</p>        <p class="item">item9</p>    </p></body></html>

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

JavaScript 部分

1、手写 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;}

2、实现一个继承

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

3、实现一个 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;}

4、实现一个 instanceof

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

5、手写 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})`;}

6、ajax 的实现

感觉这个有点无聊了……

// Asynchronous Javascript And XMLfunction 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.onreadystatechange = 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(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' }})

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

8、实现 generator 的自动执行器

要求是 yield 后面只能是 Promise 或 Thunk 函数,详见 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:123**/

9、节流

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

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

10、防抖

/** * 函数调用后不会被立即执行 之后连续 wait 时间段没有调用才会执行 * 用法 如处理用户输入 */function debounce(func, wait) {  let timer = null;

return function(...args) { if (timer) clearTimeout(timer); // 如果在定时器未执行期间又被调用 该定时器将被清除 并重新等待 wait 秒 timer = setTimeout(() => { func(...args); }, wait); }}

11、手写 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); })}

12、实现一个路由 - 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>  <p id="content"></p>  <script>    window.addEventListener('hashchange', (e) => {      let content = document.getElementById('content');      content.innerText = location.hash;    })</script></body></html>

13、路由实现 - 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>  <p id="content"></p>  <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>

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


本文完〜



good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter