JavaScript——new关键字详解

news2025/2/5 2:48:21

一、new原理

new的实现步骤(原理)如下:

  1. 第一步:创建一个空对象,作为将要返回的对象
  2. 第二步:将这个空对象的原型指向构造函数的prototype属性,也就是将对象的__proto__属性指向构造函数的prototype【让对象能沿着原型链去使用构造函数中prototype上的方法】
  3. 第三步:将这个空对象赋值给构造函数内部的this关键字,执行构造函数。【让构造器中设置的属性和方法设置在这个对象上】
  4. 第四步:返回这个对象。
function F() {}
let f = new F()

F构造函数为例,上面原理转换为伪代码大概是这样的:

  1. let obj = {}
  2. obj.__proto__ = F.prototype
  3. F.apply(obj, 参数)
  4. return obj

因此,我们可以手搓一个new方法试试:

let _new = function (F, ...args) {
  // let obj = {};
  // obj.__proto__ = F.prototype;
  let obj = Object.create(F.prototype);  // 简写
  F.apply(obj, args);
  return obj;
};

下面我们通过对比原生的new和我们手搓的_new的输出结果以验证手搓的_new效果如何:

let F = function (val, num) {  // 构造函数
  this.val = num;
  this.num = val;
  this.hello = function hello() {};
  function hi() {}
};
let _new = function (F, ...args) {  // 手搓new方法
  // let obj = {};
  // obj.__proto__ = F.prototype;
  let obj = Object.create(F.prototype);  // 简写
  F.apply(obj, args);
  return obj;
};
let f1 = new F(1, 2);
console.log(new F(1, 2));  // 原生的new的实例化输出结果
console.log(_new(F, 1, 2));  // 手搓的_new的实例化输出结果

上述代码运行结果如下:

可以看到手搓的_new方法实现效果是和原生new一样的。

二、new function和new class的区别

functionclass都可以作为构造函数,但它们之间也有不少区别:

  1. funtion定义构造函数存在提升,可以先使用后定义;class定义构造函数不存在提升,只能先定义后使用,否则会报错。

    // funtion定义构造函数存在提升,可以先使用后定义
    console.log(new F4());
    function F4() {
      this.name = 1;
    }
    // class定义构造函数不存在提升,只能先定义后使用
    class F5 {
      constructor() {
        this.name = 1;
      }
    }
    console.log(new F5());
    

    输出结果:在这里插入图片描述

    1. class不能调用call、apply、bind改变执行上下文。

      function F5() {
          console.log(this.name);
      }
      const obj1 = {
          name: 'Jack',
      };
      F5.call(obj1); // Jack
      
      class F6 {
          constructor() {
              console.log(this.name);
          }
      }
      const obj2 = {
          name: 'Jack',
      };
      F6.call(obj2); // Class constructor F6 cannot be invoked without 'new'
      

三、function作为构造函数的注意事项

  1. function尽量别有返回值,如果有返回值会根据返回值按如下处理:

    • 返回值不是对象:无视返回值,输出的实例对象结果是this对象。
    • 返回值是对象:将function当成方法处理,就不再是构造函数了。
    function F7() {
      this.name = "Jack";
      this.age = 18;
      return { name: "AAA" };
    }
    let f7 = new F7();
    console.log(f7); // {name: 'AAA'}
    
    function F8() {
      this.name = "Jack";
      this.age = 18;
      console.log(this); // F8 {name: 'Jack', age: 18}  这是this对象
      return 1;
    }
    let f8 = new F8();
    console.log(f8); // F8 {name: 'Jack', age: 18}   这是this对象
    
  2. 实例化对象需要加new,加new后构造函数里的this就指向该实例,不加的话指向的是window

    function F9(name, age) {
      this.name = name;
      this.age = age;
    }
    // 加new
    let f9_1 = new F9("Jack-1", 18);
    console.log(f9_1.name); // Jack-1
    // 不加new
    let f9_2 = F9("Jack-2", 18);
    // console.log(f9_2.name); // 报错
    console.log(window.name); // Jack-2 在window上 说明this指向window
    

为了避免第二个注意事项,我们可以在定义构造函数时添加一个判断来处理忘记加new的情况:

function F9(name, age) {
  // 处理漏加new的情况
  if (!(this instanceof F9)) {
    return new F9(name, age);
  }
  this.name = name;
  this.age = age;
}

测试结果:

// 加new
let f9_1 = new F9("Jack-1", 18);
console.log(f9_1.name); // Jack-1
// 不加new
let f9_2 = F9("Jack-2", 18);
console.log(f9_2.name); // Jack-2

可以看到这种方式是没有问题。

四、new一个箭头函数会怎么样

箭头函数是ES6中提出来的,它没有prototype,也没有自己的this指向,更可以使用arguments参数,所以不能new一个箭头函数。它会报如下错误:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1337160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何给beaglebone black狗板扩容

接上一篇 beaglebone black狗板,交叉编译Qt5(eglfs)-CSDN博客 默认的分区大小已经不够了,需要调整 这里改成500M,能勉强正常,但是SD是32G还是有大量的剩余空间没被使用 这里可以用以下两类方法来把剩余的…

Spring Boot整合MyBatis-Plus框架快速上手

最开始,我们要在Java中使用数据库时,需要使用JDBC,创建Connection、ResultSet等,然后我们又对JDBC的操作进行了封装,创建了许多类似于DBUtil等工具类。再慢慢的,出现了一系列持久层的框架:Hiber…

【Linux驱动】驱动框架的进化 | 总线设备驱动模型

