JavaScript 中 new 操作符的原理与手写实现

JavaScript 中 new 操作符的原理与手写实现详解

在 JavaScript 的编程世界里,new操作符是构建对象实例的核心工具。当我们写下new Person()这样简洁的代码时,其背后究竟隐藏着怎样精密的运作流程?接下来,就让我们深入剖析new操作符的工作原理,并一步步实现一个具备相似功能的自定义函数。

一、new 操作符如何创建对象

创建空对象

new操作符被调用时,JavaScript 引擎会立刻生成一个空的对象,形式上表现为{} 。这个空对象就像一座刚刚奠基的建筑,后续构造函数中的属性与方法会如同砖瓦一般,逐步为其增添功能与特性,它是最终实例对象的初始形态。例如,当执行new Car()时,引擎会率先创建一个空对象,为后续定义汽车的属性(如颜色、品牌)和方法(如启动、加速)做好准备。
2.

绑定原型链

新创建的空对象会与构造函数的原型对象建立起紧密的联系。具体而言,新对象的__proto__属性会被指向构造函数的prototype原型对象,从而构建起一条至关重要的原型链 。这条原型链是 JavaScript 实现继承机制的关键,它使得实例对象能够访问原型对象上定义的属性和方法。以Person构造函数为例,若在其原型上定义sayHello方法:

javascript 复制代码
function Person() {}
Person.prototype.sayHello = function() {
 	console.log("Hello!");
};
javascript 复制代码
const p1 = new Person() // p1是Person的实例
p1.sayHello()

当使用new Person()创建实例时,该实例便能调用sayHello方法,正是原型链发挥了作用,让实例拥有了从原型继承而来的能力。
3.

绑定 this 指向

在执行构造函数之前,JavaScript 会将构造函数内部的this关键字精准地指向新创建的空对象 。这一操作意义非凡,构造函数中所有对this的操作,无论是为对象添加属性,还是定义方法,都将围绕这个新对象展开。例如在Person构造函数中使用this.name = "Bob",实际上就是在为新创建的对象赋予name属性,并赋值为"Bob",塑造对象的个性化特征。

javascript 复制代码
function Person(name) {
  // 经过new之后 此时 this 已经指向了一个新的空对象 {} 
  this.name = name; // 给这个新对象添加属性 name
}

const p1 = new Person("Bob");
console.log(p1.name); // 输出 "Bob"

执行构造函数

构造函数内部的代码执行,初始化新对象 。由于构造函数的this指向的新对象,所以可以根据传入的参数,为新对象设置不同的属性值,定义专属的方法。比如,我们可以通过参数传递来初始化Person对象的姓名和年龄:

javascript 复制代码
function Person(name, age) {
	this.name = name;
	this.age = age;
}
const bob = new Person("Bob", 30);

​ 通过这种方式,每个新创建的Person对象都能拥有独特的属性值,展现出不同的状态。

返回实例对象

构造函数执行结束后,会涉及到返回值的处理,这一步决定了最终返回的对象形态。这里存在两种情况:

  • 返回值为对象 :若构造函数显式返回一个对象(例如return { job: "Engineer" }),new操作符会尊重这个返回值,直接返回该对象,之前创建的空对象将被舍弃。这赋予了构造函数极大的灵活性,开发者可以根据需求控制最终返回的实例形态。

    javascript 复制代码
    function Person(name,age){
        this.name = name
        this.age = age
        return {
            lable:'lable'
    	}
    }
    const p1 = new Person()
    console.log(p1 instanceof Person) // false
    console.log(p1)  // { lable: 'lable' }
  • 返回值为基本数据类型 :当构造函数返回基本数据类型(如return 10return "string")时,new操作符会无视这个返回值,仍然返回最初创建的新对象。这是因为new操作符的核心目标是创建对象实例,基本数据类型的返回值与这一目标不符。

    javascript 复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
      return 1
    }
    
    Person.prototype.say = function () {
      console.log("name", this.name, "age", this.age);
    };
    
    const p = new Person("张三", 18);
    console.log(p instanceof Person) // true
    console.log(p); //Person { name: '张三', age: 18 }

二、手写实现 new 功能

  1. 基于对new操作符原理的理解,我们可以动手编写一个函数,模拟new的功能。以下是具体的实现代码:

    javascript 复制代码
    function objectFactory() {
      //创建空对象
      let obj = {};
    
      // 获取argument中第一个参数  由于argument没有shift方法 这里将this指向argument
      let Constructor = [].shift.call(arguments);
    
      //绑定原型链
      obj.__proto__ = Constructor.prototype;
        
       // 绑定this指向  调用apply 让Constructor的this指向obj
      let result = Constructor.apply(obj, arguments); // 执行构造函数this 指向obj
    
    
      //   return typeof result === 'object'?result:obj;
      // 若构造函数返回的是一个不为null的对象则返回 result 否则返回obj
      // 若是一个null对象 result || obj 返回的是obj
      return typeof ret === "object" ? result || obj : obj;
    }

    在这个**objectFactory**函数中:

    • 首先创建一个空对象obj,对应new操作符创建空对象的步骤。
    • 接着通过**obj.__proto__ = Constructor.prototype建立原型链关系**,确保实例能够继承原型上的属性和方法。
    • 然后使用apply方法将构造函数的this指向obj ,并传入参数执行构造函数,执行结果存储在result中。
    • 最后根据result的类型进行判断,如果result是对象类型且不为null,则返回result否则返回最初创建的newObject ,实现与new操作符一致的返回逻辑。
  2. 测试

    javascript 复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    Person.prototype.say = function () {
      console.log("name", this.name, "age", this.age);
    };
    
    //与这个相同 let p = new Person("张三",18)
    let p = objectFactory(Person, "张三", 18);
    console.log(p); // Person { name: '张三', age: 18 } (这里由Person原型链指向 代表是谁的实例化)
    console.log(p instanceof Person); // 构造时有  obj.__proto__ = Constructor.prototype; 所以为true
    p.say();
相关推荐
sirius星夜36 分钟前
鸿蒙功效:"AbilitySlice"的远程启动和参数传递
javascript
彬师傅36 分钟前
JSAPITHREE-自定义瓦片服务加载
前端·javascript
梦语花39 分钟前
深入探讨前端本地存储方案:Dexie.js 与其他存储方式的对比
javascript
练习前端两年半39 分钟前
JavaScript当中的数据结构与算法
javascript
独立开发者Pony40 分钟前
关于我用 Ai 完成了一套系统 99% 代码这件事
前端·javascript·github
sirius星夜42 分钟前
HarmonyOS SDK 应用服务模块:通过 AccountManager 快速获取当前设备上的用户账户信息
javascript
潘小安1 小时前
『算法』图解数组排序全家桶 - 堆排序
算法·react.js·面试
默默地离开1 小时前
JS手搓代码----(new)
前端·javascript
泡芙同学1 小时前
如何用打包工具把一个复杂支持插件化的灵矶(node.js)打包成独立可执行程序(exe)
javascript
Sun_light1 小时前
AJAX揭秘 网页局部刷新其实很简单
前端·javascript