什么是构造函数?构造函数与普通函数的区别?

5,186 阅读3分钟

什么是构造函数?

典型的面向对象编程语言(比如 Java 和 Python),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

因此构造函数就是专门用来生成对象实例的函数(模板)

构造函数与普通函数的区别?

构造函数也是函数,但它跟普通的函数有些区别,

  1. this 构造函数内部this指向新创建的对象实例。 而普通函数this
    1. 如果在严格模式下,this表示undefined
    2. 非严格模式下,this指向的是window
// 普通函数 非严格模式
function person() {
  console.log(this === window);
}

person(); // true;

// 普通函数 严格模式

function person() {
  console.log(this === undefined);
}

person(); // true;

// 构造函数
function Person(name) {
  this.name = name;
  console.log(this);
}

let p1 = new Person("rudy"); // Person {name: 'rudy'}
let p2 = new Person("kobe"); // Person {name: 'kobe'}
p1,p2 中的this分别指向不同的对象
  1. 使用new关键字。 前面提到构造函数是生成对象实例的模板,既然是模板,那么它基本上就是固定的,要让这么固定的模板,在创建不同对象实例时,通过同样的属性、方法获取到不同的值。改变它的this指向和原型就是个很好的方向了。简单看下new的内部实现方案:
function createNew() {
  // 创建个对象
  var obj = new Object();
  // 获取第一个参数,既传入的构造函数
  Constructor = [].shift.call(arguments);
  // 将obj的原型指向Constructor(构造函数),这样obj就可以访问到构造函数原型中的属性
  obj.__proto__ = Constructor.prototype;
  // 使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性
  var ret = Constructor.apply(obj, arguments);
  // 返回obj对象
  return typeof ret === "object" ? ret : obj;
}

function Person(name) {
  this.name = name;
}

Person.prototype.sayName = function() {
  console.log("this is " + this.name);
};

let person = createNew(Person, "rudy");

person.name; // rudy;
person.sayName(); // this is rudy;

从上面可以看出new是个完美的解决方案。

  1. return 语句的使用。 普通函数return后面 有值正常返回,没有值或者没有写return就返回undefined。 构造函数一般不需要使用return,如果返回基本类型值,可以忽略return语句。 如果返回值是引用类型时,会直接返回引用类型本身。
// 普通函数 有值
function person() {
  return 1;
}

person(); // 1;

function person() {}

person(); // undefined;

// 构造函数 返回基本类型
function Person(name) {
  this.name = name;
  return 1;
}

let p1 = new Person("rudy");
console.log(p1); // Person {name: 'rudy'};

// 构造函数 返回引用类型
function Person(name) {
  this.name = name;
  return {
    a: 1
  };
}

let p2 = new Person("rudy");
console.log(p2); // {a: 1}
  1. 箭头函数不能用作构造器,和 new一起用会抛出错误
let Foo = () => {};
let foo = new Foo(); // TypeError: Foo is not a constructor

至于为什么会报这个错误,我也不是很清楚,如果有人知道,麻烦告知下。谢谢

  1. 一般构造函数开头首字母大写,普通函数没有这个规定。这只是大家的共识而已,并没有真正的规定要这么写,不按照这样写也没关系。

以上是自己对构造函数及和普通函数区别的一些看法,有错误或者不足的,可以指出。谢谢

参考

构造函数与 new 命令

JavaScript深入之new的模拟实现