JavaScript 中 fn() 和 new fn() 的区别
在 JavaScript 中,定义一个函数:
function fn(name) {
this.name = name
}
1. 普通调用
function fn(name) {
// this 指向全局对象
this.name = name
}
fn('john')
console.log('name =', globalThis.name)
'use strict'
function fn(name) {
// this 指向 undefined
// Uncaught TypeError: Cannot set properties of undefined (setting 'name')
this.name = name
}
fn('john')
• this 指向:
• 严格模式:undefined
• 非严格模式:全局对象(浏览器是 window,Node.js 是 global)
• 不会创建新对象
• 返回值:直接返回 return 的值;如果没有 return,返回 undefined
2. 构造调用
function Fn(name) {
this.name = name
}
const obj = new Fn('john')
console.log('name =', obj.name)
执行过程:
• 创建一个新的空对象
• 把新对象的原型指向 fn.prototype
• 将 this 绑定到新对象
• 执行函数体
• 如果 return 返回的是对象,则返回该对象;否则返回基本类型会被忽略,并返回新创建的对象
3. 模拟实现构造
function myNew(Constructor, ...args) {
const obj = Object.create(Constructor.prototype)
const result = Constructor.apply(obj, args)
return (result && typeof result === 'object') ? result : obj
}
function Fn(name) {
this.name = name
}
Fn.prototype.sayHi = function () {
console.log(`Hi, I'm ${this.name}`)
}
const p1 = myNew(Fn, 'john')
p1.sayHi() // Hi, I'm john
console.log(p1 instanceof Fn) // true
4. 流程图
flowchart TD
A[定义函数 fn] --> B1[普通调用 fn#40;#41;]
A --> B2[构造调用 new fn#40;#41;]
%% 普通调用流程
B1 --> C1[执行 fn 函数体]
C1 --> D1{严格模式?}
D1 -->|是| E1[this = undefined]
D1 -->|否| E2[this = 全局对象]
E1 --> F1[执行函数代码]
E2 --> F1
F1 --> G1{是否 return 值?}
G1 -->|是| H1[返回 return 的值]
G1 -->|否| H2[返回 undefined]
%% 构造调用流程
B2 --> C2[创建一个新对象]
C2 --> D2[新对象.__proto__ = fn.prototype]
D2 --> E3[this = 新对象]
E3 --> F3[执行 fn 函数体]
F3 --> G3{是否 return 对象?}
G3 -->|是| H3[返回该对象]
G3 -->|否| H4[返回 this]
5. class 类
在 es6 之前,还没有真正的类,es6 class 示例:
class Fn {
constructor(name) {
this.name = name
}
sayHi() {
console.log(`Hi, I'm ${this.name}`)
}
}