function Person(){
this.type='person';
}
首先从表象看,构造函数,就是前面多了一个new关键字。但是,如果想深入得了解它,就要说一下构造函数和普通函数的区别,以及,构造函数前面的new 发生了什么,接着还要介绍下,为什么箭头函数不能作为构造函数,不能new。
- 构造函数和普通函数的区别
构造函数调用的时候前面有new,普通函数没有
const p = new Person();
const p = Person();
- this指向不同 构造函数的this指向的是构造出来的对象实例,而普通函数在不改变this(比如调用的时候通过显式或者隐式等其他各种改变this)的情况下,指向的是环境对象,浏览器就指向wnidow, node指向global.
- return的结果不同 构造函数默认是不用return返回值的,因为new关键字起的作用之一就是有返回值,但是普通函数并没有构造函数的默认返回值。关于构造函数的返回值,这里值得关注下,如果我们让一个构造函数返回,boolean, string, number, null, undefined(等基础数据),和object, array等引用数据,那么实际会返回什么呢? 先来剧透一波,如果return的是基本数据,那么构造函数实际返回,会无视return设置值,返回创建的对象实例。如果return的是引用数据,return会覆盖创建实例,构造函数返回自己手写的引用类型值。
我们来验证一下
console.table(
[null, undefined, 1, true, '', Symbol(), {a: 1}, [1,2]].map(v=> [
v,
function(){
return v;
},
]).map(([item, myConstructor])=>[
Object.prototype.toString.call(item),
item,
JSON.stringify(new myConstructor()),
])
)
2. 构造函数前面的new到底干了什么? 要想知道,new干了什么,那么我们来使用js实现一下new
// 接收不定个数参数,第一个参数是构造函数,后续是被构造函数使用的参数
function myNew(fn, ...args){
//1: 创建一个空对象
const obj = {};
//2: 将新对象__proto__属性连接到构造函数的原型对象上,建立继承关系
obj.__proto__ = fn.prototype;
//3: 改变this指向为新创建出来的对象实例
const res = fn.apply(obj, args);
//4: 设定返回值,判断是否是引用数据类型
return typeof res === 'object' ? res : obj
3.箭头函数可以当构造函数吗? 答案是不能但是为什么呢?
我们可以看到,箭头函数相对于普通函数
- 没有prototype(无法将新对象__proto__属性连接到构造函数的原型对象上)
- 没有arguments
- 没有caller(无法确定上下文) 所以,new 的过程中,箭头函数很多都不能满足。