通过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 ```