一、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
的值)。虽然你可能没有意识到它们的用处,但它们实际上在许多库中都是不可或缺的,并且在处理回调、事件处理程序或需要控制函数执行上下文的情况下非常有用。
以下是一些你可能会用到这些方法的场景:
call
和 apply
调用数组的方法在非数组对象上:
如果你有一个类似数组的对象(比如有 length 属性和索引元素,但不是真正的数组),你可能想调用数组的方法,如 slice
或 map
。由于这些方法是通过原型链继承的,非数组对象没有这些方法。你可以使用 call
或 apply
来“借用”这些方法。
var arrayLike = { 0: 'a', 1: 'b', length: 2 }; var realArray = Array.prototype.slice.call(arrayLike); // ['a', 'b']
设置回调函数的上下文:
当传递一个回调函数给某个方法,并且这个方法会在不同的上下文中调用你的回调函数时(例如事件监听器或异步回调),你可能需要使用 call
或 apply
来确保回调函数在正确的上下文中执行。
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
- 事件处理程序:
在事件处理程序中,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中,call
、apply
、new
、和bind
都是与函数相关的方法或操作符,但它们的作用和优先级并不完全相同。这里我会尝试解释它们各自的作用,但需要注意的是,它们通常不会在同一表达式中一起使用,因此讨论它们的“优先级”可能并不完全准确。
new
操作符:
new
用于创建一个对象的实例。
- 它调用一个构造函数,并返回一个新对象。
- 它的优先级非常高,通常你会首先看到它(如果它存在的话)。
- 示例:
new MyClass()
call
和apply
方法:
- 这两个方法都是函数的方法,用于调用函数,并允许你设置函数内部的
this
值。 call
和apply
之间的主要区别是传递参数的方式。call
接受一个参数列表,而apply
接受一个参数数组。- 它们的优先级低于
new
,因为你通常不会在创建新对象后立即调用这些方法(尽管技术上可以在某些情况下这样做)。
- 示例:
myFunction.call(myObject, arg1, arg2)
或myFunction.apply(myObject, [arg1, arg2])
bind
方法:
bind
也是函数的一个方法,用于创建一个新的函数,该函数在调用时将具有指定的this
值和一些初始参数。bind
的优先级通常是最低的,因为它创建了一个新的函数,而不是立即执行它。- 示例:
myFunction.bind(myObject, arg1)
在实际编程中,这些方法的使用通常取决于你想要达到的目的,而不是它们的“优先级”。例如,如果你想要创建一个新对象,你会使用 new
。如果你想要调用一个函数并设置其 this
值,你会使用 call
或 apply
。如果你想要创建一个具有特定 this
值的新函数,你会使用 bind
。
需要注意的是,这些方法的“优先级”并不是指它们在语法上的优先级,而是指它们在逻辑上或在使用上的顺序。在JavaScript的语法中,这些方法和操作符的优先级是由语言规范定义的,通常与你如何在实际代码中使用它们没有直接关系。
是不是很简单啊?喜欢的小伙伴留言点赞关注吧!