关于构造函数

介绍

对于构造函数的使用很多人都很熟悉,但是对其原理很多也是比较模糊的,虽然这并不影响使用,但是熟悉了原理,才会少犯错。简单叙述下,算是给自己加深个印象。

构造函数的使用

想必都很熟悉

1
2
3
4
5
6
7
function Foo(name, age){
this.name = name;
this.age = age;
}

var foo = new Foo('xiaoming', 15)
// {name: "xiaoming", age: 15}

构造函数名的首字母是大写,但却并不是非得是大写,只是一种惯例,为了区别其他函数,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。所以即使你小写也不会有问题,但是肯定不建议这么做,提出来也只是为了让你注意不要小写首字母。

构造函数也是函数,只不过它可以用来创建对象。不过必须使用new操作符,使用new创建实例会经历4个步骤:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(this指向新对象)
  3. 执行构造函数中的代码(this赋值)
  4. 返回新对象

总结

  • 函数名首字母大写
  • 没有显示创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return 语句(默认存在)

内部原理

根据上面的4个步骤,不难知道构造函数的内部原理,每当声明一个构造函数时:

  1. 在函数体最前面隐式的加上this = {}
  2. 执行this.xxx = xxx
  3. 隐式地返回this

如:

1
2
3
4
5
6
function Foo(name, age){
var this = {}; //隐式加上
this.name = name;
this.age = age;
return this; //隐式返回
}

为了验证是否正确,我们可以自己实现一个构造函数,不过不是使用this,而是使用that

1
2
3
4
5
6
7
8
9
function Foo(name, age){
var that = {};
that.name = name;
that.age = age;
return that;
}

var foo = Foo('xiaoming', 15);
console.log(foo.name); //'xiaoming'

注意,这时我们不需要使用new操作符了,因为所有需要的步骤我们都已经添加了,这就是一个普通的函数,返回一个对象。

关于返回值

我们都知道,构造函数默认返回了this,那么假使我们自己不小心添加了return语句会怎么样呢。不妨试一下:

1
2
3
4
5
6
7
8
function Foo(name, age){
this.name = name;
this.age = age;
return this;
}

var foo = new Foo('xiaoming', 15);
console.log(foo); //{name: "xiaoming", age: 15}

显然,添加return this是不会有什么问题的。

现在我们返回一个普通值:

1
return 123;

如果你试了,会发现也不会影响结果,如果你再顺便试了一下返回字符串和布尔值,发现依旧不会影响结果。现在你知道我想说啥了,没错,当你试着返回一个对象时,结果就是那个对象了,继续试着返回数组和函数,也会影响结果,使得构造函数失去应有的作用。

总结

  • 构造函数默认返回了this
  • 如果手动返回了值类型,对结果没影响
  • 如果手动返回了引用类型,该构造函数失效