美文网首页web前端基础
JavaScript深入理解构造函数

JavaScript深入理解构造函数

作者: 蜗牛_Cy | 来源:发表于2018-07-25 19:16 被阅读0次

今天我来说说什么是构造函数。
在说构造函数之前,我们首先需要要知道JavaScript创建对象的方式有两种

  • 对象字面量方式
  • 使用new表达式方式
  1. 对象字面量是一种灵活的书写方式,例如:
var a1={
  P:"my name is  cy",
  alertp:function(){
    alert(this.p);
  }
}

这样,就用对象字面量的方式创建了一个对象a1,它具有成员变量p和成员方法alertp。这种写法不需要定义一个构造函数,因此不在本文的讨论范围之内。这种写法的缺点是,没创建一个新的对象都需要写出完整的定义 语句,不便于大量的创建相同的对象,不便于使用继承等高级特性。

  1. 使用new表达式方法创建对象。
    例如:使用new String(“a string”),调用内置的String函数构造了一个字符串对象。下面我们用构造函数的方式来创建一个实现功能与上面一直的对象,首先定义构造函数,然后调用new表达式:
function a2(){
  this.p="my name is cy";
  this.alertp=function(){
    alert(this.p)
  }
}
var b1=new a2();

那么使用new操作符来电泳一个构造函数的时候,发生了什么呢?其实很简单,就发生了四件事情。

  1. var b1={};
  2. b1._proto=a2.prototype;
  3. a2.call(b1);
  4. return b1;
  • 第一 创建一个空的b1
  • 第二 将这个对象的proto成员指向构造函数对象a2的prototype成员对象。
  • 第三 将构造函数的作用域赋值给新的对象,因此a2函数的this指向了新的对象b1,然后再调用a2函数。于是我们就给b2对象赋值了一个成员变量p ,这个成员变量的值是“my name is cy”
  • 返回新的对象b1 。当构造函数里包含返回语句时情况比较特殊,这种情况会在下文中介绍。

正确定义构造函数

不同于其他的主流编程语言,JavaScript的构造函数并不是作为类的一个特定的方法存在,当任意一个普通函数用于创建一类对象是,它就被称为构造函数,或者是构造器。一个函数要作为一个真正的构造函数,需要满足一下条件。

  1. 在函数内部新对象(this)的属性进行设置,同城是添加属性和方法。
  2. 构造函数可以包含返回语句(不推荐),但返回值必须是this,或者其他非对象类型的值。

上文定义的构造函数a2就是一个标准的、简单的构造函数。下面例子定义函数a3返回了一个对象,我们可以使用new表达式来调用它,该表达式可以正确的返回一个对象。

function a3(){
  var o={
    p:"my name is cy";
  }
  return o;
}
var b2=new a3();
alert(a3.p)

这种方式不是值得推荐的方式,因为对象b2的原型是函数a3内部的对象o的原型,也就是Object.prototype。这种方式相当于执行科new表达式的前三步,而在第四步的时候返回了a3函数 的返回值。该方式同样不便于创建大量的相同对象,不利于使用继承等高级特性,并且容易造成混乱,应该摒弃。
一个构造函数在某种情况下完全可以作为普通的功能函数来使用,这是JavaScript灵活性的一个体现。下例定义的a4就是一个多用途的函数。

function C2(a, b){
    this.p = a + b;
    this.alertP = function(){
        alert(this.p);
    }
    return this.p;//此返回语句在C2作为构造函数时没有意义
}
var c2 = new C2(2,3);
c2.alertP();//结果为5
alert(C2(2, 3)); //结果为5

该函数既可以用作构造函数来构造一个对象,也可以作为普通的函数来使用。用作普通函数时,它接收两个参数,并返回两者的相加的结果。为了代码的可读性和可维护性,建议作为构造函数的函数不要掺杂除构造作用以外的代码;同样的,一般的功能函数也不要用作构造对象。

为什么要使用构造函数

根据上文的定义,在表面上看来,构造函数似乎只是对一个新创建的对象进行初始化,增加一些成员变量和方法;然而构造函数的作用远不止这些。为了说明使用构造函数的意义,我们先来回顾一下前文提到的例子。执行var o2 = new CO();创建对象的时候,发生了四件事情:

  1. var b1={};
  2. b1._proto=a2.prototype;
  3. a2.call(b1);
  4. return b1;

我们说最重要的是第二步,将新生成的对象的prop属性赋值为构造函数的prototype属性,使得通过构造函数创建的所有对象可以共享相同的原型。这意味着同一个构造函数创建的所有对象都继承自一个相同的对象,因此它们都是同一个类的对象。关于原型(prototype)和继承的细节,笔者会再另一篇文章中深入说明。

在JavaScript标准中,并没有prop这个属性,不过它现在已经是一些主流的JavaScript执行环境默认的一个标准属性,用于指向构造函数的原型。该属性是默认不可见的,而且在各执行环境中实现的细节不尽相同,例如IE浏览器中不存在该属性。我们只要知道JavaScript对象内部存在指向构造函数原型的指针就可以了,这个指针是在调用new表达式的时候自动赋值的,并且我们不应该去修改它。

在构造对象的四个步骤中,我们可以看到,除第二步以外,别的步骤我们无须借助new表达式去实现,因此new表达式不仅仅是对这四个步骤的简化,也是要实现继承的必经之路。

相关文章

网友评论

    本文标题:JavaScript深入理解构造函数

    本文链接:https://www.haomeiwen.com/subject/nkzpmftx.html