3-javascript 构造函数

js中面向对象编程是基于 构造函数(consstructor)原型链(prototype) 的。

构造函数作为对象的模板。所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。


3-javascript 构造函数_第1张图片

为了与普通函数区别,构造函数名字的第一个字母通常大写。函数体内使用this关键字,代表所要生成的对象实例。生成对象时,必须使用new命令来调用构造函数。


object instanceof constructor

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。


3-javascript 构造函数_第2张图片

new 命令

new命令的作用就是执行构造函数并返回一个对象实例。执行时 顺序为:

1、创建新的空对象,作为将要返回的对象实例。

2、将空对象的原型指向构造函数的prototype属性

3、将空对象赋值给构造函数内部的this关键字

4、开始执行构造函数内部的代码。

基本用法

  new命令的作用,就是调用一个构造函数,并且返回一个对象实例。

function Keith() {

      this.height = 180;

 }

var boy = new Keith();

console.log(boy.height);  //180

上面代码中通过new命令,让构造函数Keith生成一个对象实例,并赋值给全局变量boy。这个新生成的对象实例,从构造函数Keith中继承了height属性。也就说明了这个对象实例是没有height属性的。在new命令执行时,就代表了新生成的对象实例boy。this.height表示对象实例有一个height属性,它的值是180。

使用new命令时,根据需要,构造函数也可以接受参数。

function Person(name, height) {

       this.name = name;

        this.height = height;

}

var boy = new Person('Keith', 180);

console.log(boy.name); //'Keith'

console.log(boy.height); //180

var girl = new Person('Samsara', 160);

console.log(girl.name); //'Samsara'

console.log(girl.height); //160

  用以上的一个例子,来对构造函数的特点和new基本原理进行一个梳理。

  上面代码中,首先,我们创建了一个构造函数Person,传入了两个参数name和height。构造函数Person内部使用了this关键字来指向将要生成的对象实例。

  然后,我们使用new命令来创建了两个对象实例boy和girl。

  当我们使用new来调用构造函数时,new命令会创建一个空对象boy,作为将要返回的实例对象。接着,这个空对象的原型会指向构造函数Person的prototype属性。也就是boy.prototype===Person.prototype的。要注意的是空对象指向构造函数Person的prototype属性,而不是指向构造函数本身。然后,我们将这个空对象赋值给构造函数内部的this关键字。也就是说,让构造函数内部的this关键字指向一个对象实例。最后,开始执行构造函数内部代码。

  因为对象实例boy和girl是没有name和height属性的,所以对象实例中的两个属性都是继承自构造函数Person中的。这也就说明了构造函数是生成对象的函数,是给对象提供模板的函数。



  一个问题,如果我们忘记使用new命令来调用构造函数,直接调用构造函数了,会发生什么?

这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。

function Keith() {

      this.height = 180;

}

var person = Keith();

console.log(person.height); //TypeError: person is undefined

console.log(window.height); //180

  上面代码中,当在调用构造函数Keith时,忘记加上new命令。结果是this指向了全局作用域,height也就变成了全局变量。而变量person变成了undefined。

因此,应该非常小心,避免出现不使用new命令、直接调用构造函数的情况。

为了保证构造函数必须与new命令一起使用,一个解决办法是,在构造函数内部使用严格模式,即第一行加上use strict。

 function Person(name, height) {

       'use strict';

      this.name = name;

       this.height = height;

}

var boy = Person();

console.log(boy) //TypeError: name is undefined

上面代码的Person为构造函数,use strict命令保证了该函数在严格模式下运行。由于在严格模式中,函数内部的this不能指向全局对象。如果指向了全局,this默认等于undefined,导致不加new调用会报错(JavaScript不允许对undefined添加属性)。

另一个解决办法,是在构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。

function Person(name, height) {

if (!(this instanceof Person)) {

          return new Person(name, height);

 }

this.name = name;

this.height = height;

}

var boy = Person('Keith');

console.log(boy.name) //'Keith'

上面代码中的构造函数,不管加不加new命令,都会得到同样的结果。

如果构造函数内部有return语句,而且return后面跟着一个复杂数据类型(对象,数组等),new命令会返回return语句指定的对象;如果return语句后面跟着一个简单数据类型(字符串,布尔值,数字等),则会忽略return语句,返回this对象。

function Keith() {

this.height = 180;

return {

         height: 200

};

}

var boy = new Keith();

 console.log(boy.height); //200

function Keith() {

this.height = 100;

       return 200;

}

var boy = new Keith();

console.log(boy.height); //100

另一方面,如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。

function Keith() {

     return 'this is a message';

}

var boy = new Keith();

console.log(boy); // Keith {}

上面代码中,对普通函数Keith使用new命令,会创建一个空对象。这是因为new命令总是返回一个对象,要么是实例对象,要么是return语句指定的对象或数组。本例中,return语句返回的是字符串,所以new命令就忽略了该语句。


构造函数的继承

1、构造函数绑定:使用call或apply方法,将父对象的构造函数绑定在子对象上。

2、prototype模式:使用prototype属性。

3-javascript 构造函数_第3张图片

你可能感兴趣的:(3-javascript 构造函数)