更深入的认识 this 语句和 new 关键字

三葉Leaves Author

这篇文章能让你对 this 和 new 语句的理解更深刻。如果你需要深刻明白原型链、继承等等内容,这块内容将变得很重要。

关于 this

场景A: 在构造函数里

我们先搞懂这块代码:

1
2
3
4
5
const obj = {}

obj.a = 1

console.log(obj.a); // 1

是不是很好理解?说简单点,当我们这样写

1
2
3
4
function Hero(name, hp) {
this.name = name; // 执行后,this ≈ { name: '亚瑟' }
this.hp = hp; // 执行后,this ≈ { name: '亚瑟', hp: 500 }
}

其实就很像是刚才那段代码:

1
obj.a = 1

只不过 obj 是一个确定的东西,this 则代表着将来创建出的东西,这就像函数的参数一样,参数就是留给未来的不确定的东西。

再回到这段代码:

1
2
3
4
5
6
function Hero(name, hp) {
this.name = name;
this.hp = hp;
}

const yase = new Hero('亚瑟', 500)

当我们写 new Hero(‘亚瑟’, 500) 时…

  1. this 是谁?

new 关键字会先在内存里创建一个全新的、空荡荡的对象。

然后,它会把这个函数里的 this 强制指向那个新创建的空对象。

你可以想象: this ≈ { } (一个空对象)

所以在这一刻,this 就代表那个即将诞生的 “亚瑟” 实例。

  1. this.name = name; 这句话做了什么?

它分为两部分:

  • this.name:这是在“点名”。它告诉 JS 引擎:“我要在 this 这个对象上操作一个叫做 name 的属性。”
  • = name:这是在“赋值”。它把传入的参数 name (也就是字符串 ‘亚瑟’) 的值,赋给 this 对象的 name 属性。

所以,这行代码的完整过程是:

this 所指向的那个新对象上,创建一个名为 name 的属性,并将外部传入的 name 变量的值赋给它。

简单来说,this.属性名 = 值 就是在 this 所代表的那个对象上“打点占地”,安放一个属性和它的值。

我之前有过疑问,在这个 function 里并没有用到 const 或者 let 声明 name 之类的属性,为什么直接就可以用了?这是因为对象的属性默认就是变量,不需要声明。从上文中,我们可以知道 this 实际上就是约等于一个空对象,我们也是往它上面打点占地了。

场景B: 在普通对象方法中

对于这种函数里的 this,就一句话:

谁调用它,this 就指向谁。如果是箭头函数,则指向外层作用域而不是调用者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let player = {
name: '小明',
level: 1,
levelUp: function() {
// `this` 是谁?
// 当代码执行 player.levelUp() 时,levelUp 方法是被 `player` 这个对象调用的。
// 所以,在这个函数内部,`this` 就指向 `player` 对象本身。
// `this` ≈ player ≈ { name: '小明', level: 1, levelUp: ƒ }

this.level = this.level + 1;
}
};

console.log(player.level); // 输出: 1
player.levelUp();
console.log(player.level); // 输出: 2

关于 new 关键字

new 是 JavaScript 中的一个“魔法”操作符。当你对一个函数使用 new 时,它并不仅仅是调用那个函数那么简单。JS 引擎在背后帮你完成了四个标准步骤,堪称“创世纪四部曲”:

假设执行了 new Hero('亚瑟', 500)

  1. 创建新对象(Create)

    • new 首先会凭空创建一个全新的、普通的对象。这个对象是 Object 的一个实例。

    相当于:

    1
    let newObject = {}

    实际情况比这个稍微复杂一点,但可以这么理解。

  2. 链接原型(Link)

    • new 会把这个新创建对象的 [[Prototype]](也就是 proto)属性,指向构造函数的 prototype 对象。

    相当于:

    1
    newObject.__proto__ = Hero.prototype
    • 这一步至关重要! 它建立了实例与原型之间的连接,原型链就此形成。未来的属性查找就靠这条链了。
  3. 绑定 this 并执行构造函数(Bind & Execute)

    • new 会将构造函数(Hero)的 this 关键字绑定到第一步创建的那个新对象上。

    • 然后,它会带着你传入的参数(‘亚瑟’, 500)去执行构造函数内部的代码。

    相当于:

    1
    Hero.call(newObject, '亚瑟', 500);
    • 这时,构造函数里的 this.name = name; 和 this.hp = hp; 就在为我们第一步创建的那个 newObject 添加属性了。执行完后,newObject 就变成了 { name: ‘亚瑟’, hp: 500 }。
  4. 返回新对象(Return)

    • 在构造函数执行完毕后,new 会自动 return 这个已经“装修”好的新对象(newObject)。

    • 特殊情况: 如果你在构造函数内部手动 return 了一个对象或数组,那么 new 操作的最终结果就是你手动 return 的那个对象,而不是 new 自己创建的那个。如果 return 的是原始类型(数字、字符串、布尔值等),则会被忽略,仍然返回 new 创建的对象。这是一个最佳实践:在构造函数里,没事别乱用 return。

让我们把这四步串起来,完整地看一下 let heroA = new Hero(‘亚瑟’, 500); 的全过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// JS 引擎的内心戏:
// 收到指令:new Hero('亚瑟', 500)

// 第1步:创建一个空对象
let obj = {};

// 第2步:将空对象的原型,链接到 Hero 的原型
obj.__proto__ = Hero.prototype;

// 第3步:将 Hero 函数的 this 指向这个新对象,并执行函数
// Hero.call(obj, '亚瑟', 500);
// Hero 函数内部开始执行:
obj.name = '亚瑟';
obj.hp = 500;
// Hero 函数执行完毕。现在 obj 是 { name: '亚瑟', hp: 500 }

// 第4步:返回这个加工好的对象
// 因为 Hero 函数没有手动 return 对象,所以自动返回 obj
// 最后,把这个返回的 obj 赋值给变量 heroA
let heroA = obj;
  • 标题: 更深入的认识 this 语句和 new 关键字
  • 作者: 三葉Leaves
  • 创建于 : 2025-07-22 00:00:00
  • 更新于 : 2025-08-13 16:31:27
  • 链接: https://blog.oksanye.com/007ebf992ffc/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论