Javascript Prototypes之旅(A Plain English Guide to JavaScript Prototypes译文)

  当我第一次学习Javascript的对象模型时,我的反应时困惑。因为这是我第一次接触基于原型的语言,所以我完完全全被原型弄得糊里糊涂(译者语:在看这篇文章前,我一直困惑function的prototype和object的__proto__的区别及它们之间的关系)。我不能理解JavaScript通过构造函数(function constructors)的方式来实现一种独特的原型。我相信你们当中也有类似经历的人。

  但随着自己写得越来越多javascript,我不仅理解了它的对象模型而且已经开始喜欢上它了。感谢Javascript我发现基于原型的语言的高雅与灵活。我现在十分喜欢基于原型的语言,因为它有比基于类的语言更简单和灵活的对性模型。

1. Prototypes in Javascript

  大多数教程多会在直接通过讲述构造函数(constructor functions)来讲解Javascript的对象。我并不认同这种做法,这样只会令到我们更困惑。所以下面我们先学习一些基础的原型吧!

2. Prototype chains(prototype inheritance)原型链/原型继承

  Javascript的每个对象均有一个原型(prototype)。当消息(请求某个属性的指令)到达某个对象时,Javascript会尝试在该对象上寻找该属性,但没有的时候就会将消息转发到该对象的原型并在原型上寻找该属性,就是这样不断向上层原型转发消息,直到在某个原型中找到该属性或消息转发到顶层原型(Object对象)。(译者语:每个对象的原型均指向另一个对象,最顶层的原型就是Object类的实例)

原型继承链可以无限延长。但一般情况下过长的原型链会令人困惑且难以维护。

3.The __proto__ object

  我们可以通过__proto__属性来简化对Javascript原型的理解。但不幸的是__proto__属性并非Javascript的标准接口。所以我们不应该在生产环境中依赖该属性。我看一看下面的代码片段吧!

可以看到通过对象的__proto__属性我们可以简单、方便地设置对象的原型。

下面我们通过isPrototypeof函数来判断父、子类的关系

4. Prototype lookups are dynamic(原型变化的即时性)

  你可以在任何时间添加属性到对象的原型中,然后就能马上通过对象来获取该属性。(译者语:因为正如2. Prototype chains(prototype inheritance)原型链/原型继承讲述那样,消息是在原型链传递并在原型中寻找该属性,所以为原型增删改了属性能即时反映出来)

5. New/updated properties are assigned to the  object, not to the prototype(增改对象的属性)

  看代码吧!

(译者语:在对象中已找到了相应的属性,那么就不会将消息转发到原型去)

6. Object.create

  前面已经说过__proto__属性并非设置原型的标准方法。下面我们使用Object.create方法来创建对象并指定该对象的原型。该方法在ES5中可用,但老的浏览器和JS引擎要通过es5-hhim来使用了。

(译者语:我们甚至可以通过object.create(null)开创建一个没有原型的对象;而使用其他方式创建的对象它的原型链中至少有一个Object类实例)

当然在创建对象的时候,还可以设置该对象的属性。

这里打算展开对象属性设置方面的几个特性的使用方法,大家可以参考相关的文档 here

7. Object.getProtype

  我们可以通过Object.getPrototypeOf来获取对象的原型

8.Constructor Functions(构造函数)

  构造函是javascript中用于构造原型链的最常用的方法。因为它是构造类型的唯一的原始方式。而很对javascript引擎对构造函数也提供了性能上的优化。

  与此同时,构造函数是javascript中一个重要且容易令人疑惑的知识点。

8.1. Functions as contructors

我们通过关键字new来创建Foo函数的实例foo

8.2. 'this' is assigned implicitly(隐式分配的this)

  当我们使用关键字new创建函数实例时,Javascript会隐式地创建一个this对象,并在函数的最后返回该this对象。

相当于

