这是我参与更文挑战的第 3 天,活动详情查看 更文挑战
这个系列也没啥花头,就是来整平时面试的一些手写函数,考这些简单实现的好处是能看出基本编码水平,且占用时间不长,更全面地看出你的代码实力如何。一般不会出有很多边界条件的问题,那样面试时间不够用,考察不全面。
平时被考到的 api 如果不知道或不清楚,直接问面试官就行, api 怎么用这些 Google 下谁都能马上了解的知识也看不出水平。关键是在实现过程,和你的编码状态、习惯、思路清晰程度等。
注意是简单实现,不是完整实现,重要的是概念清晰和实现思路清晰,建议
先解释清除概念
=>写用例
=>写伪代码
=>再实现具体功能
,再优化
,一步步来。
12. call
是什么
MDN:
call()
方法使用一个指定的 this 值
和单独给出的一个或多个参数
来调用一个函数。
关键点有这几个
- 函数被执行了
- 指定 this 值
- 可以传参
可以说这是一种指定 this 的
函数调用方式。
语法
function.call(thisArg, arg1, arg2, ...)
参数
- thisArg
可选的
。在 function 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
- arg1, arg2, ...
- 指定的参数列表。
- 返回值
- 使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
- 描述
call()
允许为不同的对象分配和调用属于一个对象的函数/方法。call()
提供新的 this 值给当前调用的函数/方法。你可以使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。
如果对 this 指向问题不甚了解,可以先移步这篇 一文说透 JS 中的 this 绑定规则
简单手写实现
实现
- 写个测试用例先
var boy = {
height: 185
};
function say(name) {
console.log(this.height);
return {
height: this.height,
name: name,
}
}
// 原生 call 的效果
// 指定 this 为 boy 对象,所以 this.height 打印为 185, 并指定 name 参数
say.call(boy, 'Keal') // 185
// say 方法返回对象,可以打印
console.log(say.call(boy, 'Keal'))
// 185
// { height: 185, name: 'Keal' }
我们可以思考下
- 我们如果不用 call 调用 ,这个 say 就是个普通方法,那么这里面 this 指向全局。
- boy 中是
不含 say 方法的
,但我们又想打印出 boy 对象的 height
say.call(boy, 'Keal')
say 方法调用中间加了 call,就是指定了 say 方法调用
的this
,即第一个参数boy
,后面的就是其他传递的参数。
- 实现主逻辑
Function.prototype.myCall = function (context, ...args) {
// 如果不传入 上下文对象 浏览器下使用 window 对象
var context = context || window;
// 使用 Symbol 是防止原有同名属性的覆盖
const func = Symbol()
// 注意你是从 say 上调用的 myCall 所以当前 this 就是指向 say 这个 function
// console.log(this) // [Function: say]
// 我们给 指定的 上下文对象新建一个方法 func, 现在 boy 上有 say 方法了
context.func = this;
// 用传入的剩余参数调用这个方法,并存储调用结果
let res = context.func(...args)
// 调用完后删除该方法
delete context.func
// 返回调用结果
return res;
}
var boy = {
height: 185
};
function say(name) {
console.log(this.height);
return {
value: this.height,
name: name,
}
}
say.myCall(boy, 'Keal') // 185
console.log(say.myCall(boy, 'Keal'))
// 185
// { value: 185, name: 'Keal' }
13. apply
是什么
MDN:
apply()
方法调用一个具有给定this值
的函数,以及以一个数组
(或类数组对象)的形式提供的参数。
call()
方法的作用和 apply()
方法类似,区别就是 call() 方法接受的是参数列表,而 apply() 方法接受的是一个参数数组。
语法
func.apply(thisArg, [argsArray])
参数/不同之处
- argsArray
可选的
。一个数组或者类数组对象
,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
简单手写实现
实现
Function.prototype.myApply = function (context, arrArgs) {
// 如果不传入 上下文对象 浏览器下使用 window 对象
var context = context || window;
// 使用 Symbol 是防止原有同名属性的覆盖
const func = Symbol()
// 注意你是从 say 上调用的 myApply 所以当前 this 就是 say 这个 function
// console.log(this) // [Function: say]
// 我们给 指定的 上下文对象新建一个方法 func, 现在 boy 上有 say 方法了
context.func = this;
// 用传入的剩余参数调用这个方法,并存储调用结果
let res = arrArgs ? context.func(...arrArgs) : context.func()
// 调用完后删除该方法
delete context.func
// 返回调用结果
return res;
}
var boy = {
height: 185
};
function say(name, age) {
console.log(this.height);
console.log(name)
return {
value: this.height,
name: name,
age: age
}
}
say.myApply(boy, ['Keal', 18])
// 185
// Keal
console.log(say.myApply(boy, ['More', 25]))
// 185
// More
// { value: 185, name: 'Keal' }
今天就到这里,下篇讲讲 bind 的实现。
另外向大家着重推荐下另一个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列 记得点赞哈
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