在 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的更多相关文章

  1. JavaScript的原型对象prototype、原型属性__proto__、原型链和constructor

    先画上一个关系图: 1. 什么是prototype.__proto__.constructor? var arr = new Array; 1. __proto__是原型属性,对象特有的属性,是对象指 ...

  2. [js高手之路]使用原型对象(prototype)需要注意的地方

    我们先来一个简单的构造函数+原型对象的小程序 function CreateObj( uName, uAge ) { this.userName = uName; this.userAge = uAg ...

  3. js高级——构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器

    一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...

  4. JavaScript中原型对象的应用!

    JavaScript中原型对象的应用! 扩展内置对象的方法 我以数组对象为例! // 原型对象的应用 扩展内置对象方法! Array.prototype.sum = function() { var ...

  5. JavaScript 之 原型对象、对象原型 —— { }

    JavaScript -- 构造函数 // 构造函数 function Player(name, age) { this.name = name; this.age = age; } JavaScri ...

  6. 原型对象prototype和原型属性[[Prototype]]

    构造器:可以被 new 运算符调用, Boolean,Number,String,Date,RegExp,Error,Function,Array,Object 都是构造器,他们有各自的实现方式. 比 ...

  7. 构造函数、原型对象prototype、实例、隐式原型__proto__的理解

    (欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指出来~) PS: 内容中的__proto__可能会被markdown语法导致显示为proto. 建议将构造函数中的方法都定义到构造函数的原 ...

  8. 【原型模式】--重写原型对象prototype的影响

    //[原型模式]--重写原型对象prototype的影响 2014-12-12//定义构造函数function Person() { }//直接指定构造函数的原型为一个对象(为了简化逐个给原型添加成员 ...

  9. javascript原型对象prototype

    “我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法.” 引用类型才具有prototype属性 ...

随机推荐

  1. SSH应该使用密钥还是密码?

    关于SSH,几乎每个人都同意密钥要优于密码,更安全,并且更先进,但我并不同意这个观点. 虽然密钥的确可以更好,但它有着还没被意识到的严重风险,并且我认为比得到妥善管理的密码更不安全. 通常密钥更好的理 ...

  2. WinAPI——钩子函数大全

    SetWindowsHookEx 函数功能:该函数将一个应用程序定义的挂钩处理过程安装到挂钩链中去,您可以通过安装挂钩处理过程来对系统的某些类型事件进行监控,这些事件与某个特定的线程或系统中的所有事件 ...

  3. Ubuntu 12.04下搭建Qt开发环境

    http://download.qt.io/official_releases/qt/ Ubuntu 环境下Gtk与Qt编译环境安装与配置(系统环境是Ubuntu 12.04) 1.配置基础开发环境G ...

  4. MYI 文件内容

    参考 http://blog.itpub.net/703656/viewspace-1018470/ 创建表结构 create table test(name char(20), age int, c ...

  5. Datalist增删改查——联系人管理

    关于Datalist,其实和Repeater差不多,都是存放数据的控件,相比较下,Datalist和Repeater虽然都是用的模板,但是Datalist比之多了Edit模板,也就是编辑栏的模板,事件 ...

  6. WinCE发展史

    Windows CE概述 WindowsCE是微软公司嵌入式.移动计算平台的基础,它是一个开放的.可升级的32位嵌入式操作系统,是基于掌上型电脑类的电子设备操作系统,它是精简的Windows 95,W ...

  7. C#字符串与char数组互转!

    字符串转换成Char数组string str="abcdefghijklmnopqretuvwxyz";char[] chars=str.ToCharArray(); char数组 ...

  8. 前端js框架收藏

    1. AngularJS :AngularJS是为克服HTML在构建应用上的不足而设计的. 2. knockout 3. avalon :MVVM是前端究极的解决方案,因此之后我大多数时间都在折腾av ...

  9. Android 主题动态切换框架:Prism

    Prism(棱镜) 是一个全新的 Android 动态主题切换框架,虽然是头一次发布,但它所具备的基础功能已经足够强大了!本文介绍了 Prism 的各种用法,希望对你会有所帮助,你也可以对它进行扩展, ...

  10. WCF 学习总结2 -- 配置WCF

    前面一篇文章<WCF 学习总结1 -- 简单实例>一股脑儿展示了几种WCF部署方式,其中配置文件(App.config/Web.config)都是IDE自动生成,省去了我们不少功夫.现在回 ...