原文地址: http://javascript.info/tutorial/native-prototypes

prototype 原型是什么?

和传统语言对象创建有些不同,比如java,php都是通过new一个class类来创建对应的对象的。

而javascript则提供了利用prototype来新建对象的机制。也就是从实体对象创建新的实体对象的方法

从prototype创建新对象的两种方法Object.create, new ClassConstructorFunction()

以及

原生的javascript 对象在prototypes里面保存他们可用的方法。

比如,当我们创建一个新的对象时, 它并未包含任何东西,它怎么知道能够有个toString方法可供使用呢?

   var obj={};
alert(obj.toString())

那是因为obj={}是下面语句

obj = new Object()

的缩写,而Object是原生的javascript 构造函数,而当我们使用new Object()来创建一个新的对象时,有一个重要的特性就是:产出对象的__proto__指针将指向构造函数的prototype对象,这里就是Object.prototype对象。也就是说obj.__proto__ == Object.prototype,而Object.prototype又是一个包含toString方法的原生对象

。注意: __proto__是随浏览器的,有可能命名并不相同。

而根据javascript的原型链查找特性,所有在这个链上的属性和方法都是可读的(注意当写一个在原型链上的属性时,会自动创建一个ownProperty,而不会去更改原型上的属性值!!),也正因为此,所以toString方法自然可用了。

上面的故事同样适用于Array,Function和其他对象。他们的方法分别在Function.prototype, Array.prototype上面定义的、

再看以下原型链的图(来自网易云课堂)

当一个对象的属性被访问或者方法被调用时,javascript引擎通过以下算法和顺序来检索:

1. 在对象自身上面找;

2. 如果1.找不到,就到对象的__proto__上面找;

3. 如果2.找不到,就到__proto__.__proto__上面找

上面这个原型链从对象本身开始持续查找,直到属性被找到(注意这时this为子对象,而非原型),或者直到下一个__proto__ == null(也就是到链底)了而返回undefined. 唯一一个其__proto__属性为 null的对象是 Object.prototype,所有的链最终都指向Object.prototype,换句话说,所有的对象都从Object继承

更改原生prototypes添加新的方法

原生的prototypes是可以被修改的,比如我们可以创建新的方法到原型对象上去。

我们可以写一个方法来多次重复一个字符串

String.prototype.repeat = function(times) {
return new Array(times+1).join(this)
} alert( "a".repeat(3) ) // aaa

再例如,我们可以在Object.prototype对象上添加一个each(func)方法,以便我们在每一个属性上来应用func函数。

Object.prototype.each = function(f) {
for(var prop in this) {
if (Object.prototype.hasOwnProperty(prop)) continue // filter
var value = this[prop]
f.call(value, prop, value)
}
} // Now correct
var obj = { name: 'John', age: 25 }
obj.each(function(prop, val) {
alert(prop) // name -> age
})

通过上面的方法修改原生对象从一开始就招致激烈的评论,有人说不安全,暴露太多到global空间可能造成命名污染,有人说很好用。但无论如何,它在做兼容低版本浏览器的js功能时,用处广泛:

比如,如果没有Object.create支持,而我们又必须兼容,那么一个可行的方法是:

if (!Object.create) {
Object.create = function(proto) {
function F() {}
F.prototype = proto
return new F
}
}

从原生对象继承

原生对象可以用来被继承,比如,Array.prototype为new Array()创建的对象保持了所有的方法

如果我们希望这些方法可在我们的myArray中被访问,那么myArray.__proto__ == Array.prototype就有用武之地了。

// constructor
function MyArray() {
this.stringify = function() {
return this.join(', ')
}
}
// Make sure that (new MyArray) has the right __proto__
MyArray.prototype = Array.prototype // Test
var myArr = new MyArray()
myArr.push(1)
myArr.push(2)
alert( myArr.stringify() ) // 1, 2
alert( myArr.length ) // 2 in all except IE

方法借用

如果你仅仅想用Array的几个方法的功能,那么是不必要继承Array的,你可以borrow a method,然后apply it without inhereting, 比如

var join = Array.prototype.join  或者更短一点 var join = [].join

随后使用一个非标准的this 来调用它:

var obj = {
0: 'first',
1: 'second',
length: 2
} alert( [].join.call(obj, ', ') ) // first, second

上例中, Array.prototype.join在ES-5标准中描述,他并不检查对象type。它做的事情是一个对所有的属性来做joining loop。Array的方法常常用来被借用以便操作array-like对象。

更改原生prototypes“修改”已经存在的原生方法

很多时候,你希望通过修改原生的方法,获得你希望得到的特性,比如我们希望extend Array对象的join()方法,以便在将控制返回给原生join()方法之前增加一些log信息。

