三种改变this指向操作

call

手写实现:

Function.prototype.myCall = function(thisArg,...args){
  if(typeof this != 'function'){
    throw new TypeError('error')
  }
  const fn = Symbol('fn')
  //如果thisArg本身就有一个方法叫做fn怎么办?那不是调用call之后,
  //就会把它本身这个方法删掉了么?有的朋友会说,那起一个复杂点的函数名,
  //保证其他人不会起这么少见的名称不就完了么?不行,这也不能保证万无一失。
  thisArg = thisArg || window
  thisArg[fn] = this
  const result = thisArg[fn](...args)
  delete thisArg[fn]
  return result
}

apply

手写实现:

Function.prototype.myApply = function (context,args){
  //Function是构造函数,Function.prototype指向该构造函数的原型对象,
  //Function.prototype.myApply在该对象实例上写一个函数方法
  //该函数传递两个参数:context(如果不传就是给window,也可以用es6给参数设置默认参数)
  //args也要做出来
  context = context || window
  args = args ? args : []

  const key = Symbol()
  context[key] = this
  //通过隐式绑定的方式调用函数
  const result = context[key](...args)
  //删除添加的属性
  delete context[key]
  //返回函数调用的返回值
  return result
}

bind

手写实现:

// 定义这个方法为myBind
Function.prototype.myBind = function(thisArg) {
  if (typeof this !== 'function') {
    return;
  }
  var _self = this;
  var args = Array.prototype.slice.call(arguments, 1)
  var fnBound = function () {
    // 检测 New
    // 如果当前函数的this指向的是构造函数中的this 则判定为new 操作
    var _this = this instanceof _self ? this : thisArg;
    return _self.apply(_this, args.concat(Array.prototype.slice.call(arguments)));
  }
  // 为了完成 new操作
  // 还需要做一件事情 执行原型  (思考题,为什么?)
  fnBound.prototype = this.prototype;
  return fnBound;
}

(思考题,为什么?)
this instanceof fBound这句话中的this,如果是在new关键字调用情况下,会指向newObj,而newObj就是fBound的实例,this instanceof fBound就是true,我们不再使用thatArg作为greeting的this,而是直接使用newObj作为greeting的this 。而当做普通函数调用的时候,this instanceof fBound就是false,greeting中的this依然指向 thatArg。

我们已经满足的区别的第一点,区别的第二点就是通过fBound.prototype = thatFunc.prototype;来实现。如果没有这句话,在new关键字调用下,newObj“继承”自Object;

### JavaScript改变 `this` 指向三种方法 在 JavaScript 中,可以通过 `call()`、`apply()` 和 `bind()` 方法来改变函数内部的 `this` 指向。以下是这三种方法的具体介绍: #### 1. 使用 `call()` 方法 `call()` 方法用于调用一个已有的函数,并指定该函数内的 `this` 值以及传递给它的参数。其基本语法如下: ```javascript function.call(thisArg, arg1, arg2, ...) ``` 其中,`thisArg` 表示函数运行时作为 `this` 的对象,后续参数则是依次传递给目标函数的实际参数。 例如: ```javascript const obj = { name: 'Alice' }; function greet(message) { console.log(`${message}, my name is ${this.name}`); } greet.call(obj, 'Hello'); // 输出: Hello, my name is Alice ``` 这种方法不仅能够改变 `this` 指向,还支持立即执行函数并传入多个独立参数[^1]。 --- #### 2. 使用 `apply()` 方法 `apply()` 方法的功能与 `call()` 似,但它接受的是一个数组(或数组结构),用来表示传递给目标函数的参数集合。其基本语法如下: ```javascript function.apply(thisArg, [argsArray]) ``` 这里 `[argsArray]` 是一个包含所有实际参数的数组。 例如: ```javascript const numbers = [50, 60, 70]; console.log(Math.max.apply(null, numbers)); // 输出: 70 ``` 通过这种方式,可以方便地将一组数据一次性传递给某个函数处理[^4]。 需要注意的是,在某些情况下,比如求数组的最大值或者最小值时,使用 `apply()` 可以简化代码逻辑[^2]。 --- #### 3. 使用 `bind()` 方法 不同于前两者会直接触发函数执行的行为模式,`bind()` 返回了一个新的绑定了特定上下文环境(`this`)的新函数实例。这意味着即使创建出了这样的闭包形式也不会马上启动原定义流程直到被显式调用为止。它的一般写法为: ```javascript function.bind(thisArg[, arg1[, arg2[, ...]]]) ``` 下面是一个简单的例子展示如何利用此特性实现延迟计算效果的同时调整好作用域关系。 ```javascript function logName() { console.log('My Name Is:' + this.firstName); } var personA = { firstName:"John"}; var boundLogPersonA=logName.bind(personA); boundLogPersonA();// My Name Is: John setTimeout(boundLogPersonA ,100); // Still prints "My Name Is: John" ``` 值得注意的地方在于虽然同样能完成更改当前实例指针的任务但却不具备即时运算能力而是生成另一个副本供以后单独启用[^3]. --- ### 总结对比表 | Call vs Apply vs Bind | 特性 | **Call** | **Apply** | **Bind** | |-----------------|----------------------------------|---------------------------------|----------------------------------| | 是否立即执行 | ✔ | ✔ | ✘ (仅返回新函数) | | 参数传递方式 | 单独列出 | 数组形式 | 单独列出 / 部分应用 | | 主要用途 | 调用函数 & 修改 this | 批量操作数组 | 创建预设 this 的新函数 | 以上就是有关于 JavaScript 当中的三个重要工具——即 call(), apply() 还有 bind()- 它们各自的特点及应用场景概述[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值