前端行者

[记录]我的日常随笔

2020-06-21  本文已影响0人  是ADI呀

HTTP

JS

Vue

Devops

书单

代码实现

  1. 手写节流防抖
/**
 * 节流
 * @param {Func} callback 需要节流的函数
 * @param {Number} wait 等待毫秒数
 * 执行一次后,一段时间内不再执行
 */
function throttle(func, wait = 0) {
  let timeoutId = null;
  return function throttle_fn(...args) {
    if (timeoutId === null) {
      timeoutId = setTimeout(() => {
        func.apply(this, args);
        timeoutId = null;
      }, wait);
    }
  };
}

/**
 * 防抖
 * @param {Func} callback 需要防抖的函数
 * @param {Number} wait 等待毫秒数
 * 一段时间内,取最后一次执行
 */
function debounce(func, wait = 0) {
  let timeoutId = null
  return function () {
      if (timeoutId) {
          clearTimeout(timeoutId)
      }
      timeoutId = setTimeout(() => {
          func.apply(this, arguments)
      }, wait)
  }
}
  1. 圣杯与双飞翼布局
/** 圣杯 **/
<div class="wrapper1">
  <div class="main">
    <p>bilibili</p>
  </div>
  <div class="left"></div>
  <div class="right"></div>
</div>
<style>
  .wrapper1 {
    padding: 0 60px 0 30px;
  }
  .wrapper1 .main {
    float: left;
    width: 100%;
    height: 300px;
    background: red;
  }
  .wrapper1 .left {
    float: left;
    width: 30px;
    margin-left: -100%;
    background: blue;
    height: 100px;
    position: relative;
    right: 30px;
  }
  .wrapper1 .right {
    float: left;
    width: 60px;
    margin-left: -60px;
    background: yellow;
    height: 200px;
    position: relative;
    left: 60px;
  }
</style>

/** 双飞翼 **/
<div class="wrapper2">
  <div class="container">
    <div class="main">
      <p>bilibili</p>
    </div>
  </div>
  <div class="left"></div>
  <div class="right"></div>
</div>
<style>
  .wrapper2 {
    min-width: 630px;
  }
  .wrapper2 .container {
    float: left;
    width: 100%;
  }
  .wrapper2 .container .main {
    height: 300px;
    background: red;
    margin: 0 600px 0 30px;
  }
  .wrapper2 .left {
    float: left;
    width: 30px;
    background: blue;
    height: 100px;
    margin-left: -100%;
  }
  .wrapper2 .right {
    float: left;
    width: 600px;
    background: yellow;
    height: 200px;
    margin-left: -600px;
  }
</style>
  1. 数组长度为5且元素的随机数在2-32间不重复的值
// 生成 [n,m] 的随机整数
const creatRandomNum = (min,max) => parseInt(Math.random()*(max-min+1)+min);
function arr5(arr=[]) {
    if(arr.length >= 5){return arr};
    arr = [...new Set([...arr, creatRandomNum(2,32)])];
    return arr5(arr);
}

4.写一个获取当前url查询字符串中的参数的方法

const getUrlQuery = (url = location.href) => {
  try {
    return [...new URL(url).searchParams].reduce(
      (pre, [key, value]) => Object.assign(pre, { key, value }),
      {},
    );
  } catch {
    throw new Error(`url格式不正确。url: ${url}`);
  }
};
  1. html5中的form怎么关闭自动完成?
// 在 input 标签中,可以设置 autocomplete="off" 来关闭自动填充。
<form action="demo_form.html" method="get" autocomplete="off">
  First name:<input type="text" name="fname"><br>
  E-mail: <input type="email" name="email"><br>
  <input type="submit">
</form>
  1. 请说说<script>、<script async>和<script defer>的区别
