跳到主要内容

this指向问题

自己实现一个 bind 函数

原理:通过 apply 或者 call 方法来实现。 1 初始版本

Function.prototype.bind=function(obj,arg){
var arg=Array.prototype.slice.call(arguments,1);
var context=this;
return function(newArg){
arg=arg.concat(Array.prototype.slice.call(newArg));
return context.apply(obj,arg);
}}

2 考虑到原型链 为什么要考虑?因为在 new 一个 bind 过生成的新函数的时候,必须的条件是要继承原 函数的原型

Function.prototype.bind=function(obj,arg){
var arg=Array.prototype.slice.call(arguments,1);
var context=this;
var bound=function(newArg){
arg=arg.concat(Array.prototype.slice.call(newArg));
return context.apply(obj,arg);
}
var F=function(){}
//这里需要一个寄生组合继承
F.prototype=context.prototype;
bound.prototype=new F();
return bound;
}

this的指向哪几种

默认绑定:全局环境中,this 默认绑定到 window。

隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this 隐式绑定到该直接对象。

隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到 window。

显式绑定:通过 call()、apply()、bind()方法把对象绑定到 this 上,叫做显式绑定。

new 绑定:如果函数或者方法调用之前带有关键字 new,它就构成构造函数调用。对于this 绑定来说,称为 new 绑定。

【1】构造函数通常不使用 return 关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。

【2】如果构造函数使用 return 语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。

【3】如果构造函数显式地使用 return 语句返回一个对象,那么调用表达式的值就是这个对象。

箭头函数的 this 指向哪⾥?

箭头函数的 this 指向是在函数定义时确定的,并且在整个函数生命周期内保持不变。与常规函数(函数声明或函数表达式)不同,箭头函数没有自己的 this 绑定。相反,它继承了父作用域中的 this 值。

具体来说,箭头函数的 this 指向的是其外部包围函数(或全局作用域)的 this 值。这意味着,无论如何调用箭头函数,它始终引用的是最近一层非箭头函数作用域的 this 值。

考虑以下示例:

function regularFunction() {
console.log(this); // this 指向调用 regularFunction 的对象
}

const arrowFunction = () => {
console.log(this); // this 指向外部作用域中的 this 值
};

const obj = {
method: regularFunction,
};

regularFunction(); // this 指向全局对象(浏览器环境中通常是 window)
obj.method(); // this 指向 obj 对象
arrowFunction(); // this 指向外部作用域中的 this 值(在此处通常是全局对象)

在上述示例中,regularFunction 是一个常规函数,它的 this 值取决于调用它的方式,可以通过 obj.method() 来改变其 this 指向。而 arrowFunction 是一个箭头函数,它的 this 始终继承自外部作用域,无法通过调用方式改变其 this 指向。

需要注意的是,箭头函数不适合作为构造函数使用,因为它没有自己的 this 绑定,无法通过 new 关键字来实例化。

改变函数内部 this 指针的指向函数(bind,apply,call 的区别)

通过 apply 和 call 改变函数的 this 指向,他们两个函数的第一个参数都是一样的表 示要改变指向的那个对象,第二个参数,apply 是数组,而 call 则是 arg1,arg2...这 种形式。通过 bind 改变 this 作用域会返回一个新的函数,这个函数不会马上执行。

对this对象的理解

this 是 JavaScript 中的特殊对象,它代表当前执行上下文中的对象或者说是当前执行代码所属的对象。this 的值在函数执行时动态绑定,取决于函数的调用方式。

下面是对 this 的一些常见情况和使用场景的解释:

  1. 全局作用域中的 this

    • 在全局作用域中,函数没有明确的调用对象,此时 this 指向全局对象(在浏览器中为 window 对象)。
    • 在严格模式下,全局作用域中的 this 值为 undefined
  2. 函数作为对象的方法调用时的 this

    • 当函数作为对象的方法被调用时,this 指向调用该方法的对象。
    • 方法中的 this 可以用于引用该对象的属性和方法。
  3. 函数使用 call()apply()bind() 显式指定 this

    • 使用 call()apply() 方法可以显式指定函数执行时的 this 值。
    • call() 方法接受多个参数,第一个参数指定 this 的值,后续参数为函数的参数。
    • apply() 方法接受两个参数,第一个参数指定 this 的值,第二个参数为一个数组,包含了函数的参数。
    • bind() 方法返回一个新函数,并预先指定 this 值。调用新函数时,this 将始终保持预先指定的值。
  4. 构造函数中的 this

    • 当函数作为构造函数使用时(使用 new 关键字),this 指向新创建的实例对象。
    • 在构造函数中,可以使用 this 来设置实例对象的属性和方法。
  5. 箭头函数中的 this

    • 箭头函数的 this 值继承自外层的作用域,与普通函数不同,箭头函数没有自己的 this
    • 在箭头函数中使用的 this 实际上是定义时所在作用域中的 this

注意:this 的值是在函数被调用时确定的,并且与函数的定义位置无关。所以在编写代码时,需要根据具体情况正确理解和使用 this

call() 和 apply() 的区别?

call()apply() 是 JavaScript 中函数对象的两个方法,用于显式调用函数并指定函数执行时的 this 值。它们的区别在于参数的传递方式。

区别如下:

  1. 参数传递方式:

    • call() 方法使用参数列表的方式传递参数,即将参数按照逗号分隔的形式依次传递给函数。
    • apply() 方法使用数组的方式传递参数,即将参数封装在数组中作为单个参数传递给函数。
  2. 参数数量:

    • call() 方法可以接受任意数量的参数,第一个参数是要指定的 this 值,后续参数是函数的参数。
    • apply() 方法只接受两个参数,第一个参数是要指定的 this 值,第二个参数是一个数组,包含了函数的参数。

示例代码如下:

function greet(message) {
console.log(message + ', ' + this.name);
}

const person = {
name: 'John',
};

// 使用 call() 方法调用 greet() 函数,并指定 this 为 person 对象
greet.call(person, 'Hello'); // 输出: Hello, John

// 使用 apply() 方法调用 greet() 函数,并指定 this 为 person 对象,参数以数组形式传递
greet.apply(person, ['Hi']); // 输出: Hi, John

在上述代码中,greet 函数使用 call()apply() 方法分别调用,并指定了 this 值为 person 对象。通过传递不同的参数,可以实现对函数的显式调用并设置函数执行时的 this 值和参数。

总结:call()apply() 方法的区别主要在于参数传递方式的不同,call() 使用参数列表传递参数,而 apply() 使用数组传递参数。根据具体的需求和参数的形式,选择合适的方法来调用函数。