JS构造函数内的方法与构造函数prototype属性上方法的对比
本文的目的是让大家理解什么情况下把函数的方法写在JavaScript的构造函数上,什么时候把方法写在函数的 prototype 属性上;以及这样做的好处.
为了阅读方便,我们约定一下:把方法写在构造函数内的情况我们简称为 函数内方法 ,把方法写在 prototype 属性上的情况我们简称为 prototype上的方法
首先我们先了解一下这篇文章的重点:
函数内的方法:使用函数内的方法我们可以 访问到函数内部的私有变量 ,如果我们通过构造函数
new出来的对象需要我们操作构造函数内部的私有变量的话,我们这个时候就要考虑使用函数内的方法.
prototype上的方法:当我们需要 通过一个函数创建大量的对象 ,并且这些对象还都有许多的方法的时候;这时我们就要考虑在函数的
prototype上添加这些方法.这种情况下我们代码的 内存占用 就比较小.
在实际的应用中,这两种方法往往是结合使用的;所以我们要首先了解我们需要的是什么,然后再去选择如何使用.
我们还是根据下面的代码来说明一下这些要点吧,下面是 代码部分 :
// 构造函数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 写在了构造函数 B 的 prototype 属性上面.
需要指出的是,通过这两个构造函数 new 出来的对象具有一样的属性和方法,但是它们的区别我们可以通过下面的一个图来说明:

