javascrip中this指向性问题详解

简介: javascrip中this指向性问题详解

一、this是谁?

“谁调用他,this就指向谁”,这句话并不全面。

1.全局环境中的this

function f1(){
  console.log(this)
}
function f2(){
  'use strict'
  console.log(this)
}
f1()//window
f2()//undefined

隐式的简单调用函数时,严格模式下this是undefined;非严格模式下this会绑定到全局对象window/golbal上

2.一个简单对象中的this

const person = {
  name:"小红",
  like:function(ev){
    console.log(`${this.name}喜欢${ev}`)
  }
}
person.like("跳皮筋")//小红喜欢跳皮筋

this的执行上下文对象调用。

3.箭头函数中的this

箭头函数中的this是又外层作用域(其所属函数或全局作用域)来决定的。

  const foo = {
        fo: function () {
            setTimeout(function () {
                console.log(this)
            }, 2000)
        }
    }
    foo.fo()//window
  const foo = {
        fo: function () {
            setTimeout( () =>{
                console.log(this)
            }, 2000)
        }
    }
    foo.fo()//{fo: ƒ}即foo

4.构造函数的this和class里的this

他们中的this都会绑定到创建的对象上。

二、如何改变this指向?

简述

1.call,apply,new,bind可以改变this指向,这里的new一个实例当然是重新绑定了this到一个新对象上。

call和apply改变this指向并调用该函数,区别是apply第二个参数是数组,call对后面的参数没有要求。

bind不会执行相关函数,只是返回一个新函数。

  function Hero(name) {
        this.name = name;
        this.hello = function () {
            console.log(`${this.name}说hello`);
        }
    }
    Hero.prototype.hit = function (...args) {
        console.log(args);
        console.log(`${this.name}打${args}`);
    }
    let b = {
        name: "剑圣"
    }
    // console.log(Hero.prototype);
    let a = new Hero("鸟人");
    a.hello.call(b)//剑圣说hello
    a.hit.call(b, {
        id: 123
    }, {
        id: 78222
    })

注意:无论是原型上的方法还是实例上的方法,new出来的实例对象其中this都是可以被call和apply重新指定。

call,apply,bind 什么情况下会用到

call, apply, 和 bind 是 JavaScript 中用于操作函数的方法,它们允许你更改函数执行时的上下文(即 this 的值)。虽然你可能没有意识到它们的用处,但它们实际上在许多库中都是不可或缺的,并且在处理回调、事件处理程序或需要控制函数执行上下文的情况下非常有用。

以下是一些你可能会用到这些方法的场景:

callapply

调用数组的方法在非数组对象上

如果你有一个类似数组的对象(比如有 length 属性和索引元素,但不是真正的数组),你可能想调用数组的方法,如 slicemap。由于这些方法是通过原型链继承的,非数组对象没有这些方法。你可以使用 callapply 来“借用”这些方法。

var arrayLike = { 0: 'a', 1: 'b', length: 2 };
var realArray = Array.prototype.slice.call(arrayLike); // ['a', 'b']

设置回调函数的上下文

当传递一个回调函数给某个方法,并且这个方法会在不同的上下文中调用你的回调函数时(例如事件监听器或异步回调),你可能需要使用 callapply 来确保回调函数在正确的上下文中执行。

function MyObject() {
  this.value = 'Hello';
}
MyObject.prototype.logValue = function() {
  console.log(this.value);
};
var obj = new MyObject();
var logMethod = obj.logValue;

// 错误的调用,因为 this 将不会指向 obj
logMethod(); // undefined

// 正确的调用,使用 call 设置 this 为 obj
logMethod.call(obj); // 'Hello'

bind

  1. 事件处理程序
    在事件处理程序中,this 通常指向触发事件的元素。如果你有一个方法需要在特定上下文中执行,你可以使用 bind 来确保 this 的正确值。
function MyButton() {
  this.value = 'Click me';
  this.element = document.createElement('button');
  this.element.innerHTML = this.value;
  this.element.addEventListener('click', this.handleClick.bind(this));
}
MyButton.prototype.handleClick = function() {
  alert(this.value); // 'Click me'
};
var button = new MyButton();
document.body.appendChild(button.element);

