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属性 ...
随机推荐
- 万网空间如何安装wordpress
万网空间如何安装wordpress建站教程 _ 学做网站论坛 http://www.xuewangzhan.com/wpbbs/1643.html 1.先在本地下载一个最新版本的wordpress ...
- Git教程之标签管理
发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来.所以,标签也是版本库的一个快照.Git的 ...
- 转XMLHelper
http://www.cnblogs.com/lixyvip/archive/2009/09/16/1567929.html using System; using System.Collection ...
- MapReduce编程系列 — 2:计算平均分
1.项目名称: 2.程序代码: package com.averagescorecount; import java.io.IOException; import java.util.Iterator ...
- python 操作符笔记:
操作符 描述 x if y else z 三元描述(2.5新加)(类似于c中的 x?y:z x or y 或 x and y 与 not x 非 x!=y ,x is y 序列成员测试 x | y 位 ...
- java中synchronized的用法详解
记下来,很重要. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchron ...
- android ListView注意事项
所有问题,都是自己遇到过的. 但内容,有一半是自己写的,也有一半是复制过来. 所以,写成原创还请原谅 1. ListView添加标题后(addHeader())后,使用listView.getAdap ...
- 【转】经典SQL语句大全
原博客地址:http://www.cnblogs.com/yubinfeng/archive/2010/11/02/1867386.html (超级纳闷为啥没有转载的功能) 一.基础 1.说明:创建数 ...
- HDU 4968 Improving the GPA
Improving the GPA Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- Peer to Peer File Sharing Through WCF
http://www.codeproject.com/Articles/614028/Peer-to-Peer-File-Sharing-Through-WCF https://github.com/ ...