小帅の技术博客 小帅の技术博客
首页
  • 基础
  • 框架
  • 进阶
  • 工程化
  • NodeJS
  • 脚本
  • 拓展
  • 技术
  • 服务器
程序猿
关于
友链
  • 分类
  • 标签
  • 归档
GitHub

前端小帅

学而不思则罔,思而不学则殆
首页
  • 基础
  • 框架
  • 进阶
  • 工程化
  • NodeJS
  • 脚本
  • 拓展
  • 技术
  • 服务器
程序猿
关于
友链
  • 分类
  • 标签
  • 归档
GitHub
  • 基础

    • 发布订阅模式vs观察者模式
    • 事件通信研究
    • JavaScript数组方法reduce的妙用
    • 记忆函数memoize
    • JS类型、类型判断、类型转换
    • 浏览器中JavaScript的运行机制
    • WebSocket连接过程及原理分析
    • 执行上下文
    • 作用域与闭包
    • JavaScript进阶之map与reduce的前世今生
    • JavaScript之new的执行过程
      • 介绍
        • 语法
        • 用法与特点
        • 描述
      • 实现
      • 总结
      • 交流
    • 从输入 URL 到页面加载完成发生了什么?
    • 说说call、apply、bind是如何改变this的
  • 工程化

  • 框架

  • 精进

  • 其他

  • 前端
  • 基础
sunss
2024-03-26

JavaScript进阶—— new 的执行过程

本文为面试专题之JavaScript进阶——原理篇系列,new 的执行过程。

# 介绍

引用MDN的官方介绍,是这样定义 new 的:

new 运算符允许开发人员创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例

注:new 在JavaScript中是一个关键字。

# 语法

new constructor
new constructor()
new constructor(arg1)
new constructor(arg1, arg2)
new constructor(arg1, arg2, /* …, */ argN)
1
2
3
4
5
  • constructor:一个指定对象实例的类型的类或函数。
  • arg:一个用于被 constructor 调用的值列表。new Foo 与 new Foo() 等价,换句话说:如果没有指定参数列表,则在不带参数的情况下调用 Foo。

# 用法与特点

举个栗子:

function Parent(name) {
  this.name = name;
}
Parent.prototype.sayName = function () {
  return `我的名字是:${this.name}`
}

const son = new Parent("小帅");
console.log(son.name); // 访问构造函数里的属性
// 小帅

console.log(son.sayName()); // 访问原型里的属性
// 我的名字是:小帅
1
2
3
4
5
6
7
8
9
10
11
12
13
  1. 可以访问构造函数里的属性
  2. 可以访问原型上的属性

# 描述

当使用 new 关键字调用函数时,该函数将被用作构造函数。new 将执行以下操作:

  1. 创建一个空的 JavaScript 对象 obj。
  2. 将 obj 的 prototype 指向构造函数的 prototype 属性
  3. 使用给定参数执行构造函数,并将 obj 绑定为 this 的上下文(换句话说,在构造函数中的所有 this 引用都指向 obj)
  4. 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象

# 实现

function myNew() {
  // 1. 获取构造函数(参数对象里的第一个)
  const constructor = [...arguments][0]
  // 2. 创建对象
  const obj = Object.create(constructor.prototype)
  // 3. 执行传入构造函数,并修改 this
  const result = constructor.apply(obj, [...arguments].slice(1))
  // 4. 根据执行函数的返回值,判断是返回结果还是返回 obj 对象
  const isResult = (typeof result === 'object' && result !== null) || typeof result === "function"
  return isResult ? result : obj
}
1
2
3
4
5
6
7
8
9
10
11

或者你也可以这样写:

function myNew(fn, ...args) {
  // 1. 获取构造函数
  const constructor = fn
  // 2. 创建对象 ,并指定原型
  const obj = Object.create(constructor.prototype)
  // 3. 执行传入构造函数,并修改 this
  const result = constructor.apply(obj, args)
  // 4. 根据执行函数的返回值,判断是返回结果还是返回 obj 对象
  const isResult = (typeof result === 'object' && result !== null) || typeof result === "function"
  return isResult ? result : obj
}

// 测试下,结果也是一致的
const son = myNew(Parent, "小帅");
console.log(son.name); // 访问构造函数里的属性
// 小帅

console.log(son.sayName()); // 访问原型里的属性
// 我的名字是:小帅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

其中步骤 2 也可以这样写:

// 1. __proto__
const obj = new Object()
obj.__proto__ = constructor.prototype

// 2. setPrototypeOf
// 指定原型链的终点null为其原型
const obj = Object.create(null) 
const propto = constructor.prototype
// setPrototypeOf方法可以把Object.create(null)指定null的创建强制修改原型
Object.setPrototypeOf(obj, propto) 
1
2
3
4
5
6
7
8
9
10

# 总结

简单来说,new 做的事情就是继承属性和方法,并改变this的上下文。

其实,通过手写 new 的实现,你应该可以发现,针对本文 new 的创建过程这个问题,仔细思考下...

我们完全可以把他看做是对原型链的一种考察,其中涉及的构造函数、prototype、__proto__、Object.create、Object.setPrototypeOf 等概念与方法,是不是又特别的熟悉呢?

其实,只要弄懂了JavaScript的原型与继承,也就明白了本文的内容了~

👀原型链的相关进阶文章请持续关注面试专栏的更新~

# 交流

好了,本文到此结束,欢迎来撩,一起学习🙋‍♂️~

面试相关的文章及代码demo,后续打算在这个仓库(JS-banana/interview: 面试不完全指北 (github.com) )进行维护,欢迎✨star,提建议,一起进步~

编辑
#JavaScript
上次更新: 2024/04/15, 14:35:14
JavaScript进阶之map与reduce的前世今生
从输入 URL 到页面加载完成发生了什么?

← JavaScript进阶之map与reduce的前世今生 从输入 URL 到页面加载完成发生了什么?→

最近更新
01
说说call、apply、bind是如何改变this的
03-29
02
从输入 URL 到页面加载完成发生了什么?
03-29
03
JavaScript进阶——map与reduce的前世今生😋
03-24
更多文章>
sunss | © 2020.08-2024.04 浙ICP备2022002957号-1
载入天数... 载入时分秒...  |  总访问量 次
提供CDN加速/云存储服务
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式