回调函数和定时器

当传递一个函数作为 setTimeout、setInterval 或其他异步函数的回调函数时,你可能需要确保这个函数在正确的上下文中执行。

function MyObject() {
  this.counter = 0;
}
MyObject.prototype.incrementCounter = function() {
  this.counter++;
  console.log(this.counter);
};
var obj = new MyObject();

// 错误的调用,因为 this 将指向全局对象(在浏览器中通常是 window)
setTimeout(obj.incrementCounter, 1000);

// 正确的调用,使用 bind 绑定 this 为 obj
setTimeout(obj.incrementCounter.bind(obj), 1000);

如果你几乎没有用过这些方法,可能是因为:

  • 你编写的代码类型不需要频繁地更改函数上下文。
  • 你使用了库或框架(如 jQuery、React 等),这些库或框架为你处理了函数上下文的问题。
  • 你可能还没有遇到需要这些高级功能的复杂场景。

然而,了解这些方法是很有用的,因为它们可以帮助你编写更加灵活和可重用的代码,并且能够更好地理解 JavaScript 函数的工作原理。

三、浅谈call,apply,new,bind的优先级

在JavaScript中,callapplynew、和bind都是与函数相关的方法或操作符,但它们的作用和优先级并不完全相同。这里我会尝试解释它们各自的作用,但需要注意的是,它们通常不会在同一表达式中一起使用,因此讨论它们的“优先级”可能并不完全准确。

  1. new 操作符:
  • new 用于创建一个对象的实例。
  • 它调用一个构造函数,并返回一个新对象。
  • 它的优先级非常高,通常你会首先看到它(如果它存在的话)。
  • 示例:new MyClass()
  1. callapply 方法:
  • 这两个方法都是函数的方法,用于调用函数,并允许你设置函数内部的 this 值。
  • callapply 之间的主要区别是传递参数的方式。call 接受一个参数列表,而 apply 接受一个参数数组。
  • 它们的优先级低于 new,因为你通常不会在创建新对象后立即调用这些方法(尽管技术上可以在某些情况下这样做)。
  • 示例:myFunction.call(myObject, arg1, arg2)myFunction.apply(myObject, [arg1, arg2])
  1. bind 方法:
  • bind 也是函数的一个方法,用于创建一个新的函数,该函数在调用时将具有指定的 this 值和一些初始参数。
  • bind 的优先级通常是最低的,因为它创建了一个新的函数,而不是立即执行它。
  • 示例:myFunction.bind(myObject, arg1)

在实际编程中,这些方法的使用通常取决于你想要达到的目的,而不是它们的“优先级”。例如,如果你想要创建一个新对象,你会使用 new。如果你想要调用一个函数并设置其 this 值,你会使用 callapply。如果你想要创建一个具有特this 值的新函数,你会使用 bind

需要注意的是,这些方法的“优先级”并不是指它们在语法上的优先级,而是指它们在逻辑上或在使用上的顺序。在JavaScript的语法中,这些方法和操作符的优先级是由语言规范定义的,通常与你如何在实际代码中使用它们没有直接关系。

是不是很简单啊?喜欢的小伙伴留言点赞关注吧!

相关文章
|
19天前
|
JavaScript 前端开发
电话号码正则表达式 代码 javascript+html,JS正则表达式判断11位手机号码
电话号码正则表达式 代码 javascript+html,JS正则表达式判断11位手机号码
48 1
|
6月前
|
JavaScript 前端开发 C#
JavaScrip基础(二)
JavaScrip基础(二)
36 0
|
6月前
JavaScrip基础(三)
JavaScrip基础(三)
32 0
|
6月前
|
前端开发 算法 JavaScript
JavaScrip实现一个睡眠函数
JavaScrip实现一个睡眠函数
62 0
|
6月前
|
JavaScript 前端开发 C#
JavaScrip基础(一)
JavaScrip基础(一)
41 0
|
6月前
|
JavaScript 前端开发 Unix
JavaScrip-T5(2022年11月21日移动2112班)
JavaScrip-T5(2022年11月21日移动2112班)
49 0
JavaScrip 第二课。回顾
JavaScrip 第二课。回顾
34 0