通过NEW 字段去“继承”函数,他的本质上是什么呢?或者说对于NEW函数的时候,他们在后面做了什么样的逻辑呢?
经过
首先我们可以回答第一个问题:他的继承的本质是什么,其实我们在js的继承部分就已经说过;对于这种new的形式
实际上 首先我们
创建一个新对象,并且将对象的**原型指向对应函数的原型对象 **,并且把函数的this指向新的对象
**
当然那我们是不是有一个具体的过程是什么呢?
01 我们会首先创建一个空对象
02 让对象的原型指向对应函数的原型对象
03 改变函数的this指向,让他指向对应生成的新的对象
04 如果一个函数有返回值的话;且返回值是函数,或者为非空的基本类型 就返回返回值
**
function myNew(Func, ...args) {const instance = {};if (Func.prototype) {Object.setPrototypeOf(instance, Func.prototype)}const res = Func.apply(instance, args)if (typeof res === "function" || (typeof res === "object" && res !== null)) {return res}return instance}// 测试function Person(name) {this.name = name}Person.prototype.sayName = function() {console.log(`My name is ${this.name}`)}const me = myNew(Person, 'Jack')me.sayName()console.log(me)
无 return 语句
构造函数最后没有 return 语句,这也是使用构造函数时默认情况,最后会返回一个新对象,如下:
function Foo(age) {this.age = age;}var o = new Foo(111);console.log(o);
这是常见的使用构造函数创建对象的过程,打印出来的是 {age: 111}。
return 对象类型数据
构造函数最后 return 对象类型数据:
function Foo(age) {this.age = age;return 1;}var o = new Foo(333);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:
- Let obj be a newly created native ECMAScript object.
创建 ECMAScript 原生对象 obj;
- Set all the internal methods of obj as specified in 8.12.
给 obj 设置原生对象的内部属性;(和原型属性不同,内部属性表示为 [[PropertyName]],两个方括号包裹属性名,并且属性名大写,比如常见 [[Prototype]]、[[Constructor]])
- Set the [[Class]] internal property of obj to Object.
设置 obj 的内部属性 [[Class]] 为 Object;
- Set the [[Extensible]] internal property of obj to true.
设置 obj 的内部属性 [[Extensible]] 为 true
- Let proto be the value of calling the [[Get]] internal property of F with argument “prototype”.
将 proto 的值设置为 F 的 prototype 属性值;
- If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.
如果 proto 是对象类型,则设置 obj 的内部属性 [[Prototype]] 值为 proto;(进行原型链关联,实现继承的关键)
- 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]] 值为内建构造函数 Object 的 prototype 值;(函数 prototype 属性可以被改写,如果改成非对象类型,obj 的 [[Prototype]] 就指向 Object 的原型对象)
- 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;
- If Type(result) is Object then return result.
如果 result 是 Object 类型,返回 result;
- 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 ```
