分享一个基础面试题---手写call

分享一个基础面试题---手写call

手写call笔记

call():在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。

let foo = {
   
	value:1
};
function bar(){
   
	console.log(this.value);
}
bar.call(foo);//1

注意两点:

  1. call改变了this的指向,指向到foo;
  2. bar 函数执行了;

第一步

上述方式等同于:

let foo = {
   
	value:1;
	bar:function(){
   
		console.log(this.value)
	}
};
foo.bar();//1

这个时候this就指向了foo,但是这样却给foo对象本身添加了一个属性,所以我们用delete再删除它即可。
所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性;
  2. 执行该函数;
  3. 删除该函数;

以上个例子为例,就是:

//第一步
//fn 是对象的属性名,反正最后也要删除它,所以起什么名字都可以。
foo.fn = bar
//第二步
foo.fn()
//第三步
delete foo.fn

根据上述思路,提供一版:

//第一版
//将foo作为context参数传递
Function.prototype.call2 = function(context){
   
	//首先要获取调用call的函数,用this可以获取
	//将函数设为对象的属性
	context.fn = this;
	//执行该函数
	context.fn();
	//删除该函数
	delete context.fn;
}

第二步

call除了可以指定this,还可以指定参数

var foo = {
   
	value:1
};
function bar(name,age){
   
	console.log(name);
	console.log(age);
	console.log(this.value);
}
bar.call(foo,'ken',18);

可以从Arguments对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
上述代码的Arguments中取第二个到最后一个参数。

//以上个例子为例,此时的arguments为:
// arguments = {
   
//		0:foo,
//		1:'ken',
//		2:18,
//		length:3
//}
//因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1,len = arguments.length;i<len;i++){
   
	args.push('arguments['+i+']');
}
//执行后args 为["arguments[1]","arguments[2]","arguments[3]"]

接下来使用eval拼接成一个函数

eval('context.fn('+args+')')

考虑到目前大部分浏览器在console中限制eval的执行,也可以使用rest
此处代码为:

//第二版
Function.prototype.call2 = function(context){
   
	context.fn = this;
	let arg = [...arguments].slice(1);
	context.fn(...arg);
	delete context.fn;
}
//测试一下
var foo = {
   
	value:1
};
function bar(name,age){
   
	console.log(name);
	console.log(age);
	console.log(this.value);
}
bar.call2(foo,'ken',18)
//ken
//18
//1

第三步

  1. this参数可以传null,当为null的时候,视为指向window
    举个例子:
var value = 1;
function bar(){
   
	console.log(this.value);
}
bar.call(null);//1
  1. 针对函数,可以实现返回值
var obj = {
   
	value:1
};
function bar(name,age){
   
	return{
   
	value:this.value,
	name:name,
	age:age
	}
}
console.log(bar.call(obj,'ken',18));
//Object{
   
//		value:1,
//		name:'ken',
//		age:18
//}

第三版:

Function.prototype.call3=function(context){
   
	//1.this为null,也可以写为=>context ?? window 或者 context=context??window
	var context = context || window;
	context.fn = this;
	let arg = [...arguments].slice(1)
	let result = context.fn(...arg)
	delete context.fn
	//2.有返回值
	return result
}
//测试一下
var value = 2;
var obj = {
   
	value:1
}
function bar(name,age){
   
	console.log(this.value);
		return{
   
			value:this.value,
			name:name,
			age:age
		}
}
bar.call3(null);//2
console.log(bar.call3(obj,'ken',18));

//1
//Object{
   
//		value:1,
//		name:'ken',
//		age:18
//}

这边给出的简化写法:

Function.prototype.call3 = function(context,..args){
   
	//判断是否是undefined和null
	if (typeof context === 'undefined' || context === null){
   
		context = window
	}
	//每个从Symbol()返回的symbol值都是唯一的
	let fnSymbol = Symbol()
	context[fnSymbol] = this
	//入参...args === [...arguments].slice(1);
	let fn = context[fnSymbol](...args)
	//删除目的是不污染原来数据
	delete context[fnSymbol]
	return fn
}

可能会有新手宝宝们看完觉得还是很晦涩,可以动手写一遍试试,不行再多写两遍,好记性不如烂键盘,脑子再快也不如肌肉记忆哈哈哈~
当然也可以留言讨论啦~
在这里插入图片描述

相关推荐

  1. 7.call函数

    2023-12-07 08:46:02       54 阅读
  2. 面试soft_nms

    2023-12-07 08:46:02       58 阅读
  3. 代码基础篇】

    2023-12-07 08:46:02       26 阅读
  4. 面试一个睡眠函数

    2023-12-07 08:46:02       55 阅读
  5. 一个vuex?

    2023-12-07 08:46:02       56 阅读
  6. 2024前端面试篇】

    2023-12-07 08:46:02       20 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-07 08:46:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-07 08:46:02       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-07 08:46:02       82 阅读
  4. Python语言-面向对象

    2023-12-07 08:46:02       91 阅读

热门阅读

  1. 4.1 Docker 容器化和镜像管理

    2023-12-07 08:46:02       51 阅读
  2. *p++和(*p)++的区别

    2023-12-07 08:46:02       50 阅读
  3. 【使用uniapp完成微信小程序的图片下载到本机】

    2023-12-07 08:46:02       63 阅读
  4. Vue实战(十):对数组数据的拆分和分组合并

    2023-12-07 08:46:02       56 阅读
  5. 有基础转Go语言学习笔记(2. 基本数据结构篇)

    2023-12-07 08:46:02       48 阅读
  6. C++的文件读写

    2023-12-07 08:46:02       69 阅读
  7. C++11改进观察者模式

    2023-12-07 08:46:02       57 阅读
  8. [leetcode 差分数组] 拼车 M

    2023-12-07 08:46:02       58 阅读
  9. ElasticSearch 查询优化手段有哪些?

    2023-12-07 08:46:02       50 阅读
  10. 持续集成部署-k8s-高级调度-亲和力

    2023-12-07 08:46:02       40 阅读