JavaScript 的原型对象 Prototype
在 JavaScript 中,每当定义一个对象(或函数)时候,对象中都会包含一些预定义的属性,其中一个属性就是原型对象 prototype。
var myObject = function( name ) {
this.name = name;
return this;
};
console.log(typeof myObject.prototype); // object
myObject.prototype.getName = function() {
return this.name;
};
上面的代码创建了一个函数,然后赋值给 myObject。如果我名调用 myObject(),它将返回window 对象。因为它是在全局作用域内定义的,而且它还没有被实例化,所以 this 直接指向全局对象:
console.log(myObject() === window); // true
原型链
JavaScript 中定义或实例化任何一个对象的时候,它都会被附加一个名为 __proto__ 的隐藏属性,原型链正是依靠这个属性才得以形成。但是千万别直接访问 __proto__ 属性,因为有些浏览器并不支持直接访问它。另外 __proto__ 和 对象的 prototype 属性也不是一回事,它们各自有各自的用途。
怎么理解呢?其实,当我们创建 myObject 函数时,实际上是创建了一个 Function 类型的对象:
console.log(typeof myObject); // function
这里要说明一下,Function 是 JavaScript 中预定义的一个对象,所以它也有自己预定义的属性(如length 和 arguments)和方法(如 call 和 apply),当然也有 __proto__,以此实现原型链。也就是说,JavaScript 引擎内可能有类似如下的代码片段:
Function.prototype = {
arguments: null,
length: 0,
call: function() {
// secret code
},
apply: function(){
// secret code
},
...
};
事实上,JavaScript 引擎代码不可能这样简单,这里只是描述一下原型链是如何工作的。
我们定义了一个函数 myObject,它还有一个参数 name,但是并没有给它任何其它属性,例如length 或者其它方法,如 call。那么下面这段代码为啥能正常执行呢?
console.log(myObject.length); // 结果:1,是参数的个数
这是因为我们定义 myObject 时,同时也给它定义了一个 __proto__ 属性,并赋值为Function.prototype(参考前面的代码片段),所以我们能够像访问其它属性一样访问myObject.length,即使我们并没有定义这个属性,因为它会顺着 __proto__ 原型链往上去找length,最终在 Function 里面找到了。
那为什么找到的 length 属性的值是 1,而不是 0 呢,是什么时候给它赋值的呢?由于 myObject是 Function 的一个实例:
console.log(myObject instanceof Function); // true
console.log(myObject === Function); // false
当实例化一个对象的时候,对象的 __proto__ 属性会被赋值为其构造者的原型对象,在本示例中就是 Function,此时构造器回去计算参数的个数,改变 length 的值。
console.log(myObject.__proto__ === Function.prototype); // true
而当我们用 new 关键字创建一个新的实例时,新对象的 __proto__ 将会被赋值为myObject.prototype,因为现在的构造函数为 myObject,而非 Function。
var myInstance = new myObject('foo');
console.log(myInstance.__proto__ === myObject.prototype); // true
新对象除了能访问 Function.prototype 中继承下来的 call 和 apply 外,还能访问从 myObject 中继承下来的 getName 方法:
console.log(myInstance.getName()); // foo
var mySecondInstance = new myObject('bar');
console.log(mySecondInstance.getName()); // bar
console.log(myInstance.getName()); // foo
其实这相当于把原型对象当做一个蓝本,然后可以根据这个蓝本创建 N 个新的对象。
prototype 的典型示例
用过 jQuery 或者 Prototype 库的朋友可能知道,这些库中通常都会有 trim 这个方法。
示例:
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
trim 用法:
' foo bar '.trim(); // 'foo bar'
但是这样做又有一个缺点,因为比较新版本的浏览器中的 JavaScript 引擎在 String 对象中本身就提供了 trim 方法, 那么我们自己定义的 trim 就会覆写它自带的 trim。其实,我们在定义 trim 方法之前,可以做个简单的检测,看是否需要自己添加这个方法:
if(!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
}
检查一下,如不存在 trim 这个方法,定义一个。
via http://net.tutsplus.com/tutorials/javascript-ajax/prototypes-in-javascript-what-you-need-to-know/
JavaScript 的原型对象 Prototype的更多相关文章
- JavaScript的原型对象prototype、原型属性__proto__、原型链和constructor
先画上一个关系图: 1. 什么是prototype.__proto__.constructor? var arr = new Array; 1. __proto__是原型属性,对象特有的属性,是对象指 ...
- [js高手之路]使用原型对象(prototype)需要注意的地方
我们先来一个简单的构造函数+原型对象的小程序 function CreateObj( uName, uAge ) { this.userName = uName; this.userAge = uAg ...
- js高级——构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器
一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...
- JavaScript中原型对象的应用!
JavaScript中原型对象的应用! 扩展内置对象的方法 我以数组对象为例! // 原型对象的应用 扩展内置对象方法! Array.prototype.sum = function() { var ...
- JavaScript 之 原型对象、对象原型 —— { }
JavaScript -- 构造函数 // 构造函数 function Player(name, age) { this.name = name; this.age = age; } JavaScri ...
- 原型对象prototype和原型属性[[Prototype]]
构造器:可以被 new 运算符调用, Boolean,Number,String,Date,RegExp,Error,Function,Array,Object 都是构造器,他们有各自的实现方式. 比 ...
- 构造函数、原型对象prototype、实例、隐式原型__proto__的理解
(欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指出来~) PS: 内容中的__proto__可能会被markdown语法导致显示为proto. 建议将构造函数中的方法都定义到构造函数的原 ...
- 【原型模式】--重写原型对象prototype的影响
//[原型模式]--重写原型对象prototype的影响 2014-12-12//定义构造函数function Person() { }//直接指定构造函数的原型为一个对象(为了简化逐个给原型添加成员 ...
- javascript原型对象prototype
“我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法.” 引用类型才具有prototype属性 ...
随机推荐
- POJ1860——Currency Exchange(BellmanFord算法求最短路)
Currency Exchange DescriptionSeveral currency exchange points are working in our city. Let us suppos ...
- 15个必知的Android开发者选项
Android开发者选项,看起来很简单的事情,其实很多同学对它了解得不够,Google用心良苦得为我们设计了这么多小开关都是有它的作用的,今天也花了点时间,过了一遍全部的30多个开关,从中整理出15个 ...
- C#反射机制介绍
反射的定义:审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等. ...
- linux系统中删除文件夹
rm -rf 文件夹的名称 rm-r 文件名称
- UVa 10048 (Floyd变形) Audiophobia
题意: 给一个带权无向图,和一些询问,每次询问两个点之间最大权的最小路径. 分析: 紫书上的题解是错误的,应该是把原算法中的加号变成max即可.但推理过程还是类似的,如果理解了Floyd算法的话,这个 ...
- shareSDK实现QQ第三方登录
// QQ登录 case R.id.login_share_qq: Platform qq = ShareSDK.getPlatform(QQ.NAME); qq.SSOSetting(false); ...
- Spring中使用quartz插件实现定时任务
第一步:导入架包 *spring3.2.3版本的架包将spring的各个功能模块给分开了,我们必须将Spring必须依赖的包导入上去 第二步:编写配置文件 <?xml version=" ...
- Java [leetcode 27]Remove Element
题目描述: Given an array and a value, remove all instances of that value in place and return the new len ...
- HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该file的url,一个空的img标签,ID为img0,把选择 ...
- Swift的字符串String是值类型
根据<The Swift Programming Language>中文版基于Xcode6.1的文章描述: Swift的 String 类型是值类型.如果创建了新的字符串,那么当其进行常量 ...