JavaScript中的this指向,call、apply、bind的简单实现

开发 前端
this是JavaScript中一个特殊关键字,用于指代当前执行上下文中的对象。它的难以理解之处就是值不是固定的,是再函数被调用时根据调用场景动态确定的,主要根据函数的调用方式来决定this指向的对象。

JavaScript中的this

this是JavaScript中一个特殊关键字,用于指代当前执行上下文中的对象。它的难以理解之处就是值不是固定的,是再函数被调用时根据调用场景动态确定的,主要根据函数的调用方式来决定this指向的对象。this 的值在函数被调用时动态确定,以下是几种常见的情况:

  • 全局上下文中:当在全局作用域中调用函数时,this 指向全局对象。在浏览器环境中,这个全局对象是 window 对象。
console.log(this); // 在浏览器中,输出为 Window 对象
  • 函数作为对象的方法:当函数作为对象的方法被调用时,this 指向调用该方法的对象。
const obj = {
  property: 'value',
  printProperty: function() {
    console.log(this.property);
  }
};


obj.printProperty(); // 输出 'value'
  • 构造函数中:在使用 new 关键字创建实例时,构造函数内部的 this 指向即将创建的新实例。
function Person(name) {
  this.name = name;
}


const person = new Person('Alice');
console.log(person.name); // 输出 'Alice'
  • 显式绑定:使用call、apply、bind方法可以显式指定this的绑定对象。
function greet(message) {
  console.log(`${message}, ${this.name}!`);
}


const person = { name: 'Bob' };


greet.call(person, 'Hello'); // 输出 'Hello, Bob!'
  • 箭头函数:箭头函数不绑定this,它会捕获外层作用域的this值作为自己的this。
const obj = {
  method: function() {
    const arrowFunc = () => {
      console.log(this === obj);
    };
    arrowFunc();
  }
};


obj.method(); // 输出 true
  • class中的this:类中的this默认指向类的实例对象。
class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }
}


const rect = new Rectangle(10, 20);
console.log(rect.width); // 输出 10
  • 事件绑定事件绑定中的this是指向触发事件的dom元素。
const button = document.getElementById('myButton');


button.addEventListener('click', function() {
  console.log(this === button);
});
// 在按钮点击时输出 true

如何改变this指向

改变 this 指向是在 JavaScript 中常见的需求,特别是当你想要在不同的上下文中调用函数时。以下是几种常见的方法来改变 this 指向:

  • 使用 call 方法:call 方法允许你显式地指定函数内部的 this 值,并且传递参数列表。第一个参数是要绑定的 this 值,后面的参数是函数的参数。
function greet(message) {
  console.log(`${message}, ${this.name}!`);
}


const person = { name: 'Alice' };


greet.call(person, 'Hello'); // 输出 'Hello, Alice!' 这里把this绑定给person对象
  • 使用 apply 方法:apply 方法与 call 类似,但它接受一个数组或类数组对象作为参数,其中的元素将作为函数参数传递。
function greet(message) {
  console.log(`${message}, ${this.name}!`);
}


const person = { name: 'Bob' };


greet.apply(person, ['Hi']); // 输出 'Hi, Bob!'
  • 使用 bind 方法:bind 方法创建一个新函数,将 this 值永久地绑定,并可以预先设置部分参数。原函数不会受到影响。
function greet(message) {
  console.log(`${message}, ${this.name}!`);
}


const person = { name: 'Charlie' };
const greetPerson = greet.bind(person);


greetPerson('Hey'); // 输出 'Hey, Charlie!'
  • 使用箭头函数:箭头函数不会绑定独立的 this 值,而是捕获其外部函数的 this 值。
const obj = {
  method: function() {
    const arrowFunc = () => {
      console.log(this === obj);
    };
    arrowFunc();
  }
};


obj.method(); // 输出 true

call和apply区别

  1. bind 方法:
  • bind 方法创建一个新函数,将原函数的 this 值永久绑定到指定的对象,并可以在调用时传递参数。
  • 它不会立即执行原函数,而是返回一个新的函数,需要手动调用新函数以执行原函数。
  • bind 方法不会改变原函数的上下文,而是返回一个新函数。
  1. call 方法:
  • call 方法立即调用函数,并指定函数内部的 this 值,同时可以传递参数列表。

  • 它的第一个参数是要绑定的 this 值,后续的参数会作为函数的参数传递。

  1. apply 方法:

  • apply 方法也立即调用函数,并指定函数内部的 this 值,但参数传递方式不同。

  • 它的第一个参数是要绑定的 this 值,第二个参数是一个数组(或类数组对象),其中的元素会作为函数的参数传递。

实现call、apply、bind

这里实现简化版的,核心思路是:

  1. 将函数设为传入对象的一个属性
  2. 执行该函数
  3. 删除该函数(临时函数调用完成删除,防止内存泄漏,以免context 对象造成污染)
  4. 返回结果或传入的this

call

js
Function.prototype.myCall = function(context, ...args) {
  context = context || window;
  const fn = Symbol();


  context[fn] = this;


  const result = context[fn](...args);
  delete context[fn];


  return result;
}

apply

js
Function.prototype.myApply = function(context, args) {
  context = context || window;
  const fn = Symbol();


  context[fn] = this;


  let result;
  if(args) {
    result = context[fn](...args);
  } else {
    result = context[fn]();
  }


  delete context[fn];
  return result;
}

bind

js
Function.prototype.myBind = function(context, ...outerArgs) {
  context = context || window;
  const _this = this;
  
  return function(...innerArgs) {
    context[fn] = _this;
    const result = context[fn](...outerArgs, ...innerArgs);
    delete context[fn];
    return result;
  }
}

责任编辑:武晓燕 来源: 海燕技术栈
相关推荐

2024-03-15 08:21:17

bindJavaScrip函数

2021-12-05 08:27:56

Javascript 高阶函数前端

2021-06-18 07:16:17

JavaScript apply()方法call()方法

2024-08-20 16:04:27

JavaScript开发

2024-08-26 08:36:26

2017-10-10 14:36:07

前端Javascriptapply、call、

2015-03-02 09:22:09

Javascript函数用法apply

2011-03-22 09:49:15

JavaScript

2021-11-30 06:56:58

CallApply函数

2021-06-09 07:01:30

前端CallApply

2017-07-27 16:31:11

2023-06-28 08:34:02

Bind()函数JavaScript

2015-10-29 14:29:48

javascriptthis指向

2019-04-03 10:50:09

Javascript区块链技术

2011-08-15 12:55:54

SQL ServerOUTER APPLYCROSS APPLY

2015-06-08 13:19:11

JavaScriptgettersetter

2018-09-18 10:11:21

前端vue.jsjavascript

2021-12-01 06:40:32

Bind原理实现

2017-08-22 16:40:22

前端JavaScript接口

2016-11-02 18:54:01

javascript
点赞
收藏

51CTO技术栈公众号