this是什么
this 是一个关键字 用于指向函数在“运行时 (runtime)”所在的“执行上下文 (execution context)“
简单来说,this 就是“调用我的人”或“我所属的对象”。
this指向的四大法则(优先级从高到低)
法则一:new 绑定 (优先级最高)
当一个函数被用作构造函数,通过 new 关键字调用时,this 会被绑定到新创建的那个对象实例上。
function Person(name) {
// 在 new 调用时,JS 引擎会先创建一个空对象 {}
// 然后把 this 指向这个空对象
this.name = name;
console.log(this); // this -> 新创建的 Person 实例
}
const alice = new Person('Alice'); // { name: 'Alice' }
console.log(alice.name); // 输出: Alice
- 场景:这是 this 指向最明确、最没有争议的一种情况。
法则二:显式绑定 (call, apply, bind)
当一个函数通过 call(), apply(), 或 bind() 方法调用时,this 会被强制绑定到这些方法指定的第一个参数上。
这就像是在说:“嘿,函数,不管你本来是谁的,现在我命令你,你的 this 必须是‘我’!”
function sayHello() {
console.log("Hello, " + this.name);
}
const personA = { name: 'Alice' };
const personB = { name: 'Bob' };
// 使用 call,立即执行函数,并将 this 绑定到 personA
sayHello.call(personA); // 输出: Hello, Alice
// 使用 apply,与 call 类似,只是参数以数组形式传递
sayHello.apply(personB); // 输出: Hello, Bob
// 使用 bind,不会立即执行,而是返回一个 this 被永久绑定的新函数
const sayHelloToAlice = sayHello.bind(personA);
sayHelloToAlice(); // 输出: Hello, Alice
- 场景:当你需要在一个特定的上下文中执行一个函数时,这种方式非常有用。
法-则三:隐式绑定 (上下文对象调用)
当一个函数作为某个对象的方法被调用时(即通过 object.method() 的形式),this 会被绑定到那个直接调用它的对象上。
这就像是在说:“谁在点我,我 (this) 就是谁。”
const person = {
name: 'Alice',
sayHello: function() {
console.log("Hello, " + this.name); // this -> person 对象
}
};
person.sayHello(); // 输出: Hello, Alice
-
场景:这是面向对象编程中最常见的 this 指向。
-
隐式绑定的“陷阱”——丢失 this:
如果将对象的方法赋值给一个变量,然后再调用这个变量,this 的指向就会改变!codeJavaScript
const person = { name: 'Alice', sayHello: function() { console.log("Hello, " + this.name); } }; const greet = person.sayHello; // 只是把函数本身赋给了 greet greet(); // 输出: Hello, undefined (在非严格模式下) 或 TypeError (在严格模式下)- 为什么? 因为 greet() 在被调用时,它不再是通过 person. 来调用的,它是一个独立的函数调用。此时,它会应用下面的法则四。
法则四:默认绑定 (优先级最低)
当一个函数不满足以上任何一种绑定规则,被直接、独立地调用时(如 myFunction()),this 就会被绑定到全局对象上。
- 在浏览器的非严格模式下,全局对象是 window。
- 在严格模式 ("use strict") 下,this 会是 undefined。
// 非严格模式
function sayName() {
console.log(this.name);
}
var name = "Global Name"; // 在浏览器中,var 声明的全局变量会挂载到 window 上
sayName(); // 输出: Global Name (因为 this 指向了 window)
// 严格模式
"use strict";
function sayNameStrict() {
console.log(this); // 输出: undefined
console.log(this.name); // TypeError: Cannot read properties of undefined
}
sayNameStrict();
特例 箭头函数
箭头函数是 ES6 引入的,它完全不遵循上述四条黄金法则。
箭头函数的 this 指向规则只有一个:
箭头函数
没有自己的 this 绑定。它会捕获其“出生地”(定义时)所在的、最近一层非箭头函数的 this 值,并将其永久地作为自己的 this
const obj = {
name: 'RenRan',
normalFn: function() {
const p = ()=>{
console.log(this.name);
}
p()
},
arrowFn: () => {
console.log('arrowFn:', this.name)
}
}
obj.normalFn() // ✅ normalFn: RenRan
obj.arrowFn() // ❌ arrowFn: undefined(或空)
分析:p是箭头函数,没有的自己的this,找自己上层的第一个非箭头函数的this,即匿名函数function,它的this指向obj
arrowFn箭头函数的this为啥指向window,关键 对象字面量不是作用域(关键!)
在 JavaScript 里:
const obj = {
name: 'RenRan',
arrowFn: () => {
console.log(this)
}
}
这里的 { ... } 是对象字面量(object literal) ,
它只是一个值(object) ,不是作用域(scope) 。
箭头函数和普通函数的区别
一、this的区别
普通函数的this是在函数被调用的时候决定的(遵循四大法则,new绑定,显示绑定,隐式绑定,默认绑定)
箭头函数没有自己的this,它会捕获其“出生地”(定义时)所在的、上面最近一层非箭头函数的 this 值,并将其永久地作为自己的 this
二、 构造函数 (new)的区别
普通函数可以作为构造函数,箭头函数不能作为构造函数
三、箭头函数没有 arguments
arguments 是 JavaScript 函数内部自动创建的一个类数组对象,它包含了调用函数时传入的所有参数。
剩余参数允许你把函数中的 不确定数量的参数收集到一个数组中
四、 核心区别四:没有 prototype 属性
-
普通函数:
- 每个普通函数(除了内置函数)在创建时,都会自动获得一个 prototype 属性,它是一个对象。
- 这个 prototype 对象是实现 JavaScript 原型继承的核心。
-
箭头函数:
- 没有 prototype 属性。
- 这与它不能作为构造函数是一脉相承的。既然不能创建实例,自然也就不需要原型对象来让实例继承。