目录
所有的方法都可以调用我们手写的方法,因此需要挂载在原型上,因此我们使用以下代码进行挂载
Function.prototype.myCall = function () { console.log(' 方法执行 ') }
call方法是改变this指向的一个常用方法,其写法是 func.call(thisArg,att1,att2,...) 。在这里第一个参数是我们要将this改变到哪个实例上,从第二个属性开始,就是我们要传递的参数。因为是直接传递的,所以我们这里不确定有几个参数,因此在重写的时候需要使用 ...args 来进行接收。同时在使用这个参数的时候需要 ...args 来进行结构。下面我们来整理一下思路以及实现吧。
-
- // 1. 定义myCall方法
- Function.prototype.myCall = function (thisArg,...args) {
- // 2. 设置this为原函数
- // thisArg 传入的设置为this的对象
- // 这里的this就是原函数 因为是 原函数.myCall()
- thisArg.f = this
- // 3. 接受剩余参数并返回结果
- const res = thisArg.f(...args)
- // 因为添加了f属性所以要删掉
- delete thisArg.f
- return res
- }
-
- // ------------- 测试代码 ----------------
- const person = {
- name : '张三'
- }
- function func(numA,numB){
- console.log(this);
- console.log(numA,numB);
- return numA + numB
- }
- const res = func.myCall(person, 1, 2)
- console.log('返回的值为:' + res);
-
在上面的代码中,我们可以看到,是使用的 thisArg.f 指向了 this 。但是这样有一个弊端,即你无法确定在 thisArg 中是否存在 f 方法,因此我们使用Symbol进行调优。将myCall()中的代码替换如下:
- //Symbol调优
- // 2. 设置this为原函数
- // thisArg 传入的设置为this的对象
- // 这里的this就是原函数 因为是 原函数.myCall()
- // 4. Symbol调优
- const key = Symbol('key')
- //这里是动态解析key
- thisArg[key] = this
- // 3. 接受剩余参数并返回结果
- const res = thisArg[key](...args)
- // 因为添加了f属性所以要删掉
- delete thisArg[key]
- return res
这里就不附加运行图了,最终的效果也是一样的哦!而且更为的安全可靠,推荐使用这种方法。
apply方法是另一种比较常见的改变this指向的方法,这个方法和call方法一样,都是在调用时改变this的指向,但是 apply 与 call 不同的地方在于,apply接收的第一个参数是thisArg(需要指向的对象),而第二个参数则是一个数组。apply只有这两个参数,这一点是区别于 call 方法的。其余的地方基本上是一样的。下面是实现思路以及具体代码。
这个实现方法其实和myCall的实现方法很相近,不同的是接收参数的时候因为已经传的是数组了,所以我们不需要使用 ... 来接收不确定数量的参数,直接使用args就可以了。
-
- // 1. 定义myCall方法
- Function.prototype.myApply = function (thisArg,args) {
- // 2. 设置this为原函数 直接使用Symbol调优
- // thisArg 传入的设置为this的对象
- // 这里的this就是原函数 因为是 原函数.myCall()
- // 4. Symbol调优
- const key = Symbol('key')
- //这里是动态解析key
- thisArg[key] = this
- // 3. 接受剩余参数并返回结果
- const res = thisArg[key](...args)
- // 因为添加了f属性所以要删掉
- delete thisArg[key]
- return res
- }
-
- // ------------- 测试代码 ----------------
- const person = {
- name : '张三'
- }
- function func(numA,numB){
- console.log(this);
- console.log(numA,numB);
- return numA + numB
- }
- const res = func.myApply(person, [1, 2])
- console.log('返回的值为:' + res);
-
bind 方法是直接区别于 call 方法和 apply 方法的,该方法是在创建时就改变了this的指定,同时返回的是一个新的方法,在调用新方法的时候同样可以传参,这样会和之前方法的参数进行一个拼接合并。该方法不会改变原方法的this指向,具体思路以及实现见下。
-
- // 1. 定义myBind方法
- Function.prototype.myBind = function (thisArg,...args) {
- // 2. 返回绑定this的新函数
- return (...reArgs) => {
- // this :原函数(原函数.myBind)
- //3. 合并绑定和新传入的参数,注意先后顺序
- return this.call(thisArg,...args,...reArgs)
- }
- }
-
- // ------------- 测试代码 ----------------
- const person = {
- name : '张三'
- }
- function func(numA,numB,numC,numD){
- console.log(this);
- console.log(numA,numB,numC,numD);
- return numA + numB + numC + numD
- }
- const bindFunc = func.myBind(person, 1, 2)
- const res = bindFunc(3,4)
- console.log('返回的值为:' + res);
-
call、apply、bind三个方法是改变this指向的重要方法,熟练的使用以及掌握其源码实现原理,能够帮助我们更好地理解和使用这三个方法。同时可以让我们在项目开发过程中规避掉很多不应该的错误,并且提高我们的逻辑思维能力。
因此,学习这三个方法是很有必要性的。希望本文能够对各位小伙伴有所帮助哦~