「中高级前端面试」JavaScript手写代码无敌秘籍((2)

Function.prototype.call2 = function(content = window) { content.fn = this; let args = [...arguments].slice(1); let result = content.fn(...args); delete content.fn; return result; } let foo = { value: 1 } function bar(name, age) { console.log(name) console.log(age) console.log(this.value); } bar.call2(foo, 'black', '18') // black 18 1

4.2 Function.apply的模拟实现

apply()的实现和call()类似,只是参数形式不同。直接贴代码吧:

Function.prototype.apply2 = function(context = window) { context.fn = this let result; // 判断是否有第二个参数 if(arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result }

5. 实现一个Function.bind()

bind()方法:

会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )

此外,bind实现需要考虑实例化后对原型链的影响。

Function.prototype.bind2 = function(content) { if(typeof this != "function") { throw Error("not a function") } // 若没问参数类型则从这开始写 let fn = this; let args = [...arguments].slice(1); let resFn = function() { return fn.apply(this instanceof resFn ? this : content,args.concat(...arguments) ) } function tmp() {} tmp.prototype = this.prototype; resFn.prototype = new tmp(); return resFn; }

6. 实现一个继承

寄生组合式继承

一般只建议写这种,因为其它方式的继承会在一次实例中调用两次父类的构造函数或有其它缺点。

核心实现是:用一个 F 空的构造函数去取代执行了 Parent 这个构造函数。

function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log('parent name:', this.name); } function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } function create(proto) { function F(){} F.prototype = proto; return new F(); } Child.prototype = create(Parent.prototype); Child.prototype.sayName = function() { console.log('child name:', this.name); } Child.prototype.constructor = Child; var parent = new Parent('father'); parent.sayName(); // parent name: father var child = new Child('son', 'father');

7. 实现一个JS函数柯里化

什么是柯里化?

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

函数柯里化的主要作用和特点就是参数复用、提前返回和延迟执行。

7.1  通用版

function curry(fn, args) { var length = fn.length; var args = args || []; return function(){ newArgs = args.concat(Array.prototype.slice.call(arguments)); if (newArgs.length < length) { return curry.call(this,fn,newArgs); }else{ return fn.apply(this,newArgs); } } } 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);

7.2 ES6骚写法

const curry = (fn, arr = []) => (...args) => ( arg => arg.length === fn.length ? fn(...arg) : curry(fn, arg) )([...arr, ...args]) let curryTest=curry((a,b,c,d)=>a+b+c+d) curryTest(1,2,3)(4) //返回10 curryTest(1,2)(4)(3) //返回10 curryTest(1,2)(3,4) //返回10

8. 手写一个Promise(中高级必考)

我们来过一遍Promise/A+规范:

三种状态pending| fulfilled(resolved) | rejected

当处于pending状态的时候,可以转移到fulfilled(resolved)或者rejected状态

当处于fulfilled(resolved)状态或者rejected状态的时候,就不可变。

必须有一个then异步执行方法,then接受两个参数且必须返回一个promise:

// onFulfilled 用来接收promise成功的值 // onRejected 用来接收promise失败的原因 promise1=promise.then(onFulfilled, onRejected);

8.1 Promise的流程图分析

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

来回顾下Promise用法:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/b22226a7e413d1fb406724a2dfb1fc76.html