1.script 同步下载,下载成功继续阻塞 DOM 的渲染,立即执行。
2. async异步下载,下载成功后阻塞 DOM 的渲染,立即执行。
3. defer异步加载,下载成功后等待文档加载,文档加载完成后执行。
4.async、defer这两个属性无法应用于内联script。
image
  1. 实现一个call / apply / bind
// call
Function.prototype._call = function (target=window, ...res) {
    target._fun = this;
    const ret = target._fun(...res);
    delete target._fun;
    return ret;
}
// apply
Function.prototype._apply = function (target=window, list=[]) {
    target._fun = this;
    const ret = target._fun(...list);
    delete target._fun;
    return ret;
}
// bind
Function.prototype._bind = function (target, ...res) {
    if (typeof this !== 'function') {
      throw new TypeError('Error')
    }
    const that = this;
    const _func = function(...args) {
        // 判断当前韩式是直接访问还是通过new进行构造
        return that.apply(this instanceof _func ? this : target, res.concat(args));
    }
    // 添加一层原型,防止修改_func.prototype时影响到this.prototype
    _func.prototype = Object.create(this.prototype);
    return _func;
}

8.Object.create 的模拟实现

Object.create = function(target) {
  function _func () {};
  _func.prototype = target;
  return new _func();
}
  1. instanceof模拟实现
function _instanceof(L,R){
    L = L.__proto__;
    while(true){
        if(L === null) return false;
        if(R.prototype === L) return true;
        L = L.__proto__;
    }
}

10.解释一个为什么10.toFixed(10)会报错?

/** 
在我们的直觉上,10.toFixed(10) 是把整数的 10 转为浮点数并且保留 10 位小数部分。

但实际上会出错,是因为 JS 的解释器对 . 操作符产生了歧义。
在 JS 中 . 可以表示小数和从对象中取值。在这个例子中, 由于 10 是整数,
所以在 10. 默认是小数点,因此会报错。
**/

// 解决的办法有下面几种:
(10).toFixed(10) 个人喜欢这种,看起来舒服一点
10..toFixed(10)

11.将Object 与 Map 互转

var obj = { foo: "bar", baz: 42 }; 
var map = new Map(Object.entries(obj));// Map { foo: "bar", baz: 42 }
var obj2 = Object.fromEntries(map);// {foo: "bar", baz: 42}

12.寄生组合式继承

// 通过构造函数来继承实例属性,通过原型链的混成形式来继承原型方法
function clonePrototype(Super,Suber){
   var prototype = Object.create(Super.prototype);
   prototype.constructor = Suber;
   Suber.prototype = prototype;
}

function Super(name){
  this.name = name
  this.like = ['sing','dance','rap','basketball']
}
Super.prototype.sayName=function(){
   console.log(this.name)
}

function Suber(name,age){
   Super.call(this,name)      //  继承属性
   this.age=age
}
clonePrototype(Super,Suber);
Suber.prototype.sayAge=function(){
  console.log(this.age)
}

var sub1 = new Suber('sss',18);
console.log(sub1.name);  // -> sss
sub1.sayName();  // -> sss
sub1.sayAge();   // -> 18

13.如何让 (a == 1 && a == 2 && a == 3) 的值为true?

var a = {
  valueOf: (function () {
    let i = 1;
    //闭包的特性之一:i 不会被回收
    return function () {
      return i++;
    }
  })()
}
console.log(a == 1 && a == 2 && a == 3); // true
  1. JS 模块化
AMD: require.js 为代表,依赖前置,一律先加载再使用。
CMD: sea.js 为代表,依赖就近原则。
UMD: 兼容AMD和commonJS规范的同时,还兼容全局引用的方式。
ES6 import/export

15.你从未注意的隐藏危险: target = "_blank" 和 "opener"

// 最佳实践
<a href="https://an.evil.site" target="_blank" 
   rel="noopener noreferrer nofollow">
  Enter an "evil" website
</a>

16.阶乘