注意:这个隐式创建的this对象,当且仅当使用关键字new创建函数实例时出现,若不使用关键字new就会就会出现不可预知的问题,一般情况下为以首字母大写的方式来命名构造函数,以提示需使用关键字new来调用该函数。

8.3. The 'function prototype'

  每一个Javascript的函数都有一个名为prototype的属性(译者语:这个prototype属性与之前说__proto__一样会指向原型,它们之间的关系下面的内容会有所讲解。因为prototype这个属性名称的中文就是为原型,所以为了区分下面的内容会用“prototype属性”来代表function的prototype属性)

这个prototype属性与之前说__proto__一样会指向原型,但两者指向的原型又有所区别,具体请看

(译者语:这里原文的代码和讲解有问题,据本人实践所得,对象并没有prototype属性,若要访问对象的原型需要使用__proto__属性或Object.getPrototype函数;而要访问函数的原型则要通过访问prototype属性。而上述代码的无论foo是对象还是函数均有一方必为undefined,比较结果铁定为false。下面代码片段可以证明两者指向相同的原型:

  function Foo(){}

  var foo = new Foo();

  Object.getPrototype(foo) === Foo.prototype; // => true

  且原型为Foo {},该原型的原型为Object {};Foo{} 中有constructor属性指向function Foo(){}自身。)

__proto__和prototype属性的关系其实很简单,prototype属性所指向的原型会在使用关键字new调用构造函数时被复制到隐式创建的this对象的__proto__中。所以prototype属性指向的原型有那些属性和方法,那么__proto__就有哪些属性和方法。

英文原文地址:http://sporto.github.com/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/?utm_source=javascriptweekly&utm_medium=email

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一“技”之长

Swift讲解专题十——类与结构体 原

        Swift中的类与结构体十分相似,和Objective-C不同的是,Swift中的结构体不仅可以定义属性,也可以像类一样为其定义方法。

9920
来自专栏C/C++基础

C/C++ const

const是C语言的关键字,经C++扩充,功能变得强大,用法复杂。const用于定义一个常变量(只读变量)。当const与指针、引用、函数等结合起来使用时,情况...

12510
来自专栏漏斗社区

听说,这个是CTF中最重要的问题······

0x00 序列化和反序列化 简单的理解:序列化就是使用serialize()将对象的用字符串的方式进行表示,反序列化是使用unserialize()将序列化的字...

40750
来自专栏小白的技术客栈

Python函数基础

函数基础 简单地说,一个函数就是一组Python语句的组合,它们可以在程序中运行一次或多次运行。Python中的函数在其他语言中也叫做过程或子例程,那么这些被包...

37250
来自专栏Modeng的专栏

Javascript数组系列四之数组的转换与排序Sort方法

今天我们继续来介绍 Javascirpt 数组中的方法,也是数组系列的第四篇文章,因为数组的方法众多,每篇文章我们都对数组的每个方法都有比较细致的描述,只要你能...

12730
来自专栏哲学驱动设计

关于静态方法和实例方法的一些误区。

转自《关于静态方法和实例方法的一些误区。》 一、 静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存。     事实上,方法都是一样的,在加载时机和占...

19960
来自专栏python3

python 列表(List)

Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。

20210
来自专栏python3

python3--面向对象进阶之内置方法

print执行时,是去内部寻找__str__方法,所以print没有输出不了的数据,因为每一个对象都有__str__方法

9610
来自专栏听雨堂

代码页

  最近写一个网络程序时,碰到字符串和字节数组之间的转换问题,开始时还比较简单,字符串都是标准的Ascll编码,处理起来比较简单:   字符串转字节数组 by...

21390
来自专栏Crossin的编程教室

【Python 第67课】函数的参数传递(1)

本篇面向读者:有一点点 Python 基础 关键字:函数,参数,默认值 先说下上次课最后留的那题,我自己的解法: print ';'.join([str(i) ...

29450

扫码关注云+社区

领取腾讯云代金券