Array.prototype.join = (function(_super) {

    // return our new `join()` function
return function() {
console.log("Hey, you called join!");
return _super.apply(this, arguments);
}; // Pass control back to the original join()
// by using .apply on `_super` })(Array.prototype.join);
//
// Pass the original function into our
// immediately invoked function as `_super`
// which remains available to our new
// function thanks to JavaScript closures.

借用原生代码简化重构自用的函数

有时候,我们会嫌直接使用原生函数方法太过啰嗦冗长,一个有效的办法是借鸡生蛋,重新包装。比如我们常常需要就正则表达式来对一个字符串做test,可行的办法就是借用Function.bind返回一个有待运行的函数,后面直接简单调用:

var testForA = RegExp.prototype.test.bind(/[aA]/);
var testForDigit = RegExp.prototype.test.bind(/[0-9]/);
// function () { [native code] } testForA('hello');
// false testForA('hella');
// true ['hello', 'hella', 'holla'].filter(testForA);
// ['hella', 'holla'] testForDigit('this has no digits'); //false
testForDigit('this has 123 digits'); //true

http://prototypejs.org/

http://sugarjs.com/native

扩展javascript原生对象的更多相关文章

  1. 据说每个大牛、小牛都应该有自己的库——JavaScript原生对象拓展

    在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏,一是,关于写个自己的库的想法由来 ...

  2. JavaScript原生对象拓展

    JavaScript原生对象拓展 在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏 ...

  3. JavaScript原生对象及扩展

    来源于 https://segmentfault.com/a/1190000002634958 内置对象与原生对象 内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始 ...

  4. JavaScript原生对象总纲

    一. javascript之Array类 创建js数组两种方式: var arr = [];  或var arr = new Array(); ()里可以指定长度,也可以不指定,指不指定都无所谓,因为 ...

  5. 在TypeScript中扩展JavaScript基础对象的功能

    最近工作中用到,记录一下:假设我们需要一个功能,把一个数字比如10000输出为下面的字符串格式“10,000”,一般是写一个方法,那么我希望更方便一点,直接向Number类型添加一个格式化方法,比如叫 ...

  6. JavaScript原生对象属性和方法详解——Array对象

    http://www.feeldesignstudio.com/2013/09/native-javascript-object-properties-and-methods-array/ lengt ...

  7. Object、Function、String、Array原生对象扩展方法

    JavaScript原生对象的api有些情况下使用并不方便,考虑扩展基于Object.Function.String.Array扩展,参考了prototype.js的部分实现,做了提取和修改,分享下: ...

  8. JavaScript原生折叠扩展收缩菜单带缓冲动画

    JavaScript原生折叠扩展收缩菜单带缓冲动画 @落雨 <div id="div_two" style="display: none;"> &l ...

  9. JavaScript内置对象与原生对象【转】

    原文:https://segmentfault.com/a/1190000002634958 内置对象与原生对象 内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始化 ...

随机推荐

  1. 一个迷你的 Node.js 基于 Express 的 MVR 模式的 API工程 的分析

    1. 工程说明 该工程是基于 Express 库,编写的一个 API 查询返回的一个微型应用. API Resource 就是把 API 的内容当做网络资源去处理.工程中的路由访问也是返回 API 内 ...

  2. C#文件上传编码乱码

    又遇到文件编码乱码的事情,这回稍微有些头绪,但是还是花了很多时间去解决. 场景:上传csv文件,导入到数据库.上传文件的编码不定,需要转成unicode存储. 问题点:需要解决判断上传文件的编码. 关 ...

  3. Linux 开机、重启和用户登录注销、用户管理、用户组

    l 关机&重启命令   基本介绍: shutdown –h now 立该进行关机 shudown -h 1 "hello, 1 分钟后会关机了" shutdown –r n ...

  4. JavaScript 刷题一

    最近读<JavaScirpt编程精解>,想把里面的三个大的程序实现,现在记录下来. 问题一: 从下面这封信中,emily奶奶每封信的结尾都会用同样的格式注明哪只猫出生了,哪只猫死去了.现要 ...

  5. Ubuntu14.04下编译安装或apt-get方式安装搭建Apache或Httpd服务(图文详解)

    不多说,直接上干货! 写在前面的话 对于 在Ubuntu系统上,编译安装Apache它默认路径是在/usr/local/apache2/htdocs 或者编译安装httpd它默认路径是在/usr/lo ...

  6. condition实现原理

    condition是对线程进行控制管理的接口,具体实现是AQS的一个内部类ConditionObject,主要功能是控制线程的启/停(这么说并不严格,还要有锁的竞争排队). condition主要方法 ...

  7. Java线程问题(基础回顾)

    1.概念:线程是运行程序(进程)中单个顺序的小程序,一个进程可以由多个线程组成,而这多个线程共享同一个存储空间,这使得线程间的通信比较容易.在一个多进程的程序中,如果要切换到另一个进程,需要改变地址空 ...

  8. Stirng,Stringbuffer,Stringbuild的区别浅淡

    String 1,Stirng是对象不是基本数据类型 2,String是final类,不能被继承.是不可变对象,一旦创建,就不能修改它的值. 3,对于已经存在的Stirng对象,修改它的值,就是重新创 ...

  9. 软工网络15Alpha阶段敏捷冲刺博客汇总

    博客链接汇总: 第一篇:http://www.cnblogs.com/pubg722/p/8891605.html 第二篇:http://www.cnblogs.com/pubg722/p/89090 ...

  10. C++Array类模板编写笔记

    C++Array类模板 函数模板和类模板都属于泛型技术,利用函数模板和类模板来创建一个具有通用功能的函数和类,以支持多种不同的形参,从而进一步简化重载函数的函数体设计. 声明方法:template&l ...