function factorial(num, sum = 1) {
    if(num <= 1)return sum;
    sum *= num;
    return factorial(--num, sum); // 尾递归
}
factorial(3) // -> 6

17.柯里化

const curry = (fn , args = []) => {
    return (...rets) => {
        const allArgs = args.concat(rets);
        if(allArgs.length < fn.length) {
            return curry(fn, allArgs);
        } else {
            return fn.apply(this, allArgs);
        }
    }
}
function multiFn(a, b, c) {
    return a * b * c;
}

var multi = curry(multiFn);

multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);

18.「中高级前端面试」JavaScript手写代码无敌秘籍

  1. 实现一个Promise 《图解 Promise 实现原理
// Promise 简单的实现
function Promise(excutor) {
  this.callbacks = [];

  function resolve(value) {
    setTimeout(() => {
      this.data = value;
      this.callbacks.forEach((callback) => callback(value));
    });
  }

  excutor(resolve.bind(this));
}

Promise.prototype.then = function (onResolved) {
  return new Promise((resolve) => {
    this.callbacks.push(() => {
      const result = onResolved(this.data);
      if (result instanceof Promise) {
        result.then(resolve);
      } else {
        resolve(result);
      }
    });
  });
};

// test
new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 500);
})
  .then((res) => {
    console.log(res);
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(2);
      }, 500);
    });
  })
  .then(console.log);

//Promise 完整的实现
class Promise {
  callbacks = [];
  state = 'pending';//增加状态
  value = null;//保存结果
  constructor(fn) {
    fn(this._resolve.bind(this), this._reject.bind(this));
  }
  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      this._handle({
        onFulfilled: onFulfilled || null,
        onRejected: onRejected || null,
        resolve: resolve,
        reject: reject
      });
    });
  }
  catch(onError) {
    return this.then(null, onError);
  }
  finally(onDone) {
    if (typeof onDone !== 'function') return this.then();

    let Promise = this.constructor;
    return this.then(
      value => Promise.resolve(onDone()).then(() => value),
      reason => Promise.resolve(onDone()).then(() => { throw reason })
    );
  }
  static resolve(value) {
    if (value && value instanceof Promise) {
      return value;
    } else if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise(resolve => {
        then(resolve);
      });

    } else if (value) {
      return new Promise(resolve => resolve(value));
    } else {
      return new Promise(resolve => resolve());
    }
  }
  static reject(value) {
    if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise((resolve, reject) => {
        then(reject);
      });

    } else {
      return new Promise((resolve, reject) => reject(value));
    }
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let fulfilledCount = 0
      const itemNum = promises.length
      const rets = Array.from({ length: itemNum })
      promises.forEach((promise, index) => {
        Promise.resolve(promise).then(result => {
          fulfilledCount++;
          rets[index] = result;
          if (fulfilledCount === itemNum) {
            resolve(rets);
          }
        }, reason => reject(reason));
      })

    })
  }
  static race(promises) {
    return new Promise(function (resolve, reject) {
      for (let i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(function (value) {
          return resolve(value)
        }, function (reason) {
          return reject(reason)
        })
      }
    })
  }
  _handle(callback) {
    if (this.state === 'pending') {
      this.callbacks.push(callback);
      return;
    }

    let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;

    if (!cb) {//如果then中没有传递任何东西
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
      cb(this.value);
      return;
    }

    let ret;

    try {
      ret = cb(this.value);
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
    } catch (error) {
      ret = error;
      cb = callback.reject
    } finally {
      cb(ret);
    }

  }
  _resolve(value) {
    if(this.state !== 'pending') return
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var then = value.then;
      if (typeof then === 'function') {
        then.call(value, this._resolve.bind(this), this._reject.bind(this));
        return;
      }
    }

    this.state = 'fulfilled';//改变状态
    this.value = value;//保存结果
    this.callbacks.forEach(callback => this._handle(callback));
  }
  _reject(error) {
    if(this.state !== 'pending') return
    this.state = 'rejected';
    this.value = error;
    this.callbacks.forEach(callback => this._handle(callback));
  }
}
  1. 深拷贝
