别再蒙了! new操作符工作原理全面解析

new的作用 ✨✨✨

  1. 通过new操作符创建一个构造函数实例。
  2. 首选初始化一个空的obj对象
  3. 实例对象的__proto__指向构造函数的prototype
  4. 构造函数中的this指向实例对象
  5. 如果构造函数有返回值并且是引用类型值,则返回此返回值;如果没有返回值或者返回值为基础类型值,则返回obj对象。

实现myNew()函数

js 复制代码
function myNew(Con, ...args) {
  let obj = {}; // 创建一个空对象
  Object.setPrototypeOf(obj, Con.prototype);  // 将obj的__proto__设置为Con.prototype,接入原型链
  let result = Con.apply(obj, args); // 将构造函数中的this指向obj,并将构造函数参数传递给构造函数
  return result instanceof Object ? result : obj; // 判断构造函数是否返回值是否为引用类型值如果是则返回,否则返回实例对象obj
}

function Fn() {
  this.name = "zhangsan";
  this.age = 18;
}

let obj = myNew(Fn);
console.log(obj); // Fn { name: 'zhangsan', age: 18 }

手动中断原型链问题

思考一下下面代码的打印的值应该是什么?

js 复制代码
function Fn(name, age) {
  this.name = name;
  this.age = age;
}
Fn.prototype = null;
const obj = new Fn("zhangsan", 22);
console.log(obj.__proto__ == Object.prototype);
console.log(obj.__proto__ == Fn.prototype); 

可能有人会感觉应该是false 和 true ,但是在控制台输出的却是true 和 false,这就让人很疑惑了。为什么将Fn.prototype = null并且Object.setPrototypeOf(obj,Fn.prototype)两者应该相等才对啊!!!为什么obj.__proto__ = Object.prototype呢?

通过查阅资料有以下解释:

对象的 __proto__ 属性在查找上溯原型链的特性,是 JavaScript 中原型继承的核心机制之一。 这一机制可以在 ECMAScript 语言规范中找到相关描述:

ECMAScript® 2022 Language Specification - 9.1.1 Ordinary Object Internal Methods and Internal Slots When a constructor creates an object, that object implicitly references the constructor's "prototype" property for the purposes of resolving property references. The [[Prototype]] link is set at the time of object creation. The value of the object's [[Prototype]] internal slot is retrieved from the constructor's "prototype" property only once, at object creation time. If the value of the constructor's "prototype" property is modified after the object is created, the object's [[Prototype]] is not updated to reflect the change.

这里明确指出,对象的 [[Prototype]] 内部属性(在 JS 中为 __proto__ 属性)是在对象创建时从构造函数的 prototype 属性获取的。

9.1.2 Object Internal Methods and Internal Slots The value of the [[Prototype]] internal slot of an object may be accessed at run-time using the Object.getPrototypeOf abstract operation. Setting the [[Prototype]] internal slot of an object at run-time is accomplished using the Object.setPrototypeOf abstract operation. The [[Prototype]] internal slot of an object may also be exposed indirectly to ECMAScript code using the accessors Object.prototype.__proto__ or Object.prototype.isPrototypeOf.

这里说明了 [[Prototype]] 可以通过 Object.getPrototypeOf 来获取,也提到了 __proto__ 的访问器的作用。

8.3.1 [[GetPrototypeOf]] () > The [[GetPrototypeOf]] internal method of a native ECMAScript object O performs the following steps:

  1. Return ? O.[GetPrototypeOf].
  2. If O does not have a [[Prototype]] internal slot, then a. Return null.
  3. Let proto be the value of O's [[Prototype]] internal slot.
  4. If proto is not null, return proto.
  5. Return null.

这里详细描述了 [[GetPrototypeOf]] 的执行步骤,其中第 4 步表明如果当前对象的 [[Prototype]] 不为 null,则会返回继续上溯原型链。 所以 ECMAScript 规范中确实明确了对象 __proto__ 属性在找不到当前构造函数的 prototype 时,会继续在原型链上逐级查找的机制,这也保证了原型链不会因某个构造函数的 prototype 被修改或删除而中断。

通过上面的解释我们可以得出当手动中断构造函数的原型链时Fn.prototype = null,其构造函数实例化出来的实例对象的obj.__proto__不会指向Fn.prototype。而是根据js运行机制按照默认原型链想上寻找最近的原型并将其赋值给obj.__proto__。为了保证原型链的完整性。

由此我们可能会想到如果将Fn.prototype 设置为其他基本类型呢结果会是怎么样呢?那让我们来试一下吧!!!这里就展示Symbol的结果为true 和 false,其他的大家可以自行测试。 所以如果将构造函数的prototype设置为基本数据类型,实例对象的原型会指向对象的原型Object.prototype,😊😎 OK

js 复制代码
function Fn(name, age) {
  this.name = name;
  this.age = age;
}
let str = "";
let num = 111;
let bol = true;
let bigNum = BigInt(12345678901234567890);
let symbol = Symbol();
let und = undefined;
let nul = null;
Fn.prototype = symbol;
const obj = new Fn("zhangsan", 22);
console.log(obj.__proto__ == Object.prototype); // true
console.log(obj.__proto__ == Fn.prototype); // false

问题又来了!😁如果将构造函数的原型赋值为引用类型值呢?这个应该都知道哦😉我们来试一下。

js 复制代码
function Fn(name, age) {
  this.name = name;
  this.age = age;
}
let str = new String();

Fn.prototype = str;
const obj = new Fn("zhangsan", 22);
console.log(obj.__proto__); // String {''}
console.log(obj.__proto__ == Object.prototype); // false
console.log(obj.__proto__ == Fn.prototype); // true

从结果中可以知道,此时完全符合预期哦😉

OK,今天你学fei了吗?😁😎😊

相关推荐
AI浩4 小时前
【Labelme数据操作】LabelMe标注批量复制工具 - 完整教程
运维·服务器·前端
涔溪4 小时前
CSS 网格布局(Grid Layout)核心概念、基础语法、常用属性、实战示例和进阶技巧全面讲解
前端·css
2401_878454534 小时前
浏览器工作原理
前端·javascript
西陵5 小时前
为什么说 AI 赋能前端开发,已经不是选择题,而是必然趋势?
前端·架构·ai编程
by__csdn6 小时前
Vue3 setup()函数终极攻略:从入门到精通
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
天天扭码6 小时前
前端如何实现RAG?一文带你速通,使用RAG实现长期记忆
前端·node.js·ai编程
Luna-player7 小时前
在前端中,<a> 标签的 href=“javascript:;“ 这个是什么意思
开发语言·前端·javascript
lionliu05197 小时前
js的扩展运算符的理解
前端·javascript·vue.js
小草cys7 小时前
项目7-七彩天气app任务7.4.2“关于”弹窗
开发语言·前端·javascript
奇舞精选7 小时前
GELab-Zero 技术解析:当豆包联手中兴,开源界如何守住端侧 AI 的“最后防线”?
前端·aigc