当我们new一个构造函数时,发生了什么?

4,723 阅读3分钟

构造函数

我们经常说new一个对象,说明通过new,我们可以创建出一个对象。那么除此之外,还发生了什么呢?

先来看一个代码

function Fun(name){
	this.name=name;
}
Fun.prototype={
	constructor:Fun,
    say(){
    	console.log(this)
    }
}
let a =new Fun('liudehua')

上面代码中,我设置一个构造函数Fun,然后设置Fun的原型对象,最后让new出一个实例对象a。

上面代码总共会实现以下内容:

1、创建一个构造函数

2、new一个实例对象

3、实例对象拿到构造函数中的属性

4、实例对象a可以调用构造函数原型中的方法。

要了解上面内容,我们首先需要明白原型,因为这在js中至关重要。

原型配对

我们需要明白原型图的基本构造

  • 当我创建构造函数Fun时,实际上会产生两样东西,分别是Fun.prototypeFun.__proto__

根据js公理:对象的__proto__ === 其构造函数的prototype我们能知道Fun__proto__指向的是Functionprototype

每个函数的产生都会有一个prototype,我们通过打印可以知道Fun的prototype里面包含的内容。

可以看到里面具有一个say方法,这个方法是共用方法,只要使用构造函数new出来的对象都能使用prototype的方法。

接着我们来查看一下对象a的结构 继续根据js公理对象的__proto__ === 其构造函数的prototype,可以得出结论:a.__proto__ === Fun.prototype

那么我们知道当new了之后,创建出来的对象的__proto__都会被js默认设置指向到其构造函数的prototype中。

this指向

通过new关键字,还将让构造函数中的this指向到新创建的对象中

你可以这样理解

var a=new Fun("liudehua")
new 之后//
function Fun(name){
	newObj={}
	newObj.name=name;
    return newObj
}

new只是对调用后的Fun做了一些额外的处理罢了,构造函数实际上只是对函数的构造调用。调用我们已经知道是什么了,构造就是new把新创造的对象绑定在Fun函数内的this上。

结论

我们可以得出通过new一个构造函数后,发生了什么

  • 创建了一个对象
  • 执行构造函数,并且把属性方法设置给了对象
  • 把this的指向指向给对象
  • 将对象的__proto__ 跟函数的Prototype做对应

不通过new来模拟一个构造函数

通过以上结论,我们来模拟构造函数的new,把任务分为以下部分:

1、返回一个对象

2、让对象获得构造函数的属性

3、将对象的__proto__跟函数的ptorotype做对应

4、模拟this

function fun(name){
	let obj={
    	name:name
    };
    obj.__proto__=fun.prototype
    return obj
}
fun.prototype={
    	constructor:fun,
        say(futureObj){//请查看注释
        	console.log(futureObj)
        },
    }

上面的代码返回一个对象,并且已经设置好让obj的__proto__指向fun的prototype,指的注意的几个点是:

  • 由于重新设置了prototype,所以我们要重新加上constructor
  • futureObj取代this,把this当成参数来传递,所以调用say()方法时,我们需要使用。
		let a=fun('liudehua')
		a.say(a) //使用这种方法来取代this

优化代码

我们可以使用Object.create()来创建一新个对象并且给它指定ptototype

      function fun(name){
          let obj=Object.create(fun.prototype)
          //obj.name = name 遇到属性很多的情况,这种写法就会很烦
          //我们可以用Object.assign()方法来批量增加
          Object.assign(obj,{
          	name:name
          })
          return obj
      };
      fun.prototype={
          constructor:fun,
          say(futureObj){
              console.log(futureObj)
              },
          }

参考链接:

JS原型链

JS世界与内存