0

0

关于JS中new调用函数的原理介绍

不言

不言

发布时间:2018-07-10 17:38:10

|

2527人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了关于js中new调用函数的原理介绍,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

JavaScript 中经常使用构造函数创建对象(通过 new 操作符调用一个函数),那在使用 new 调用一个函数的时候到底发生了什么?先看几个例子,再解释背后发生了什么。

1)看三个例子

1.1 无 return 语句

构造函数最后没有 return 语句,这也是使用构造函数时默认情况,最后会返回一个新对象,如下:

function Foo(age) {
  this.age = age;
}

var o = new Foo(111);
console.log(o);

这是常见的使用构造函数创建对象的过程,打印出来的是 {age: 111}

1.2 return 对象类型数据

构造函数最后 return 对象类型数据:

function Foo(age) {
  this.age = age;

  return { type: "我是显式返回的" };
}

var o = new Foo(222);
console.log(o);

打印出来的是 {type: '我是显式返回的'},也就是说,return 之前的工作都白做了,最后返回 return 后面的对象。

1.3 return 基本类型数据

那是不是只要构造函数体内最后有 return,返回都是 return 后面的数据呢?

我们看下返回基本类型数据的情况:

function Foo(age) {
  this.age = age;

  return 1;
}

var o = new Foo(333);
console.log(o);

打印出来的是 {age: 333},和没有 return 时效果一样。跟预期不一样,背后你原理看下面分析。

2)背后原理

2.1 非箭头函数的情况

当使用 new 操作符创建对象是,ES5 官方文档在 函数定义 一节中做了如下定义 13.2.2 [[Construct]]

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:

  1. Let obj be a newly created native ECMAScript object.

  2. Set all the internal methods of obj as specified in 8.12.

  3. Set the [[Class]] internal property of obj to Object.

  4. Set the [[Extensible]] internal property of obj to true.

  5. Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".

  6. If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.

  7. If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.

  8. Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.

  9. If Type(result) is Object then return result.

    WEBGM游戏金币虚拟货币交易源代码
    WEBGM游戏金币虚拟货币交易源代码

    WEBGM2.0版对原程序进行了大量的更新和调整,在安全性和实用性上均有重大突破.栏目介绍:本站公告、最新动态、网游资讯、游戏公略、市场观察、我想买、我想卖、点卡购买、火爆论坛特色功能:完美的前台界面设计以及人性化的管理后台,让您管理方便修改方便;前台介绍:网站的主导行栏都采用flash设计,美观大方;首页右侧客服联系方式都采用后台控制,修改方便;首页中部图片也采用动态数据,在后台可以随意更换图片

    下载
  10. Return obj.

看第 8、9 步:

8)调用函数 F,将其返回值赋给 result;其中,F 执行时的实参为传递给 [[Construct]](即 F 本身) 的参数,F 内部 this 指向 obj;9)如果 result 是 Object 类型,返回 result;

这也就解释了如果构造函数显式返回对象类型,则直接返回这个对象,而不是返回最开始创建的对象。

最后在看第 10 步:

10)如果 F 返回的不是对象类型(第 9 步不成立),则返回创建的对象 obj

如果构造函数没有显式返回对象类型(显式返回基本数据类型或者直接不返回),则返回最开始创建的对象。

2.2 箭头函数的情况

那如果构造函数是箭头函数怎么办?

箭头函数中没有 [[Construct]] 方法,不能使用 new 调用,会报错。

NOTICE:其中 [[Construct]] 就是指构造函数本身。

相关规范在 ES6 的官方文档 中有提,但自从 ES6 以来的官方文档巨难懂,在此不做表述。

3)new 调用函数完整过程

3.1 中文描述及相关代码分析

除了箭头函数之外的任何函数,都可以使用 new 进行调用,背后发生了什么,上节英文讲述的很清楚了,再用中文描述如下:

1)创建 ECMAScript 原生对象 obj;  
2)给 obj 设置原生对象的内部属性;(和原型属性不同,内部属性表示为 [[PropertyName]],两个方括号包裹属性名,并且属性名大写,比如常见 [[Prototype]][[Constructor]])  
3)设置 obj 的内部属性 [[Class]]Object;  
4)设置 obj 的内部属性 [[Extensible]]true;  
5)将 proto 的值设置为 Fprototype 属性值;  
6)如果 proto 是对象类型,则设置 obj 的内部属性 [[Prototype]] 值为 proto;(进行原型链关联,实现继承的关键)  
7)如果 proto 是不对象类型,则设置 obj 的内部属性 [[Prototype]] 值为内建构造函数 Objectprototype 值;(函数 prototype 属性可以被改写,如果改成非对象类型,obj[[Prototype]] 就指向 Object 的原型对象)  
8)9)10)见上节分析。(决定返回什么)

对于第 7 步的情况,见下面代码:

function Foo(name) {
  this.name = name;
}

var o1 = new Foo("xiaoming");
console.log(o1.__proto__ === Foo.prototype); // true

// 重写构造函数原型属性为非对象类型,实例内部 [[Prototype]] 属性指向 Object 原型对象
// 因为实例是一个对象类型的数据,默认会继承内建对象的原型,
// 如果构造函数的原型不满足形成原型链的要求,那就跳过直接和内建对象原型关联
Foo.prototype = 1;
var o2 = new Foo("xiaohong");
console.log(o2.__proto__ === Foo.prototype); // false
console.log(o2.__proto__ === Object.prototype); // true

3.2 更简洁的语言描述

若执行 new Foo(),过程如下:

1)创建新对象 o;  
2)给新对象的内部属性赋值,关键是给[[Prototype]]属性赋值,构造原型链(如果构造函数的原型是 Object 类型,则指向构造函数的原型;不然指向 Object 对象的原型);  
3)执行函数 Foo,执行过程中内部 this 指向新创建的对象 o;  
4)如果 Foo 内部显式返回对象类型数据,则,返回该数据,执行结束;不然返回新创建的对象 o

4)几点说明

4.1 判断是否是 Object 类型

关于一个数据是否是 Object 类型,可以通过 instanceof 操作符进行判断:如果 x instanceof Object 返回 true,则 xObject 类型。

由上可知,null instanceof Object 返回 false,所以 null 不是 Object 类型,尽管typeof null 返回 "Object"。

4.2 instanceof 原理

instanceof 的工作原理是:在表达式 x instanceof Foo 中,如果 Foo 的原型(即 Foo.prototype)出现在 x 的原型链中,则返回 true,不然,返回 false

因为函数的原型可以被改写,所以会出现在 x 通过 Foo new 出来之后完全改写 Foo 的原型 x instanceof Foo 返回 false 的情况。因为实例创建之后重写构造函数原型,实例指向的原型已经不是构造函数的新的原型了,见下面代码:

const Foo = function() {};

const o = new Foo();

o instanceof Foo; // true

// 重写 Foo 原型
Foo.prototype = {};
o instanceof Foo; // false

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

16

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

23

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

75

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

95

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

218

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

420

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

168

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

222

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

33

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 13.2万人学习

CSS3 教程
CSS3 教程

共18课时 | 7万人学习

Vue 教程
Vue 教程

共42课时 | 9.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号