apply,call学习

一、this

例子1

var name = "windowName"
function getName() {
  var name = "jack"
  console.log(this.name)   // windowName
  console.log("inner", this)   // window
}

getName()
console.log("outer", this)  // window

this.namewindowName,因为调用的对象是window,getName() 相当于 window.getName()。如果使用严格模式的话,全局对象就是 <font color="red">undefined</font>

例子2

let name = "windowName"
let user = {
  name: 'jack',
  getName: function () {
    console.log(this.name)   // this 指向jack
  }
}
user.getName()

getName这个函数对象user调用的,应证了那句话“this 永远指向最后调用它的那个对象”

例子3

var name = "windowName"
var user = {
  name: null,
  getName: function () {
    console.log(this.name)   // windowName
  }
}
var fn = user.getName
fn()

因为把函数赋值给了fn,getName并没有调用,最后还是相当于window调用了这对方法,所以结果是 windowName<font color="red">不要在严格模式下</font>

this 的指向并不是在创建的时候就可以确定的,在 es5 中,永远是this 永远指向最后调用它的那个对象。

二、改变this的指向

  • 备份指针
  • 箭头函数
  • apply、call、bind

例子4

name = "windowName"
var user = {
  name: null,
  getName: function () {
    console.log(this.name)
  },
  test: function () {
    setTimeout(function () {
      this.getName()  // 报错 TypeError: this.getName is not a functionvar
    }, 100)
  }
}
user.test()

在不使用箭头函数的情况下,是会报错的,因为最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。

(1)箭头函数

箭头函数的 this 始终指向函数定义时的 this,而非执行时。

var name = "windowName"
var user = {
  name: "jack",
  getName: function () {
    console.log(this.name)   // this 指向jack
  },
  test: function () {
    setTimeout(() => {
      this.getName()
    }, 100)
  }
}
user.test()

箭头函数修正了this的指向

(2)备份指针

var name = "windowName"
var user = {
  name: "jack",
  getName: function () {
    console.log(this.name)   // tack
  },
  test: function () {
    var self = this  // 备份指针
    setTimeout(function () {
      self.getName()
    }, 100)
  }
}
user.test()

(3)apply、call、bind

使用 apply、call、bind 函数也是可以改变 this 的指向的

使用apply
var user = {
  name: "jack",
  getName: function () {
    console.log(this.name)   // jack
  },
  test: function () {
    setTimeout(function () {
      this.getName()
    }.apply(user), 100)
  }
}
user.test()

使用call

var user = {
  name: "jack",
  getName: function () {
    console.log(this.name)   // jack
  },
  test: function () {
    setTimeout(function () {
      this.getName()
    }.call(user), 100)
  }
}
user.test()

使用bind

var user = {
  name: "jack",
  getName: function () {
    console.log(this.name)   // jack
  },
  test: function () {
    setTimeout(function () {
      this.getName()
    }.bind(user)(), 100)
  }
}
user.test()

(4)apply、call、bind 区别

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

语法

func.apply(thisArg, [argsArray])

  • thisArg
    可选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。
  • argsArray 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 浏览器兼容性 请参阅本文底部内容。
  • 返回值 调用有指定this值和参数的函数的结果。
(5)call 和 apply的区别

applycall 基本类似,他们的区别只是传入的参数不同。

fun.call(thisArg[, arg1[, arg2[, ...]]])

call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

例子 (apply)

var operation = {
  sum: function (a, b) {
    console.log(a + b)   // 3
  }
}

var a = operation.sum
a.apply(operation, [1, 2])

例子 (call)

var operation = {
  sum: function (a, b) {
    console.log(a + b)   // 3
  }
}

var a = operation.sum
a.call(operation, 1, 2)
(6)bind 和 apply、call 区别

还是刚刚的例子

var operation = {
  sum: function (a, b) {
    console.log(a + b)   // 3
  }
}

var a = operation.sum
a.bind(operation, 1, 2)()
(7)创建对象时候使用call
function Person(name, age) {
  this.name = name
  this.age = age
}
var person = new Person('jack', 18)
person.name // jack

简单的来看一下 new 的过程吧:

var person = new Person('jack', 18)

new Person {
  var obj = {}
  obj.__proto__ = myFunction.prototype;
  var result = myFunction.call(obj,"jack","18");
  return typeof result === 'obj'? result : obj;
}
  • 创建一个空对象
  • 将新创建的空对象的隐式原型指向其构造函数的显示原型
  • 使用 call 改变 this 的指向
  • 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。
