this

57 阅读4分钟

this

this 可以用在构造函数之中,表示实例对象。除此之外,this 还可以用在别的场合。但不管是什么场合,this 都有一个共同点:它总是返回一个对象

this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同

在函数中使用this,它的指向完全取决于函数是如何被调用的

调用方式示例函数中的this指向
通过new调用new method()创建的实例对象
直接调用method()全局对象
通过对象调用obj.method()前面的对象
callmethod.call(ctx)call的第一个参数
applymethod.apply(ctx)apply的第一个参数

this 关键字在构造函数中用于引用正在创建的实例对象

function Person(name, age) {
  this.name = name;  // `this.name` 是实例对象的属性
  this.age = age;    // `this.age` 是实例对象的属性
}

const person1 = new Person('Alice', 30);
console.log(person1.name); // 输出: Alice
console.log(person1.age);  // 输出: 30

实例方法中的this指向的是当前对象(实例对象)

constructor的this指向的是当前对象(实例对象)

静态方法中的this指向的是当前类

class Person {
  constructor(name, age) {
    this.name = name;  // `this` 指向新创建的实例对象
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    // `this` 在类的方法中指向当前实例
  }

  static greet() {
    // `this` 指向 Person 类
    console.log(`Hello from ${this.name}`);  
  }
}

const person1 = new Person('Alice', 30);
person1.greet();  // 输出: Hello, my name is Alice and I am 30 years old.

明确:大部分时候,this的指向取决于函数的调用方式

  • 如果直接调用函数(全局调用),this指向全局对象或undefined (启用严格模式)
  • 如果使用``对象.方法``调用,this指向对象本身
  • 如果是dom事件的处理函数,this指向事件处理对象

特殊情况:

  • 箭头函数,this在函数声明时确定指向,指向函数位置的this
  • 使用bind、apply、call手动绑定this对象
function f1() {
    console.log(this);
}

function f2() {
    'use strict'
    console.log(this);
}

f1(); // window or global
f2(); // undefined
const foo = {
    bar: 10,
    fn: function(){
        console.log(this); // window or global
        console.log(this.bar); // undefined
    }
}
var fn1 = foo.fn;
fn1();

这里的 this 仍然指向 window。虽然 fn 函数在 foo 对象中作为该对象的一个方法,但是在赋值给 fn1 之后,fn1 仍然是在 window 的全局环境下执行的。因此上面的代码仍然会输出 window 和 undefined。

const foo = {
    bar : 10,
    fn : function(){
        console.log(this); // { bar: 10, fn: [Function: fn] }
        console.log(this.bar); // 10
    }
}
foo.fn();

这时,this 指向的是最后调用它的对象,在 foo.fn( ) 语句中,this 指向的是 foo 对象。

const student = {
    name: 'zhangsan',
    fn: function () {
        return this;
    }
}
console.log(student.fn() === student); // true
const student = {
    name: 'zhangsan',
    son: {
        name: 'zhangxiaosan',
        fn: function () {
            return this.name
        }
    }
}
console.log(student.son.fn()); // zhangxiaosan

在上面的代码中,this 会指向最后调用它的对象,因此输出的zhangxiaosan。

const o1 = {
    text: 'o1',
    fn: function () {
        return this.text;
    }
}

const o2 = {
    text: 'o2',
    fn: function () {
        return o1.fn();
    }
}

const o3 = {
    text: 'o3',
    fn: function () {
        var fn = o1.fn;
        return fn();
    }
}

console.log(o1.fn()); // o1
console.log(o2.fn()); // o1
console.log(o3.fn()); // undefined

这里主要讲一下为什么第三个是 undefined。这里将 o1.fn 赋值给了 fn,所以 fn 等价于 function () { return this.text; },然后该函数在调用的时候,是直接 fn( ) 的形式调用的,并不是以对象的形式,相当于还是全局调用,指向 window,所以打印出 undefined。

call,apply,bind

这三个函数可以用来改变this指向

call的意思就是调用函数,只是修改了this指向

Function.prototype.call( )

call 方法可以指定 this 的指向(即函数执行时所在的的作用域),然后再指定的作用域中,执行函数。

var obj = {};
var f = function(){
	return this;
};
console.log(f() === window);  // this 指向 window
console.log(f.call(obj) === obj) // 改变this 指向 obj

call 方法的参数,应该是对象 obj,如果参数为空或 null、undefind,则默认传参全局对象,如果传入的是普通类型则转换为包装对象

使用call可以直接调用原生的toString方法

var obj = {};
obj.hasOwnProperty('toString') // false

// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
  return true;
};
obj.hasOwnProperty('toString') // true

Object.prototype.hasOwnProperty.call(obj, 'toString') // false

Function.prototype.apply( )第二个参数是个数组或者对象

Object.prototype.hasOwnProperty.call(obj, [])
配合数组对象的 slice 方法,可以将一个类似数组的对象(比如 arguments 对象)转为真正的数组。

Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
上面代码的 apply 方法的参数都是对象,但是返回结果都是数组,这就起到了将对象转成数组的目的。

Function.prototype.bind( )

bind 用于将函数体内的 this 绑定到某个对象,然后返回一个新函数

var d = new Date();
d.getTime() // 1481869925657

var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.