function deepCopy(obj){
    let result;
    if(typeof obj == "object"){
        //复杂数据类型
       result = obj.constructor == Array ? [] : {};
        for(let i in obj){
            result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
        }
    }else {
       result = obj;
    }
    return result;
}

21.浏览器进程与线程
https://imweb.io/topic/58e3bfa845e5c13468f567d5

22.设计一个简单的任务队列,要求分别在1,3,4秒后打印出”1“,”2“,”3“

/**
 * 题目
 */
new Quene()
  .task(1000, () => {
    console.log(1);
  })
  .task(2000, () => {
    console.log(2);
  })
  .task(1000, () => {
    console.log(3);
  })
  .start();

function Quene() { ... }

/**
 * 解题1 promise
 */
class Quene {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({
      wait,
      fn,
    });
    return this;
  }
  async start() {
    for (let task of this.tasks) {
      const { wait, fn } = task;
      await new Promise((res, rej) => {
        setTimeout(() => {
          fn();
          res();
        }, wait);
      });
    }
  }
}

/**
 * 解题2 递归
 */
class Quene {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({ wait, fn });
    return this;
  }
  start() {
    const firstTask = this.tasks.shift();
    if (firstTask) {
      setTimeout(() => {
        firstTask.fn();
        this.start();
      }, firstTask.wait);
    }
  }
}

/**
 * 解题3 闭包
 */
class Queue {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({
      wait,
      fn,
    });
    return this;
  }
  start() {
    let int = 0;
    this.tasks.forEach(({ wait, fn }) => {
      setTimeout(() => {
        fn();
      }, (int += wait));
    });
  }
}

  1. 用 setTimeout 实现 setInterval,阐述实现的效果与 setInterval 的差异
function mySetInterval(fn, wait) {
    mySetInterval.timer = setTimeout(() => {
        fn();
        mySetInterval(fn, wait);
    }, wait)
}

mySetInterval.clear = function() {
    clearTimeout(mySetInterval.timer)
}

mySetInterval(() => {
    console.log(11111)
}, 1000)

setTimeout(() => {
    // 5s 后清理
    mySetInterval.clear()
}, 5000)
  1. vue3 中的数据侦测
const rawToReactive = new WeakMap();
const reactiveToRaw = new WeakMap();

/**
 * utils
 * */
function isObject(val) {
  return typeof val === "object";
}
function hasOwn(val, key) {
  const hasOwnProperty = Object.prototype.hasOwnProperty;
  return hasOwnProperty.call(val, key);
}

/**
 * traps
 * */
// get
function createGetter() {
  return function(target,key,receiver) {
    const res = Reflect.get(target,key,receiver);
    console.log('get', key);
    return isObject(res) ? reactive(res) : res;
  }
}
// set
function set(target,key,value,receiver) {
  const hadKey = hasOwn(target, key);
  const oldValue = target[key];
  value = reactiveToRaw.get(value) || value;
  const res = Reflect.set(target, key, value, receiver)
  if(!hadKey || value !== oldValue) {
    console.log('tigger...');
  }
  return res;
}
// handle
const mutableHandlers = {
  get: createGetter(),
  set: set
};
// create reactive object
function createReactiveObject(target, toProxy, toRaw, baseHandlers) {
  let observed = toProxy.get(target);
  // target 生成过 observed,返回 observed
  if(observed !== void 0) {
    return observed;
  };
  // target 是 observed, 返回 target
  if(toRaw.has(target)) {
    return target;
  }
  observed = new Proxy(target, baseHandlers);
  toProxy.set(target, observed);
  toRaw.set(observed, target);
  return observed;
}
// enter
function reactive(target) {
  return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers)
}
上一篇下一篇

猜你喜欢

热点阅读