在 JavaScript 中,定义一个函数:

function fn(name) {
    this.name = name
}

 2. 普通调用

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

 4. 构造调用

function Fn(name) {
    this.name = name
}

const obj = new Fn('john')

console.log('name =', obj.name)

执行过程:

 • 创建一个新的空对象

 • 把新对象的原型指向 fn.prototype

 • 将 this 绑定到新对象

 • 执行函数体

 • 如果 return 返回的是对象,则返回该对象;否则返回基本类型会被忽略,并返回新创建的对象

 6. 模拟实现构造

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

 8. 流程图

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]

 10. class 类

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

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

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