通过JavaScript原型链理解基于原型的编程

零.此文动机

  用了一段时间的Lua,用惯了Java C++等有Class关键字的语言,一直对Lua的中的面向对象技术感到费解,一个开源的objectlua更是看了n遍也没理解其中的原理,直到看到了Prototype-based programming

一.什么是基于原型的编程

  基于原型的编程是面向对象编程的一种形式,通过复制已经存在的原型对象来实现面向对象,无与基于类的编程较大的区别是没有Class关键字,但是有类的概念。基于原型的编程也可以理解成基于实例的编程。

  基于原型的系统可以在程序运行时对原型进行修改,基于类(Java, C+)的语言则很难实现这一点。这么说比较抽象,下面会对比基于原型的类(JavaScript)和基于类的编程区别。

二.JavaScript中的类继承

  一.java中的类

   java实现类有现成的关键字class,用java实现一个动物类,并实现一个人类来继承动物类。

 1 class Animal {
 2     public Animal() {
 3         name = "Animal";
 4     }
 5     public String eat() {
 6         return "eat!";
 7     }
 8     public String name;
 9 }
10
11 class People extends Animal {
12     public People() {
13         super();
14         name = "people";
15     }
16 }

  二.JavaScript中的类

  JavaScript定义了少数的数据类型:null,undefined,Boolean,Number,Function,Object(对象)。每个对象都有类属性,但是不能通过.class来访问,只能通过.toString方法来访问。但是很多对象继承的toString()方法重写了,所以要调用Function.call()方法。

1 object.prototype.toString.call("")
2 //[object String]
3 object.prototype.toString.call(1)
4 //[object Number]
5 object.prototype.toString.call([])
6 //[object Array]
7 function f(){}
8 object.prototype.toString.call(new f())
9 //[object Object]

  每个对象除了有类属性外,还有原型属性(__proto__),这个属性便是用来继承的,对对象属性的查询,若没有此属性,便到其原型中继续查找。比如有对象A和对象B,A.__proto__ = B,执行代码A.b,若A.b == null, 再查找B.b,若找到则作为A.b的返回,若没有找到则继续到B的原型中找,直到找到或原型(Ojbect.prototype.__proto__)为空。JavaScript中的面向对象需要写一整篇博文来捋顺,下面只写最基本的对象继承。同样是上面人继承动物的例子,JavaScript这么搞:

 1 var Animal = {
 2     name : "Animal",
 3     eat : function() {
 4         return "eat!"
 5     }
 6 };
 7
 8 var People = {
 9     name : "People"
10 }
11
12 People.__proto__ = Animal;
13
14 People.eat()
15 // "eat!"
16 People.name
17 // "People"

  People.__proto__ = Animal,便是让People的原型为Animal,实现People对Animal的继承,People.eat()返回“eat!”.

  这种原型的继承有什么优点呢?我理解到的是可以进行运行中的类修改,比如下面的代码,程序运行中在想在基类中添加属性或方法,java就不能做到。

1 //继续上面代码
2 Animal.run = function () {
3     return "Animal run";
4 }
5 People.run()
6 // "Animal run"

三.其他基于原型的语言

  C++中的类只是对象的布局的定义,其肯定不是基于原型的语言。

  那Java呢,Java中的类也是对象,那Java是不是基于原型的语言呢?不是!简单的判断Java提供了Class关键字……更关键的是Java是一种强类型语言,所以其不具有动态扩展性。

  个人觉得记忆原型的语言必须具备下面2个特点:

  • 弱类型
  • 动态可扩展  

  具备这两个特点的语言看着那么像脚本语言呢,是的,Lua,Tcl,Perl【1】都是基于对象的语言。Python比较特殊,其语言级别提供了Class关键字,但是它又满足弱类型与动态可扩展,这时就不要纠结它是不是面向原型的语言了,个人愿意认为它是基于类的语言,毕竟提供了Class关键字…… 这个貌似是让python看起来像是基于原型语言的东东。

参考

  1. https://en.wikipedia.org/wiki/Prototype-based_programming
  2. http://www.cnblogs.com/winter-cn/archive/2008/06/02/1212167.html
  3. JavaScript权威指南第六版
时间: 2024-10-29 19:09:47

通过JavaScript原型链理解基于原型的编程的相关文章

JavaScript ES5类 原型 原型链 组合、原型、寄生式继承

