构造函数内的方法与构造函数prototype属性上方法的对比

挺有用的一篇文章,今天还有人在问我关于构造函数的方法和原型,构造函数的方法是定义在函数内容,做为一个私有方法,不对外开放,而prototype则能够经过对象定义,在外面访问,更加深刻请看本文。app

本文的目的是让你们理解什么状况下把函数的方法写在JavaScript的构造函数上,何时把方法写在函数的prototype属性上;以及这样作的好处.

为了阅读方便,咱们约定一下:把方法写在构造函数内的状况咱们简称为函数内方法,把方法写在prototype属性上的状况咱们简称为prototype上的方法函数

首先咱们先了解一下这篇文章的重点:this

  • 函数内的方法:
    使用函数内的方法咱们能够访问到函数内部的私有变量,若是咱们经过构造函数new出来的对象须要咱们操做构造函数内部的私有变量的话,
    咱们这个时候就要考虑使用函数内的方法.
  • prototype上的方法:
    当咱们须要经过一个函数建立大量的对象,而且这些对象还都有许多的方法的时候;这时咱们就要考虑在函数的prototype上添加这些方法.
    这种状况下咱们代码的内存占用就比较小.
  • 在实际的应用中,这两种方法每每是结合使用的;因此咱们要首先了解咱们须要的是什么,而后再去选择如何使用.

咱们仍是根据下面的代码来讲明一下这些要点吧,下面是代码部分:spa

// 构造函数A
function A(name) {
    this.name = name || 'a';
    this.sayHello = function() {
        console.log('Hello, my name is: ' + this.name);
    }
}

// 构造函数B
function B(name) {
    this.name = name || 'b';
}
B.prototype.sayHello = function() {
    console.log('Hello, my name is: ' + this.name);
};

var a1 = new A('a1');
var a2 = new A('a2');
a1.sayHello();
a2.sayHello();

var b1 = new B('b1');
var b2 = new B('b2');
b1.sayHello();
b2.sayHello();

咱们首先写了两个构造函数,第一个是A,这个构造函数里面包含了一个方法sayHello;第二个是构造函数B, 咱们把那个方法sayHello写在了构造函数Bprototype属性上面.prototype

须要指出的是,经过这两个构造函数new出来的对象具备同样的属性和方法,可是它们的区别咱们能够经过下面的一个图来讲明:code

clipboard.png

咱们经过使用构造函数A建立了两个对象,分别是a1,a2;经过构造函数B建立了两个对象b1,b2;咱们能够发现b1,b2这两个对象的那个sayHello方法 都是指向了它们的构造函数的prototype属性的sayHello方法.而a1,a2都是在本身内部定义了这个方法. 对象

定义在构造函数内部的方法,会在它的每个实例上都克隆这个方法;定义在构造函数的prototype属性上的方法会让它的全部示例都共享这个方法,可是不会在每一个实例的内部从新定义这个方法. 若是咱们的应用须要建立不少新的对象,而且这些对象还有许多的方法,为了节省内存,咱们建议把这些方法都定义在构造函数的prototype属性上ip

固然,在某些状况下,咱们须要将某些方法定义在构造函数中,这种状况通常是由于咱们须要访问构造函数内部的私有变量.内存

下面咱们举一个二者结合的例子,代码以下:原型链

function Person(name, family) {
    this.name = name;
    this.family = family;

    var records = [{type: "in", amount: 0}];

    this.addTransaction = function(trans) {
        if(trans.hasOwnProperty("type") && trans.hasOwnProperty("amount")) {
           records.push(trans);
        }
    }

    this.balance = function() {
       var total = 0;

       records.forEach(function(record) {
           if(record.type === "in") {
             total += record.amount;
           }
           else {
             total -= record.amount;
           }
       });

        return total;
    };
};

Person.prototype.getFull = function() {
    return this.name + " " + this.family;
};

Person.prototype.getProfile = function() {
     return this.getFull() + ", total balance: " + this.balance();
};

在上面的代码中,咱们定义了一个Person构造函数;这个函数有一个内部的私有变量records,这个变量咱们是不但愿经过函数内部之外的方法 去操做这个变量,因此咱们把操做这个变量的方法都写在了函数的内部.而把一些能够公开的方法写在了Personprototype属性上,好比方法getFullgetProfile.

把方法写在构造函数的内部,增长了经过构造函数初始化一个对象的成本,把方法写在prototype属性上就有效的减小了这种成本. 你也许会以为,调用对象上的方法要比调用它的原型链上的方法快得多,其实并非这样的,若是你的那个对象上面不是有不少的原型的话,它们的速度实际上是差很少的

另外,须要注意的一些地方:

  • 首先若是是在函数的prototype属性上定义方法的话,要牢记一点,若是你改变某个方法,那么由这个构造函数产生的全部对象的那个方法都会被改变.
  • 还有一点就是变量提高的问题,咱们能够稍微的看一下下面的代码:
func1(); // 这里会报错,由于在函数执行的时候,func1尚未被赋值. error: func1 is not a function
var func1 = function() {
   console.log('func1');
};

func2(); // 这个会被正确执行,由于函数的声明会被提高.
function func2() {
   console.log('func2');
}
  • 关于对象序列化的问题.定义在函数的prototype上的属性不会被序列化,能够看下面的代码:
function A(name) {
   this.name = name;
}
A.prototype.sayWhat = 'say what...';

var a = new A('dreamapple');
console.log(JSON.stringify(a));

咱们能够看到输出结果是{"name":"dreamapple"}

相关文章
相关标签/搜索