面试中常考的源码实现

【面试中常考的源码实现】面试中常被考到的手撕代码:

  1. call/apply/bind
  2. instanceof
  3. 深拷贝
  4. 基于 ES5/ES6 实现“双向绑定”
  5. promise相关
1. call/apply/bind的代码实现 call
Function.prototype.call2 = function(context) { if (typeof this !== "function") { throw new TypeError("Error"); }// 默认上下文是window context = context || window; // 保存默认的fn const { fn } = context; // 将函数本身作为对象context的属性调用,自动绑定this context.fn = this; const args = [...arguments].slice(1); const result = context.fn(...args); // 恢复默认的fn context.fn = fn; return result; };

apply
Function.prototype.apply2 = function(context) { if (typeof this !== "function") { throw new TypeError("Error"); }context = context || window; const { fn } = context; context.fn = this; let result; if (Array.isArray(arguments[1])) { // 通过...运算符将数组转换为用逗号分隔的参数序列 result = context.fn(...arguments[1]); } else { result = context.fn(); }context.fn = fn; return result; };

bind
Function.prototype.bind2 = function(context) { if (typeof this !== "function") { throw new TypeError("Error"); }const that = this; // 保留之前的参数,为了下面的参数拼接 const args = [...arguments].slice(1); return function F() { // 如果被new创建实例,不会被改变上下文! if (this instanceof F) { return new that(...args, ...arguments); }// args.concat(...arguments): 拼接之前和现在的参数 // 注意:arguments是个类Array的Object, 用解构运算符..., 直接拿值拼接 return that.apply(context, args.concat(...arguments)); }; };

2.instanceof代码实现
function instanceof2(left, right) { let prototype = right.prototype; // 沿着left的原型链, 看看是否有何prototype相等的节点 left = left.__proto__; while (1) { if (left === null || left === undefined) { return false; } if (left === prototype) { return true; } left = left.__proto__; } }

3.深拷贝
function cloneArr(src, target) { for (let item of src) { if (Array.isArray(item)) { target.push(cloneArr(item, [])); } else if (typeof item === "object") { target.push(deepClone(item, {})); } else { target.push(item); } } return target; } function deepClone(src, target) { const keys = Reflect.ownKeys(src); let value = https://www.it610.com/article/null; for (let key of keys) { value = src[key]; if (Array.isArray(value)) { target[key] = cloneArr(value, []); } else if (typeof value ==="object") { // 如果是对象而且不是数组, 那么递归调用深拷贝 target[key] = deepClone(value, {}); } else { target[key] = value; } }return target; }

4.基于 ES5/ES6 实现“双向绑定” ES5的Object.defineProperty()
Document - 锐客网 > const obj = { value: "" }; function onKeyUp(event) { obj.value = https://www.it610.com/article/event.target.value; }// 对 obj.value 进行拦截 Object.defineProperty(obj,"value", { get: function() { return value; }, set: function(newValue) { value = https://www.it610.com/article/newValue; document.querySelector("#value").innerHTML = newValue; // 更新视图层 document.querySelector("input").value = https://www.it610.com/article/newValue; // 数据模型改变 } }); 值是:id="value">

ES6的proxy
Document - 锐客网 > const obj = {}const newObj = new Proxy(obj, { get: function(target, key, receiver) { return Reflect.get(target, key, receiver) }, set: function(target, key, value, receiver) { if(key === 'value') { document.querySelector('#value').innerHTML = value document.querySelector('input').value = https://www.it610.com/article/value } return Reflect.set(target, key, value, receiver) } })function onKeyUp(event) { newObj.value = event.target.value }值是:id="value">

    推荐阅读