我们通过使用构造函数 A 创建了两个对象,分别是 a1 , a2 ;通过构造函数 B 创建了两个对象 b1 , b2 ;我们可以发现 b1 , b2 这两个对象的那个 sayHello 方法都是指向了它们的构造函数的 prototype 属性的 sayHello 方法.而 a1 , a2 都是在自己内部定义了这个方法.
定义在构造函数内部的方法,会在它的每一个实例上都克隆这个方法;定义在构造函数的 prototype 属性上的方法会让它的所有示例都共享这个方法,但是不会在每个实例的内部重新定义这个方法 .如果我们的应用需要创建很多新的对象,并且这些对象还有许多的方法,为了节省内存,我们建议把这些方法都定义在构造函数的 prototype 属性上 当然,在某些情况下,我们需要将某些方法定义在构造函数中,这种情况一般是因为我们需要访问构造函数内部的私有变量 .
下面我们举一个两者结合的例子,代码如下:
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 ,这个变量我们是不希望通过函数内部以外的方法去操作这个变量,所以我们把操作这个变量的方法都写在了函数的内部.而把一些可以公开的方法写在了 Person 的 prototype 属性上,比如方法 getFull 和 getProfile .
把方法写在构造函数的内部,增加了通过构造函数初始化一个对象的成本,把方法写在 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"}参考的文章或者问答:
技术交流QQ群:15129679
JS构造函数内的方法与构造函数prototype属性上方法的对比的更多相关文章
- js面向对象之公有、私有、静态属性和方法详解
现下,javascript大行其道,对于网站开发人员来说,javascript是必需掌据的一门语言,但随着jquery等框架的流行和使用,许多人对于原生javascript缺乏深入的理解,习惯了函数式 ...
- js进阶正则表达式11RegExp的属性和方法(RegExp的属性和方法,就是RegExp对象.(点)什么的形式)(正则表达式执行之前会被编译)
js进阶正则表达式11RegExp的属性和方法(RegExp的属性和方法,就是RegExp对象.(点)什么的形式)(正则表达式执行之前会被编译) 一.总结 1. RegExp的属性和方法,就是RegE ...
- static 关键字详解 static方法调用非static属性和方法
静态的属性和方法在内存中的存放地址与非静态的是不同的,静态的是存放在static区,它意味着静态方法是没有this的,所以我们不可以从一个static方法内部发出对非static方法的调用.但是反之是 ...
- 《JS权威指南学习总结--8.7 函数属性、方法和构造函数》
内容要点: 在JS程序中,函数是值.对函数执行typeof运算会返回字符串 "function",但是函数是JS中特殊的对象.因为函数也是对象,它们也可以拥有属性和方法,就像普 ...
- 从toString()方法到Object.prototype.toString.call()方法
一.toString方法和Object.prototype.toSting.call()的区别 var arr=[1,2]; 直接对一个数组调用toString()方法, console.log(ar ...
- JS面向对象组件(三)--面向对象中的常用属性和方法
图片的由来看下面: 1.hasOwnProperty:看是不是对象自身下面的属性 var arr = []; arr.num = ; Array.prototype.num2 = ; //所有的数组对 ...
- 对js原型对象、实例化对象及prototype属性的一些见解
什么是原型对象? 请看下面的代码,我们以各种姿势,创建了几个方法! function fn1() { } var fn2 = function () { } var fn3 = new Functio ...
- HTML5 canvas图像绘制方法与像素操作属性和方法
图像绘制方法 drawImage() 向画布上绘制图像.画布或视频 像素操作属性和方法 width 返回 ImageData ...
- [pathlib]内置pathlib库的常用属性和方法
pathlib中的Path类可以创建path路径对象, 属于比os.path更高抽象级别的对象. 官网 from pathlib import Path path = Path(__file__) p ...
随机推荐
- TeeChart 有用的属性
//背景 BackWall.Gradient.Visible = True //是否显示右边图标选项 Legend.Visible = False //不在显示3D效果, 比较有用 View3D = ...
- 教程:如何手动安装Xamarin与Xamarin for VisualStudio
[2016/4/17更新:如果你下载后发现仍然需要付费才能编译Android/iOS APP,请到文章最下面更新Xamarin for VS和Xamarin Studio到最新的版本.Build201 ...
- PHP扩展迁移为PHP7扩展兼容性问题记录
PHP7扩展编写的时候,提供的一些内核方法和之前的PHP之前的版本并不能完全兼容.有不少方法参数做了调整.下面是在迁移过程中遇到的一些问题.记录下来,避免大家再踩坑. add_assoc_string ...
- Java进程线程理解
一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存在,它必须是进程的一部分.一个进程一直运行,直到所有的非守护线程都结束运行后才能结束. 多线程能满足程序员编写高效率的程序 ...
- ASIHTTPRequestErrorDomain Code=5
ASIHttpRequest解析带空格的URL时 出错!!!(已解决) 用的是post请求 URL 地址是: http://111.234.51.56/login_member.pl?time=201 ...
- 能在xcode5中开发基于IOS7sdk的应用程序兼容ios4.3之后的系统吗?
能在xcode5中开发基于IOS7sdk的应用程序兼容ios4.3之后的系统吗?
- 无线通信中FEC 编码原理及评价
转自:http://blog.csdn.net/wiznet2012/article/details/7492146 大家好,前面我们给大家介绍了无线通信中FEC编码原理(1)和(2),今天继续献上F ...
- SharePoint Online 创建和使用视图
前言 本文介绍如何在Office 365中创建和使用视图. 正文 首先,解释一下什么是SharePoint站点视图,所谓视图,就是列表的一个呈现形式,包含特定的栏.排序.筛选.分组等特性,我们通常创建 ...
- Android:客户端和服务器之间传输数据加密
Android客户端与服务器进行数据传输时,一般会涉及到两类数据的加密情况,一类是只有创建者才能知道的数据,比如密码:另一类是其他比较重要的,但是可以逆向解密的数据. 第一类:密码类的数据,为了让用户 ...
- 如何选择JAVA培训机构,兼议什么样的人适合培训机构
首先,利益相关,本人就是培训机构创办者兼讲师,但这不妨碍我对此发表看法. 我们先来看什么样的人适合培训机构?要回答这个问题,需要先换个角度.这个角度就是,你学习一门语言的动机是什么?99%的人的回答是 ...