Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

类的本质概念与JavaScript对应实现

  无论是面向对象还是面向过程,程序最终都是顺序执行的,只是有编译器在解析一些东西所以所以无法从代码上直观的看出。实际上程序都是从个一个入口函数看是的,只是有时候这个入口函数被语言本身封装的已经看不到原样了,只有一些底层的语言中才能直接找到他们。
  C语言中入口函数是main,但是通常操作系统中main函数的返回值是作为进程的退出代码使用的。所以C语言中标准的main函数返回值是int类型。但是看Java的“public void main”,虽然名字也叫main,但是概念就完全不同了。Java本身管理了main函数,而自己规定一个main函数给开发者,也就是说main函数被Java封装了。不仅是Java,只要稍微高级点的编程语言或框架都是在对原本顺序执行的概念做封装。而且main函数只是最基本例子,像Java那样的高级语言几乎已经封装的看不出程序的基本执行原理了。
  类实际上就是在封装程序,把原本顺序执行的代码在逻辑上封装的一块块的以便管理。而类本身其实只是逻辑概念,它是编程语言的东西,而不是程序的东西。类本身甚至不占任何内存只是编译时存在的逻辑信息。也许这种说法很纠结,类中确实有方法和一些常量,这些东西是需要占内存的。但是他们在程序中并不是类本身,而是一堆预定义的常量而已,类只是把这些常量给逻辑化了。即使不使用类,程序中需用用到的常量也依然会存在。
  类是一个管理逻辑的东西,对应到JavaScript中,它是Object而不是Function。类中有方法、属性、事件,这些东西都是名字和类型以及初始常量对应的,类似key-value结构的。类在编译型语言中不占程序内存,但是JavaScript是脚本语言,没有编译的概念。或者脚本语言本身就需要管理编译器的内存。所以如果要在JavaScript中实现类,那就用是一个普通的Object来存储类的信息。因为Object本身是hash存储的,本身就是key-value结构的。
  当我们需要实例化一个类时,编程语言就照着类中描述的名称和类型到内存中申请一组内存。比如一个类中有一个test方法,首先这个方法的函数被作为常量储存。当实例化这个类时,test是一个函数,是指针类型,所以申请一块足够容纳指针的内存,并让它指向test这个函数常量。在JavaScript中,我们把对象放入构造器的prototype。然后new这个构造器就可以得到一个可以访问构造器prototype的对象。比如构造器的prototype中有一个test方法,那么它的实例就可以访问到这个test方法,虽然原理有些不同。但是这就和类继承做的事情是一样的。
  类中还有构造函数,它会在实例化时调用。但是函数不可能平白无故的就自己运行了,构造函数必然是被什么东西调用的。实际上我们实例化一个类时编程语言调用了构造函数。或者说编译时在执行实例化的地方插入了一个call。JavaScript中虽然有构造器函数,但是它的性质和类的构造函数是完全不同的。我们应该用构造器函数去调用实例中的“构造函数”。如果构造函数名为“init”,我们就应该在构造器函数中执行“this.init.apply(this,arguments)”,而不是把整个构造器函数当做构造函数来使用。
  其实类就是一个逻辑概念,它只是描述一个对象的属性、方法、事件。对于其它的东西,比如访问权限、继承,都只是编程语言赋予它的而已。比如私有成员不能外部访问,为什么不能?实际上我们访问私有成员时候是被编程语言阻止了,如果编译器中可以把这个阻止去掉程序也依然可以编译出来。因为都是一块内存没理由不能访问,只是编程语言自己规定不允许而已。
  最后咱也来模拟下类这东西,不过我这里使用了__proto__,目前IE不兼容它。 //构造器
var A=function(){
  this.A.apply(this,arguments);
};
//类
A.prototype={
  A:function(){
    //构造函数
    this.name=name;
  },getName:function(){
    //方法
    return this.name;
  },name:"" //属性
};
//构造器
var B=function(){
  this.B.apply(this,arguments);
};
//继承于A的类
B.prototype.__proto__=A.prototype;
//构造函数
B.prototype.B=function(name){
  this.name=name;
};

var b=new B("次碳酸钴"); //实例化

console.log(b.getName());
console.log(b instanceof B);
console.log(b instanceof A);
console.dir(b);
网名:
52.91.185.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^