技巧杂烩

JavaScript 中 fn() 和 new fn() 的区别

在 JavaScript 中,fn() 和 new fn() 看起来调用的都是同一个函数,但运行机制差异非常大…

JavaScript

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]

 5class 类

在 es6 之前,还没有真正的类,es6 class 示例:

class Fn {
    constructor(name) {
        this.name = name
    }

    sayHi() {
        console.log(`Hi, I'm ${this.name}`)
    }
}

文章标题:JavaScript 中 fn() 和 new fn() 的区别

文章作者:浅小沫

文章链接:https://blog.truimo.com/posts/js-fn-vs-new-fn


您可以自由在任何媒介以任何形式分享本作品,但需署名,且不得用于商业目的或改编。若分发衍生作品,须采用相同的许可协议。

本博客的所有原创内容采用 CC BY-NC-ND 4.0 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。