[记录]我的日常随笔

HTTP

  • [缓存相关]
  • 讲一讲强缓存和协议缓存?
  • 有了【Last-Modified,If-Modified-Since】为何还要有【ETag、If-None-Match】
  • 有关 HTTP 缓存的首部字段说一下
  • [TCP/IP 相关]
  • HTTP 和 TCP 的区别
  • TCP 三次握手和四次挥手?以其存在意义。
  • 在一次传输中它是如何保证每个数据包之间的顺序的?
  • [HTTP 相关]
  • HTTP 请求的什么时候用的对称加密什么时候非对称加密
  • HTTP 中的 keep-alive 有了解吗?
  • HTTP2 特性
  • HTTP/2 对比 HTTP1.1
  • HTTP/2 都有哪些特性?头部压缩的原理?
  • HTTP/2 是怎么解决队头阻塞的
  • HTTP/2 是如何压缩头部的
  • HTTPS 握手
  • 具体说一下 HTTP/2 中的多路复用
  • GET 和 POST 的区别
  • GET 就一定是幂等的吗?
  • 状态码。302.304.301.401.403 的区别?
  • 状态码。204 和 304 分别有什么作用?
  • HTTP 和 HTTPS 握手差异?
  • 为什么说 HTTPS 比 HTTP 安全呢
  • 简单讲了一下非对称加密的握手过程
  • 证书签名过程和如何防止被串改
  • TCP/IP 网络分层模型是怎样分层的
  • OSI 网络分层模型是怎样分层的
  • TCP 和 UDP 区别
  • HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2、HTTP/3 各版本之间的区别?
  • [综合相关]
  • CSRF 跨站请求伪造和 XSS 跨站脚本攻击是什么?
  • 如果让你去实现一个 CSRF 攻击你会怎做?
  • 如果使用 jsonp 的话会有什么安全问题吗?
  • 你是如何解决跨域的?都有几种?
  • 为什么说 GET 会留下历史记录?
  • 从“在浏览器输入域名”到“页面静态资源完全加载”的整个流程
  • 假设有两个子项目,他们需要共用同一个用户体系如何保证关掉页面之后打开另一个项目用户还是登录状态?

JS

  • Promise 实现
  • Generator 实现
  • async、await 实现
  • 垃圾回收中的堆和栈的区别
  • 0.1 + 0.2 != 0.3 背后的原理?
  • 手写 vue2/3 具体实现
  • 手写继承
  • requestAnimationFrame 属于宏任务还是微任务
  • 动态表单实现
  • null 为什么被 typeof 错误的判断为了'object'
  • 洋葱模型
  • 实现对象深拷贝
  • 实现数组去重
  • 实现一个 apply/call/bind 方法
  • 实现一个函数,URL 参数解析为对象
  • 实现一个 trim
  • 实现柯理化函数
  • 实现 loadsh 的 get 方法 (_.get('a.b.c'))
  • 查找字符串中的最长无重复子串
  • 两个数组的并集与交集
  • 排序算法实现
  • 数组扁平化

Vue

  • 双向绑定原理
  • nextTick 原理
  • nextTick 中的 waiting 是什么时候变为 true 的呢
  • 虚拟 DOM
  • Object.defineProperty()有什么缺点?Vue3 为什么用 Proxy
  • Vue3 有哪些新的 API 或者有做哪些优化?
  • 说一下 Vue 的 diff 算法
  • diff 算法的缺点

Devops

  • webpack 的构建流程、自定义 loader,插件原理、HMR 的实现、打包原理,常用的插件以及性能优化
  • 单元测试做过吗?你是怎么做的?
  • 对 tree-shaking 的了解(虽然生产模式下默认开启,但是由于经过 babel 编译全部模块被封装成 IIFE IIFE 存在副作用无法被 tree-shaking 掉 需要配置 { module: false }和 sideEffects: false rollup 和 webpack 的 shaking 程度不同,以一个 Class 为例子)
  • webpack-dev-server 原理和如何处理跨域

书单

  • 《 网络是怎样连接的 》
  • 《 图解 HTTP 》
  • 《 图解 TCP/IP 》
  • 《 极客时间- 透视 HTTP 协议 》
  • 《 TCP/IP 详解(第一卷)》
  • 《 浏览器原理 》
  • 《 DevOps 实战笔记 》
  • 《 Nginx 核心知识 100 讲 》
  • 《 学习 Javascipt 数据结构与算法 》
  • 《 JavaScript 版 数据结构与算法 》
  • 《 极客时间- 数据结构与算法之美 》
  • 《 极客时间- 算法面试通关 》

代码实现

  1. 手写节流防抖
/**
 * 节流
 * @param {Func} callback 需要节流的函数
 * @param {Number} wait 等待毫秒数
 * 执行一次后,一段时间内不再执行
 */