ES5类 原型  原型链 继承 JavaScript中,原型是相对于构造函数(类)的叫法(或者说概念),原型链是相对于构造函数(类)的实例对象的叫法. 对于JavaScript对象,如果在对象自身上找不到该属性,那么就会向上沿着原型链继续查找该属性 创建一个ES5类 在ES5中,类是由函数名首字母大写的函数,通过关键字new创建的. 类的构造函数就是函数自身 一般情况下,ES5类的原型对象prototype是自身构造函数,该类的实例化对象的原型链对象__proto__也是该构造函数,这二者指向同

javascript原型链理解

javascript原型和原型链的引入,最初的目的是属性和方法的共享.没有原型,我们使用同一个构造函数新建的一系列对象,就都拥有一组完全相互独立的属性和方法,但是方法和一些属性我们不需要所有对象都各自有一个,有时候我们甚至需要所有对象的这些属性和方法是同一个,可以达到修改一个,所有的都要改变.这种需求在C#.java等语言中使用类和继承来实现,在js中没有用这种方法,而是给多有对象给了一个__proto__属性,同一个构造函数创建的所有对象的__proto__属性指向同一个对象,这个对象就是构造

js中原型和原型链理解

js中属性的继承以及查找都会用到原型链的知识,对于深入学习js的人来说是一个难点也是一个重点,下面梳理下对于原型以及原型链的理解. 首先,我们要知道什么是原型以及原型链?他们有什么样的作用? 可以理解为JS对象在创建时都会与之关联另一个对象,这就是我们所说的原型,每一个对象都会从原型"继承"属性.下图表示了构造函数与实例原型的关系,其中Object.prototype表示实例原型. 那么实例与实例原型又是怎么联系的呢?接下来又要说到另一个属性__proto__,每一个JS对象都有一个属

原型原型链理解

由来 js是基于原型的语言,没有类的概念,为了描述联系对象和对象之间的关系就有了原型和原型链. 原型 原型(prototype)就是模板,本质也是一个对象,它定义了构造函数构造出来的对象可以继承该原型的属性和方法,用于表示对象之间的关系.每个函数都有一个prototype属性,这个属性指向的就是原型对象:实例上有一个__proto__指向它的构造函数的原型对象. 特点 prototype只有函数有,对象没有 原型链 定义 每个对象上拥有一个__proto__属性指向原型对象,对象以其原型为模板,

原型、原型对象、构造函数、原型链理解

1. 基本概念: "原型属性"也可以叫做"原型"(prototype):所有函数都有prototype,我觉得可以理解为python中的类属性,不需要通过实例,直接用类(es5就是函数名)可以调用,下面列举了三种创建函数的方法,函数创建后都有prototype属性,prototype指向"原型对象". // 函数声明 function F1() { }; // 表达式定义 let F2 = function () { }; // 函数构造 let

JS原型链理解

1. 每个对象都有原型属性(__proto__)2. 对象的原型(__proto__)指向其构造函数(Class)的prototype属性3. 构造函数(Class)的prototype属性本身也是一个对象,其原型(__proto__)亦指向其构造函数的prototype4. 如此形成一个链式结构,而Class.prototype若没有自定义构造函数,则其始终是一个对象,构造函数为Object,  原型为Object.prototype5. Object.prototype的原型为null,原型

js原型和原型链理解 constructor 构造函数

一.对象:普通对象   函数对象 二.构造函数特点:1.需要new实例化,内部使用this对象指向即将要生成的实例对象  2.首字母大写,用于区分普通函数 function Person(name){ this.name=name } var person1=new Person('xiaohong') var person2=new Person('lili') person1.constructor=Person   constructor指向构造函数,Person的内置属性 Person.

javascript作用域链理解

执行上下文(Execution context,简称EC) 概念 每当控制器到达ECMAScript可执行代码的时候,就进入了一个执行上下文. javascript中,EC分为三种: 全局级别的代码(全局执行上下文) 函数级别的代码(函数执行性上下文) Eval的代码(eval执行上下文) 执行上下文对象包括三个关键属性,可能有其他自定义属性. VO(Variable object), 变量对象 或者 AO(activation object),活动对象,是个字典,包括函数arguments对象

深刻理解JavaScript基于原型的面向对象

主题一.原型 一.基于原型的语言的特点 1 只有对象,没有类;对象继承对象,而不是类继承类. 2  "原型对象"是基于原型语言的核心概念.原型对象是新对象的模板,它将自身的属性共享给新对象.一个对象不但可以享有自己创建时和运行时定义的属性,而且可以享有原型对象的属性. 3 除了语言原生的顶级对象,每一个对象都有自己的原型对象,所有对象构成一个树状的层级系统.root节点的顶层对象是一个语言原生的对象,其他所有对象都直接或间接继承它的属性. 显然,基于原型的语言比基于类的语言简单得多,我