🐱作者:一只大喵咪1201 🐱专栏:《Linux驱动》 🔥格言:你只管努力,剩下的交给时间! 目录 🥩驱动框架的进化🥠分层🥠面向对象🥠编程&am…

一台服务器​最大并发 tcp 连接数多少?65535?

首先,问题中描述的65535个连接指的是客户端连接数的限制。 在tcp应用中,server事先在某个固定端口监听,client主动发起连接,经过三次握手后建立tcp连接。那么对单机,其最大并发tcp连接数是多少呢? 如何标…

将elementUI,NaiveUI的progress环形进度条设置为渐变色

需求 :进度条要有一个渐变效果。效果图: NaiveUI和elementUI的官方progress组件都是只能设置一种颜色,不符合需求所以改一下。 其实NaiveUI和elementUI设置进度条的实现方式基本一样都是使用svg渲染出两个path,第一个是底色&…

教你一分钟弄清屏幕SPI接口名称

相关文章 快速入门ESP32——开发环境配置Arduino IDE 快速入门ESP32——开发环境配置PlatformIO IDE 快速入门ESP32—— platformIO添加开源库和自己的开发库 一分钟弄清屏幕SPI接口名称 前言一、屏幕SPI接口名称二、与单片机连接总结 前言 最近,我在捣鼓CD屏幕的SP…

服务器系统时间不同步如何处理

在分布式计算环境中,服务器系统时间的同步至关重要。然而,由于各种原因,服务器系统时间不同步的问题时有发生,这可能会导致严重的问题,如日志不准确、证书验证失败等。下面我们可以一起探讨下造成服务器系统时间不同的原因以及解决…

理解io/nio/netty

一、io io即input/output,输入和输出 1.1 分类 输入流、输出流(按数据流向) 字节流(InputStream/OutputStream(细分File/Buffered))、字符流(Reader/Writer(细分File/Buffered/pu…

iClient for JavaScript如何以mvt矢量瓦片的形式加载数据服务

刘大 这里写目录标题 前言1.iServer中的预览页面2.iClient for JavaScript加载2.1 构建Style2.2 iCient加载2.2.1Leaflet & MapboxGL2.2.2 OpenLayers 前言 在提到查看iServer REST数据服务的概况的时候,大家总会想到说,通过发布对应的地图服务或者…

一文读懂SoBit 跨链桥教程

从BTC网络到Solana网络桥接BRC20 1.打开SoBit平台:在您的网络浏览器中启动SoBit Bridge应用程序。 2.连接您的钱包: 选择SoBit界面右上角的比特币网络来连接您的数字钱包。 3.选择源链、目标链和您想桥接的代币: 从下拉菜单中选择’BTC’作为…

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集 HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤。 由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小&#x…

k8s---kubernets

目录 一、Kurbernetes 1.2、K8S的特性: 1.3、docker和K8S: 1.4、K8S的作用: 1.5、K8S的特性: 二、K8S集群架构与组件: 三、K8S的核心组件: 一、master组件: 1、kube-apiserver&#xff1…

【Spring实战】07 JPA

文章目录 1. 定义2. 出现原因3. 添加依赖4. 使用1)创建 Repository 接口2)自定义查询方法(非必须)3)创建实体类4)调用方法 5. 验证6. 优点7. 缺点8. 详细代码总结 1. 定义 Spring Data JPA 是 Spring 提供…

C# 编写简单二维码条形码工具

C# 二维码条形码工具 该工具简单实现了二维码条形码生成与识别功能,识别方式:通过摄像头实时识别或通过图片文件识别。 using AForge.Genetic; using AForge.Video.DirectShow; using System; using System.Collections.Generic; using System.Component…

实习知识整理6:前后端利用jQuery $.ajax数据传输的四种方式

方式1&#xff1a;前端发送key/value(String字符串)&#xff0c;后台返回文本 前端&#xff1a; <input id"test1" type"button" value"前端发送key/value(String字符串)&#xff0c;后台返回文本"/> $(function() {$("#test1&quo…

YHZ001 Python 简介

配套视频链接: YHZ001 Python 简介 目录 &#x1f649; Python的历史&#x1fab1; Python的作者&#x1f98a; Python 的优缺点&#x1f417; Python 的应用领域&#x1f41e; Python 哲学&#x1f430; Python 解释器 &#x1f649; Python的历史 1989年圣诞节&#xff1a; …

数据智慧:C#中编程实现自定义计算的Excel数据透视表

前言 数据透视表&#xff08;Pivot Table&#xff09;是一种数据分析工具&#xff0c;通常用于对大量数据进行汇总、分析和展示。它可以帮助用户从原始数据中提取关键信息、发现模式和趋势&#xff0c;并以可视化的方式呈现。 在数据透视表中&#xff0c;数据分析师通常希望进…

Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Redis Streams在Spring Boot中的应用&#xff1a;构建可靠的消息队列解决方案 引言前言Redis Streams的基本概念和特性1. 日志数据结构2. 消息和字段3. 消费者组4. 消息ID5. 实时和历史数据处理6. 性能…

1.决策树

目录 1. 什么是决策树? 2. 决策树的原理 2.1 如何构建决策树&#xff1f; 2.2 构建决策树的数据算法 2.2.1 信息熵 2.2.2 ID3算法 2.2.2.1 信息的定义 2.2.2.2 信息增益 2.2.2.3 ID3算法举例 2.2.2.4 ID3算法优缺点 2.2.3 C4.5算法 2.2.3.1 C4.5算法举例 2.2.4 CART算法 2.2.4…

智能优化算法应用:基于孔雀算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于孔雀算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于孔雀算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.孔雀算法4.实验参数设定5.算法结果6.参考文献7.MA…