<think>好的,用户让我介绍一下JavaScript中的callapply和bind方法。首先,我需要回忆这三个方法的共同点和区别。它们都是用来改变函数执行时的this指向的,但用法和适用场景有所不同。 用户之前问过JSON.stringify,现在转向函数方法,可能是想更深入学习JavaScript的核心概念。我需要确认他们的知识水平,可能已经有一定基础,但需要系统梳理这三个方法。 首先,应该从基本定义入手,说明每个方法的作用。callapply都是立即调用函数,而bind是返回一个新函数,稍后执行。接下来,参数传递的区别是关键点,call接受参数列表,apply接受数组。 需要举例子说明不同情况下的使用方式,比如改变this指向、参数传递、继承中的应用等。可能用户在实际开发中遇到过this指向的问题,或者想在类数组对象上使用数组方法,比如arguments或者NodeList。 还要注意特殊情况和注意事项,比如非严格模式下this指向全局对象的问题,多次bind无效的情况,以及如何利用apply展开数组参数。此外,bind后的函数作为构造函数时的行为需要说明,因为这时候this绑定会失效。 要确保语言通俗易懂,结构清晰,分点列出每个方法的语法、示例和用途。可能用户需要对比这三者的区别,所以最后做一个对比表格会很有帮助,帮助用户快速理解不同点。 需要检查是否有遗漏的重要点,比如callapply的性能差异(虽然通常可以忽略),或者bind在事件处理函数中的应用。同时,避免使用专业术语过多,保持解释的直观性。 最后,总结它们的共同目的,强调根据参数形式和是否需要立即执行来选择合适的方法。确保用户能够根据具体场景选择正确的函数方法,提升代码的灵活性和可维护性。</think>以下是关于 JavaScript 中 `call`、`apply` 和 `bind` 的对比解析,通过结构化说明帮助你理解它们的核心区别和实际应用: --- ### 一、共同目标 **核心作用**:**改变函数执行时的 `this` 指向** (即显式绑定函数的上下文对象) --- ### 二、方法对比 | 方法 | 调用方式 | 参数形式 | 执行时机 | 返回值 | |-----------|-------------------|-------------------|----------------|--------------| | `call` | 立即执行 | **参数列表** | 直接调用 | 函数执行结果 | | `apply` | 立即执行 | **数组参数** | 直接调用 | 函数执行结果 | | `bind` | **不执行** | 参数列表 | 返回新函数 | 绑定后的函数 | --- ### 三、详细解析 #### 1. **`call()`** **语法**:`func.call(thisArg, arg1, arg2, ...)` **特点**:直接传递参数列表 **场景**:明确知道参数个数时使用 ```javascript function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'Alice' }; // 绑定 this 为 person,并传递参数列表 greet.call(person, 'Hello', '!'); // 输出: Hello, Alice! ``` --- #### 2. **`apply()`** **语法**:`func.apply(thisArg, [argsArray])` **特点**:参数以数组形式传递 **场景**:参数数量不确定或需要动态传递时 ```javascript function sum(a, b, c) { return a + b + c; } const numbers = [1, 2, 3]; // 将数组展开为参数列表 console.log(sum.apply(null, numbers)); // 输出: 6 // 实际应用:在类数组对象上调用数组方法 const arrayLike = { 0: 'a', 1: 'b', length: 2 }; console.log(Array.prototype.join.apply(arrayLike, ['-'])); // 输出: a-b ``` --- #### 3. **`bind()`** **语法**:`const boundFunc = func.bind(thisArg, arg1, arg2, ...)` **特点**:返回一个绑定上下文的新函数,可延迟调用 **场景**:需要保留上下文供后续使用(如事件回调) ```javascript const car = { brand: 'Toyota', getBrand: function() { return this.brand; } }; // 直接调用(正常情况) console.log(car.getBrand()); // Toyota // 上下文丢失的场景 const getBrandLater = car.getBrand; console.log(getBrandLater()); // undefined(严格模式报错) // 使用 bind 修复上下文 const boundGetBrand = getBrandLater.bind(car); console.log(boundGetBrand()); // Toyota ``` --- ### 四、特殊场景 #### 1. **参数复用**(`bind` 的柯里化) ```javascript function multiply(a, b) { return a * b; } // 预先绑定第一个参数 const double = multiply.bind(null, 2); console.log(double(5)); // 输出: 10 (等价于 multiply(2,5)) ``` #### 2. **构造函数绑定** `bind` 后的函数作为构造函数时,原始绑定会被覆盖: ```javascript function Person(name) { this.name = name; } const BoundPerson = Person.bind({}); const obj = new BoundPerson('Bob'); console.log(obj.name); // 输出: Bob(this 指向新对象,而非绑定的空对象) ``` --- ### 五、注意事项 1. **严格模式**: - 非严格模式下,`thisArg` 为 `null`/`undefined` 时自动指向全局对象(如 `window`) - 严格模式下保持 `null`/`undefined` 2. **多次 `bind` 无效**: ```javascript function foo() {} const bound1 = foo.bind({a: 1}); const bound2 = bound1.bind({a: 2}); console.log(bound2()); // this 仍指向 {a: 1} ``` 3. **性能取舍**: `call` 通常比 `apply` 更快(参数处理差异) --- ### 六、总结选择 | 场景 | 推荐方法 | |------------------------------|-----------| | 明确参数个数且需立即执行 | `call` | | 参数动态变化或为数组形式 | `apply` | | 需要延迟执行或保持上下文引用 | `bind` | 通过灵活组合这三个方法,可以精准控制 JavaScript 函数的执行上下文和参数传递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值