function throttle(func, wait) {
  let timer = null;
  return function (...args) {
    if (timer === null) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, wait);
    }
  };
}
/**
 * 防抖
 * @param {Func} callback 需要防抖的函数
 * @param {Number} wait 等待毫秒数
 * 一段时间内,取最后一次执行
 */
function debounce(func, wait) {
  let timer = null;
  return function (...args) {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      func.apply(this, args);
    }, 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 / new
// call
Function.prototype.call2 = function (target, ...args) {
  target._func = this;
  const ret = target._func(...args);
  delete target._func;
  return ret;
};
// apply
Function.prototype.apply2 = function (target, args=[]) {
  target._func = this;
  const ret = target._func(...args);
  delete target._func;
  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;
}
// new
function _new(target, ...args) {
    const obj = Object.create(target.prototype);
    const ret = target.apply(obj, args);
    return typeof ret === 'object' ? ret : obj;
}

8.Object.create 的模拟实现

Object.create = function(target) {
  function _func () {};
  _func.prototype = target;
  return new _func();
}
  1. instanceof 模拟实现
function _instanceof(left, right) {
  let proto = left.__proto__;
  let prototype = right.prototype;
  while (true) {
    if (proto === null) return false;
    if (proto === prototype) return true;
    proto = proto.__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);

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

  2. 实现一个 Promise 《图解 Promise 实现原理

// Promise 简单的实现
function APromise(fn) {
  const that = this;
  that.status = "pending"; // Promise初始状态为pending
  that.data = undefined; // Promise的值
  that.resCbs = []; // APromise resolve回调函数集合
  that.rejCbs = []; // APromise reject回调函数集合

  function resolve(data) {
    if (that.status === "pending") {
      that.status = "resolved";
      that.data = data;
      setTimeout(() => {
        that.resCbs.forEach((cb) => cb(data));
      });
    }
  }

  function reject(data) {
    if (that.status === "pending") {
      that.status = "rejected";
      that.data = data;
      setTimeout(() => {
        that.rejCbs.forEach((cb) => cb(data));
      });
    }
  }

  try {
    fn(resolve, reject); // 执行传进来的函数,传入resolve, reject参数
  } catch (e) {
    reject(e);
  }
}

APromise.prototype.then = function (onRes = (v) => v, onRej = (j) => j) {
  const that = this;

  if (that.status === "resolved") {
    // 这里promise的状态已经确定是resolved,所以调用onResolved
    return new APromise((resolve, reject) => {
      setTimeout(() => {
        try {
          // ret是onRes的返回值
          const ret = onRes(that.data);
          if (ret instanceof APromise) {
            // 如果ret是一个promise,则取其值作为新的promise的结果
            ret.then(resolve, reject);
          } else {
            // 否则,以它的返回值作为新的promise的结果
            resolve(ret);
          }
        } catch (e) {
          // 如果出错,以捕获到的错误作为promise2的结果
          reject(e);
        }
      });
    });
  }

  // 这里的逻辑跟前面一样,不再赘述
  if (that.status === "rejected") {
    return new APromise((resolve, reject) => {
      setTimeout(() => {
        try {
          const ret = onRej(that.data);
          if (ret instanceof APromise) {
            ret.then(resolve, reject);
          } else {
            reject(ret);
          }
        } catch (e) {
          reject(e);
        }
      });
    });
  }

  if (that.status === "pending") {
    // 如果当前的Promise还处于pending状态,则不能确定调用
    // onResolved还是onRejecte,只能等到Promise状态确定后,
    // 才能确定如何处理
    return new APromise((resolve, reject) => {
      that.resCbs.push(() => {
        setTimeout(() => {
          try {
            const ret = onRes(that.data);
            if (ret instanceof APromise) {
              ret.then(resolve, reject);
            } else {
              resolve(ret);
            }
          } catch (e) {
            reject(e);
          }
        });
      });

      that.rejCbs.push(() => {
        setTimeout(() => {
          try {
            const ret = onRej(that.data);
            if (ret instanceof APromise) {
              ret.then(resolve, reject);
            } else {
              reject(ret);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    });
  }
};

// 顺便实现一下catch方法
APromise.prototype.catch = function (onRej) {
  return this.then(null, onRej);
};

const p = new APromise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 2000);
});

p.then(function (v) {
  console.log(v);
  return 2;
})
  .then(function (v) {
    console.log(v);
    return new APromise(function (resolve, reject) {
      setTimeout(function () {
        resolve(3);
      }, 3000);
    });
  })
  .then(function (v) {
    console.log(v);
  });


/**
 *实现promise中的all方法
 */
Promise.prototype.all = function (array) {
  judgeType(array);
  let count = 0;
  const total = array.length;
  const ret = [];
  return new Promise((resolve, reject) => {
    array.forEach((element) => {
      element.then((res) => {
        ret.push(res);
        count++;
        if (count === total) {
          resolve(ret);
        }
      });
      element.catch((err) => {
        reject(err);
      });
    });
  });
};
/**
 *类型的判断
 */
function judgeType(array) {
  if (array instanceof Array) {
    array.forEach((item) => {
      if (!(item instanceof Promise)) {
        throw "该参数的每一项必须是Promise的实例";
      }
    });
  } else {
    throw "必须是数组哦";
  }
}

var p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);
all = function (promises) {
  const total = promises.length;
  const ret = [];
  let count = 0;
  return new Promise((resolve, reject) => {
    promises.forEach((item) => {
      item.then((res) => {
        ret.push(res);
        count++;
        if (count === total) {
          return resolve(ret);
        }
      });
      item.catch((err) => {
        return reject(err);
      });
    });
  });
};
all([p1, p2, p3]).then(function (results) {
    //then方法不会被执行
    console.log(results);
}).catch(function (e){
    //catch方法将会被执行,输出结果为:2
    console.log(2);
});
/**
 *实现promise中的race方法
 */
Promise.prototype.race = function (promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((item) => {
      Promise.resolve(item).then(
        (res) => {
          return resolve(res);
        },
        (err) => {
          return reject(err);
        }
      );
    });
  });
};
var p1 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 500, "500");
});
var p2 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 600, "600");
});
race([p1, p2]).then(function (result) {
  console.log(result); // '2018' 因为2018更快
});
/**
 *实现promise中的finally方法
 */
