通过NEW 字段去“继承”函数,他的本质上是什么呢?或者说对于NEW函数的时候,他们在后面做了什么样的逻辑呢?

经过

首先我们可以回答第一个问题:他的继承的本质是什么,其实我们在js的继承部分就已经说过;对于这种new的形式
实际上 首先我们
创建一个新对象,并且将对象的**原型指向对应函数的原型对象 **,并且把函数的this指向新的对象
**
当然那我们是不是有一个具体的过程是什么呢?

01 我们会首先创建一个空对象
02 让对象的原型指向对应函数的原型对象
03 改变函数的this指向,让他指向对应生成的新的对象
04 如果一个函数有返回值的话;且返回值是函数,或者为非空的基本类型 就返回返回值
**

  1. function myNew(Func, ...args) {
  2. const instance = {};
  3. if (Func.prototype) {
  4. Object.setPrototypeOf(instance, Func.prototype)
  5. }
  6. const res = Func.apply(instance, args)
  7. if (typeof res === "function" || (typeof res === "object" && res !== null)) {
  8. return res
  9. }
  10. return instance
  11. }
  12. // 测试
  13. function Person(name) {
  14. this.name = name
  15. }
  16. Person.prototype.sayName = function() {
  17. console.log(`My name is ${this.name}`)
  18. }
  19. const me = myNew(Person, 'Jack')
  20. me.sayName()
  21. console.log(me)

无 return 语句

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

  1. function Foo(age) {
  2. this.age = age;
  3. }
  4. var o = new Foo(111);
  5. console.log(o);

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

return 对象类型数据

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

  1. function Foo(age) {
  2. this.age = age;
  3. return 1;
  4. }
  5. var o = new Foo(333);
  6. console.log(o);

原理

当使用 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.

创建 ECMAScript 原生对象 obj

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

obj 设置原生对象的内部属性;(和原型属性不同,内部属性表示为 [[PropertyName]],两个方括号包裹属性名,并且属性名大写,比如常见 [[Prototype]][[Constructor]]

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

设置 obj 的内部属性 [[Class]]Object

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

设置 obj 的内部属性 [[Extensible]]true

  1. Let proto be the value of calling the [[Get]] internal property of F with argument “prototype”.

proto 的值设置为 Fprototype 属性值;

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

如果 proto 是对象类型,则设置 obj 的内部属性 [[Prototype]] 值为 proto;(进行原型链关联,实现继承的关键

  1. 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.

如果 proto 是不对象类型,则设置 obj 的内部属性 [[Prototype]] 值为内建构造函数 Objectprototype 值;(函数 prototype 属性可以被改写,如果改成非对象类型,obj[[Prototype]] 就指向 Object 的原型对象)

  1. 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.

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

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

如果 resultObject 类型,返回 result

  1. Return obj. ```javascript 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 ```