this
this 可以用在构造函数之中,表示实例对象。除此之外,this 还可以用在别的场合。但不管是什么场合,this 都有一个共同点:它总是返回一个对象。
this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同
在函数中使用this,它的指向完全取决于函数是如何被调用的
| 调用方式 | 示例 | 函数中的this指向 |
|---|---|---|
| 通过new调用 | new method() | 创建的实例对象 |
| 直接调用 | method() | 全局对象 |
| 通过对象调用 | obj.method() | 前面的对象 |
| call | method.call(ctx) | call的第一个参数 |
| apply | method.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.