2019-08-07 15:16:04 3407浏览
今天千锋扣丁学堂HTML5培训老师给大家分享一篇关于前端开发岗位面试中常考的源代码实现,下面我们一起来看一下吧。function test(arg1, arg2) { console.log(arg1, arg2) console.log(this.a, this.b) } run.call({ a: 'a', b: 'b' }, 1, 2)
let obj = { a: 'a', b: 'b', test: function (arg1, arg2) { console.log(arg1, arg2) // this.a 就是 a; this.b 就是 b console.log(this.a, this.b) } } obj.test(1, 2)
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 } // 以下是测试代码 function test(arg1, arg2) { console.log(arg1, arg2) console.log(this.a, this.b) } test.call2({ a: 'a', b: 'b' }, 1, 2)
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 } /** * 以下是测试代码 */ function test(arg1, arg2) { console.log(arg1, arg2) console.log(this.a, this.b) } test.apply2({ a: 'a', b: 'b' }, [1, 2])
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)) } } /** * 以下是测试代码 */ function test(arg1, arg2) { console.log(arg1, arg2) console.log(this.a, this.b) } const test2 = test.bind2({ a: 'a', b: 'b' }, 1) // 参数 1 test2(2) // 参数 2
/** * 数组的深拷贝函数 * @param {Array} src * @param {Array} target */ 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 } /** * 对象的深拷贝实现 * @param {Object} src * @param {Object} target * @return {Object} */ function deepClone(src, target) { const keys = Reflect.ownKeys(src) let value = 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 }
// 这个对象a是一个囊括以上所有情况的对象 let a = { age: 1, jobs: { first: "FE" }, schools: [ { name: 'shenda' }, { name: 'shiyan' } ], arr: [ [ { value: '1' } ], [ { value: '2' } ], ] }; let b = {} deepClone(a, b) a.jobs.first = 'native' a.schools[0].name = 'SZU' a.arr[0][0].value = '100' console.log(a.jobs.first, b.jobs.first) // output: native FE console.log(a.schools[0], b.schools[0]) // output: { name: 'SZU' } { name: 'shenda' } console.log(a.arr[0][0].value, b.arr[0][0].value) // output: 100 1 console.log(Array.isArray(a.arr[0])) // output: true
<!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> <script> const obj = { value: '' } function onKeyUp(event) { obj.value = event.target.value } // 对 obj.value 进行拦截 Object.defineProperty(obj, 'value', { get: function() { return value }, set: function(newValue) { value = newValue document.querySelector('#value').innerHTML = newValue // 更新视图层 document.querySelector('input').value = newValue // 数据模型改变 } }) </script> </head> <body> <p> 值是:<span id="value"></span> </p> <input type="text" onkeyup="onKeyUp(event)"> </body> </html> ES6的Proxy
<!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> <script> 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 = value } return Reflect.set(target, key, value, receiver) } }) function onKeyUp(event) { newObj.value = event.target.value } </script> </head> <body> <p> 值是:<span id="value"></span> </p> <input type="text" onkeyup="onKeyUp(event)"> </body> </html>
/** * 判断left是不是right类型的对象 * @param {*} left * @param {*} right * @return {Boolean} */ 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__; } } /** * 测试代码 */ console.log(instanceof2([], Array)) // output: true function Test(){} let test = new Test() console.log(instanceof2(test, Test)) // output: true
// 数组置空: // arr = []; arr.length = 0; arr.splice(0, arr.length) class Event { constructor() { this._cache = {}; } // 注册事件:如果不存在此种type,创建相关数组 on(type, callback) { this._cache[type] = this._cache[type] || []; let fns = this._cache[type]; if (fns.indexOf(callback) === -1) { fns.push(callback); } return this; } // 触发事件:对于一个type中的所有事件函数,均进行触发 trigger(type, ...data) { let fns = this._cache[type]; if (Array.isArray(fns)) { fns.forEach(fn => { fn(...data); }); } return this; } // 删除事件:删除事件类型对应的array off(type, callback) { let fns = this._cache[type]; // 检查是否存在type的事件绑定 if (Array.isArray(fns)) { if (callback) { // 卸载指定的回调函数 let index = fns.indexOf(callback); if (index !== -1) { fns.splice(index, 1); } } else { // 全部清空 fns = []; } } return this; } } // 以下是测试函数 const event = new Event(); event .on("test", a => { console.log(a); }) .trigger("test", "hello");
【关注微信公众号获取更多学习资料】 【扫码进入HTML5前端开发VIP免费公开课】