Promise.prototype.finally = function (onFinally) {
  return this.then(
    /* onFulfilled */
    (res) => Promise.resolve(onFinally()).then(() => res),
    /* onRejected */
    (err) =>
      Promise.resolve(onFinally()).then(() => {
        throw err;
      })
  );
};

// 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. 深拷贝
// 小细节 -> 需要考虑一下循环引用的情况 -> WeakMap
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;
}

function deepCopy2(target, weakMaps = new WeakMap()) {
  if (typeof target !== "object" || target === null) {
    return target;
  }
  if (weakMaps.has(target)) return weakMaps.get(target);
  const res = Array.isArray(target) ? [] : {};
  weakMaps.set(target, res);
  for (let key in target) {
    res[key] = deepCopy(target[key], weakMaps);
  }
  return res;
}

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)
}
  1. Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?
  • 优缺点
    1. Object.defineProperty 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
    2. Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象。
    3. Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
  1. 实现 async await
function co(genFun) {
    return new Promise((resolve, reject) => {
        const gen = genFun();
        function next(...params){
            const {value, done} = gen.next(...params);
            if(done){
                return resolve(value)
            } else {
                value.then((...args)=>next(...args));
            }
        };
        next();
    })
};
// test
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000));
function* testG() {
  // await被编译成了yield
  const data = yield getData()
  console.log('data: ', data);
  const data2 = yield getData()
  console.log('data2: ', data2);
  return 'success'
}
co(testG).then(res=>{console.log('res', res)});
// logs
data:  data
data2:  data
res success
  1. LazyMan
// 实现LazyMan
LazyMan('jack').sleep(3000).eat('篮球').eat('rap').eat('唱、跳')
// hi,I'm jack
// 阻塞3s
// 篮球
// rap
// 唱、跳

LazyMan('x1').eat('高').sleep(5000).eat('富').eat('帅')
// hi,I'm x1
// 高
// 阻塞5s
// 富
// 帅

LazyMan('lurenjia').sleepFirst(3000).eat('吹').eat('牛')
// 阻塞3s
// hi,I'm lurenjia
// 吹
// 牛

class CraeteLazyMan {
  constructor(name) {
    this.queue = [];
    const nameTask = () => {
      console.log(`ADI-LOG => name`, name);
      this.task();
    };
    this.queue.push(nameTask);
    setTimeout(() => {
      this.task();
    }, 0);
  }
  task() {
    const fun = this.queue.shift();
    fun && fun();
  }
  sleep(time) {
    const _task = () => {
      setTimeout(() => {
        this.task();
      }, time);
    };
    this.queue.push(_task);
    return this;
  }
  sleepFirst(time) {
    const _task = () => {
      setTimeout(() => {
        this.task();
      }, time);
    };
    this.queue.unshift(_task);
    return this;
  }
  eat(str) {
    const _task = () => {
      console.log(`ADI-LOG => eat`, str);
      this.task();
    };
    this.queue.push(_task);
    return this;
  }
}

function LazyMan(name = "") {
  return new CraeteLazyMan(name);
}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。