由于工作需要项目中要用prototype框架,所以这几天捣鼓了一下,研究了一下prototype 创建对象和类以及继承的一些源码,其实早在很久以前就接触prototype,然后直接看源码, 看着太蛋疼,里面的牵连太多太深, 绕来绕去,脑袋都绕晕了, 所以索性直接看prototype官方教程里面Class.create()这个函数的使用方式,了解了它的使用方式以后我们再来一步一步的反推它是怎么实现的,这里注意一下我不是直接讲的prototype源码实现这一块的内容,说穿了源码我看着也晕, 上面都说了东西太多牵连太深。好了, 废话就不多说了,我们直接进入主题

我们先来看一段基于prototype来创建对象以及继承的一段代码

//创建一个动物类
var Animal = Class.create({
//初始化构造函数
initialize: function(name, type) {
this.name = name;
this.type = type;
},
//动物类的方法
speak: function() {
alert("my name is "+name);
}
});

上面这段代码描述一个基于prototype写的动物类, 不得不佩服在面向对象这一块prototype设计的非常整洁和优雅,既然创建了一个类,下面我们来使用这个,如果有过java背景或者面向对象高级语言的同学是不是觉得调用方式有点相似,这样就体现出javascript在实现面向对象这一块还是很有优势的。

//下面我们来使用这个动物类
var animal = new Animal('小白', 'dog');
animal.speak();

但是现在问题来了,光能创建类就不能对刚刚创建的类进行扩展或者继承嘛, 答案是肯定的,要不然怎么说是大名鼎鼎的prototype嘛,好, 下面我们就来实现继承这个Animal类

//创建人类,继承自动物类
var Person = Class.create(Animal, {
initialize: function($super, name, type) {
$super(name, type);
},
work: function() {
alert(this.name+"今天工作了一整天,虽然有点累但很开心");
}
});

好到这里面我们已经看到prototype的强大之处了吧,那现在我们来说说这种方式创建类的一些特性,以便我们在后面来实现这样写面向对象做一些铺垫,那到底有什么一些特性或者特点呢

1.是通过Class.create()这个函数来创建类的,接受一个或者两个参数,这个函数重载了的

2.这个函数返回一个类,这个类又可以通过new的方式给为我们创建对象

3.每个类都有一个initialize方法,这个是一个构造器可以用于初始化构造对象

4.如果Class.create(base, child)方法重载了两个参数,那么base就是基类,child类是继承自base类的

上面说了prototype创建对象时的一些基本特点,下面我们就要来详细分析一下prototype创建到底是怎么来实现的,首先声明我不是看prototype框架源码来分析,我是根据这些写对象的一些特性来进行的,我们都知道如果声明一个函数,这个函数就是一个构造器,可以把它new出来的,看看下面的代码思路会更清晰

//这样也能创建一个类,至于它与prototype的优劣只有自己体会了
function Animal(name, type) {
this.name = name;
this.type = type; this.speak = function() {
alert("my name is"+this.name);
};
}
var animal = Animal("小黄", "dog");
animal.speak();

现在大家知道如果要采用new的方式肯定要有构造器,说白了就是一个函数,那现在我们知道Class.create()这个方法返回的是一个函数了吧,但是这到底是个怎么样的函数呢,接着在进行挖掘,首先我们来分析当传入一个参数也就是创建一个类没有继承的时候是这样一种情况

var Animal = Class.create({
//初始化构造函数
initialize: function(name, type) {
this.name = name;
this.type = type;
},
//动物类的方法
speak: function() {
alert("my name is "+name);
}
});

其实就是传入的了json参数,里面放了两个函数,一个构造函数和一个成员函数,刚刚我们讲了这个Class.create()方法返回的是一个函数,传入的又是一个json, 那我们肯定要将json里面的函数复制到返回出来的这个函数里面,请看下面代码

var Class = {
create: function(object) {
var fn = function() {};
fn.prototype = object;
return fn;
}
};
//好了, 现在我们可以用上面的这个Class.create()方法来创建一个类
var Animal = Class.create({
initialize: function(name) {
this.name = name;
},
speak: function() {
alert("my name is "+this.name);
}
});
//下面我来new一下创建这个动物类
var animal = new Animal();
animal.initialize("dog");
animal.speak();

上面这段代码是不是和prototype创建对象有点不一样,细心的同学会发现我们在new Animal()这个动物类的时候没有参数, 构造参数是通过animal.initialize()来初始化的,这样就不对了, prototype不是通过构造函数的时候就直接调用initialize()函数来进行初始化的吗,没错,所以我们要将上面的代码做一些小小的修改,上代码吧

var Class = {
create: function(object) {
var fn = function() {
this.initialize.apply(this, arguments);
};
fn.prototype = object;
return fn;
}
}; var Animal = Class.create({
initialize: function(name) {
this.name = name;
},
speak: function() {
alert("my name is "+this.name);
}
});
//下面我来new一下创建这个动物类
var animal = new Animal("dog");
animal.speak();

到这里大家应该能看清楚到底是哪儿做了改动吧,this.initialize.apply(this, arguments); 就是在这儿做了手脚,fn这个函数在创建类的时候是会被返回的,所以在new这个被返回的函数里面可以做初始换的一些东西,就是调用我们的initialize()函数来进行初始化了, 这里声明一些哈,如果没有对javascript, this, 闭包,作用域,原型链方面的知识理解就非常痛苦了,不过我还是会大概说一下,this.initialize.apply(this, arguments);我们对这句话进行分解, this 其实指的是{init:functdion(), speak:function() {}}这个传进去的对象,apply(this, arguments), apply是将当前函数的上下文改变也就是把this改变,arguments就是一个函数运行时的参数,这样说可能有点同学不是很明白,如果实在看不明白javascript基础知识需要补补课了。现在我们能实现向prototype的语法一样来创建一个了类, 但仅仅是创建一个类,如果需要继承怎么办呢, 就像这样Class.create(base, object); 这个object要继承base, 大家都知道如果在继承的话肯定是要将base里面的成员和方法copy到object里面来,就这么简单吗, 我们来仔细想一下吧,应该有以下几点

首先将基类的成员copy到子类里面

  a. 如果子类的成员变量和积累的同名,会覆盖基类的

  b.子类的成员方法和基类的同名会覆盖积累的

  c.能不能子类和基类的成员方法进行重载呢,答案是肯定的

  d.手动控制调用基类的构造方法进行初始化会更灵活

以上这些就是prototype创建类的一些特性, 可能还不完善,欢迎大家讨论。 下面我们就用代码具体的实现,我会尽量用多的注释来标注方便大家理解和传播

var Class = {
/*
*功能:创建一个类
*参数:
* 1.base 表示基类,但一定要是functdion类型的
* 2.object 表示要创建的子类,json数据格式类型的
*/
create: function(base, object) {
var fn = null;
//这个判断主要是创建有没有继承的类
//一般情况其实就是检测create()方法是一个参数还是两个参数
if(typeof base == "function") {
//这个就是创建要返回的函数
fn = function() {
var args = [];
//这个判断是检测子类initialize($super, ...)方法里面参数
//如果有$super这个参数就是传了基类的构造函数可以调用,反之就没有
if(object.initialize.length > arguments.length) {
//这里就是把基类的构造函数加入到args函数里面
//这里大家可以仔细体会一下这儿为什么要用一个闭包,还有
//apply(fn.prototype, arguments)方法里面两个参数的意义
args.push(function() {
base.prototype.initialize.apply(fn.prototype, arguments);
});
}
//将构造函数里面的参数加入到这个args数组
for(var i = 0 ; i < arguments.length ; i++) {
args.push(arguments[i]);
}
//执行构造函数的初始化参数
this.initialize.apply(this, args);
};
//先将积累里面的成员变量和方法copy到返回函数fn里面
for(var property in base.prototype) {
if(property != "initialize") {
fn.prototype[property] = base.prototype[property];
}
}
//在将子类里面成员变量和方法copy到返回函数fn里面
//注意这里为什么要先拷贝基类在拷贝子类,原因是
//基类和子类的成员变量和方法重名的话优先的是子类的
for(var property in object) {
fn.prototype[property] = object[property];
}
}
//这个是没有继承的情况就非常简单了, 上面有讲到,
//这里就不再细细叙述了
else {
fn = function() {
this.initialize.apply(this, arguments);
}
fn.prototype = base;
}
return fn;
}
} //下面就可以像prototype语法一样写出优雅的代码,
//这段是prototype官方Class.create()APi的源码实例 //创建一个动物类
var Animal = Class.create({
initialize: function(name, sound) {
this.name = name;
this.sound = sound;
}, speak: function() {
alert(this.name+"says:"+this.sound+"!");
}
});
//实例化调用
var dog = new Animal('gogo', "wangwang");
dog.speak(); //创建一个人类,继承自动物类
var Snake = Class.create(Animal, {
initialize: function($super, name) {
//alert($super);
$super(name, 'hisssssssssssssss');
},
say: function() {
alert("my name is "+this.name);
}
}); //实例化调用
var ringneck = new Snake("Ringneck");
ringneck.speak();
ringneck.say();

说到这里prototype的 Class.create()方法的内核源码基本上就告一段落了,当然还有一些其他的方式,也各有千秋,大家可以看一下

var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}; var Animal = Class.create();
Animal.prototype = {
initialize: function(name) {
this.name = name;
},
say: function() {
alert("my name is "+this.name);
}
};

深入prototype源码之--Class的更多相关文章

  1. React v16-alpha 从virtual dom 到 dom 源码简读

    一.物料准备 1.克隆react源码, github 地址:https://github.com/facebook/react.git 2.安装gulp 3.在react源码根目录下: $npm in ...

  2. jQuery 源码分析 8: 回头看jQuery的构造器(jQuery.fn,jQury.prototype,jQuery.fn.init.prototype的分析)

    在第一篇jQuery源码分析中,简单分析了jQuery对象的构造过程,里面提到了jQuery.fn.jQuery.prototype.jQuery.fn.init.prototype的关系. 从代码中 ...

  3. prototype.js 源码解读(02)

    如果你想研究一些比较大型的js框架的源码的话,本人建议你从其最初的版本开始研读,因为最初的版本东西少,易于研究,而后的版本基本都是在其基础上不断扩充罢了,所以,接下来我不准备完全解读prototype ...

  4. prototype.js 源码解读(01)

    prototype.js是一个设计的非常优雅且很有实用价值的js基础类库,其源码非常值得研究.研究它的源码不仅能提升个人水平,而且对你打下坚实的js基础也很有帮助.因本人技术水平有限,该解读仅供参考. ...

  5. .29-浅析webpack源码之Resolver.prototype.resolve

    在上一节中,最后返回了一个resolver,本质上就是一个Resolver对象: resolver = new Resolver(fileSystem); 这个对象的构造函数非常简单,只是简单的继承了 ...

  6. jquery源码'jQuery.fn.init.prototype'

    一般我们在创建构造函数即使用的时候会这样写,使用的时候会使用new 关键字,先实例化,然后使用. function test(name, age) { this.name = name; this.a ...

  7. 观V8源码中的array.js,解析 Array.prototype.slice为什么能将类数组对象转为真正的数组?

    在官方的解释中,如[mdn] The slice() method returns a shallow copy of a portion of an array into a new array o ...

  8. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  9. HTML5游戏源码 飞翔的字母 可自定义内容

    相信大家都玩过飞翔的小鸟吧,当然,可能已经有很多人因为这个游戏砸了不少手机.吼吼. 废话不多说,回到主题,源码如下. 博客园上传空间大小有限制,没法上传了,需要打包源码的朋友们请留言邮箱地址.当然还有 ...

随机推荐

  1. Akka Stream文档翻译:Quick Start Guide: Reactive Tweets

    Quick Start Guide: Reactive Tweets 快速入门指南: Reactive Tweets (reactive tweets 大概可以理解为“响应式推文”,在此可以测试下GF ...

  2. Error building Player: CommandInvokationFailure: Failed to re-package resources. See the Console for details. ShareSDK 也有这种错误

    Error building Player: CommandInvokationFailure: Failed to re-package resources. See the Console for ...

  3. SQLite入门与分析(二)---设计与概念

    写在前面:谢谢各位的关注,没想到会有这么多人关注.高兴的同时,也感到压力,因为我接触SQLite也就几天,也没在实际开发中用过,只是最近项目的需求才来研究它,所以我很担心自己的文章是否会有错误,误导别 ...

  4. Centos之LAMP环境搭建

    原文:http://blog.sina.com.cn/s/blog_c02ed6590101d2sl.html 一.安装 MySQL 首先来进行 MySQL 的安装.打开超级终端,输入: [root@ ...

  5. Spring中的Resource

    Spring中的资源定义:Resource此接口的全名为:org.springframework.core.io.Resource比较常用的资源定义的实现类为:1.ClassPathResource ...

  6. C#解析.msg文件(outlook文件)

    起因 有一批邮件(700+),全是 .msg 文件,是同群发邮件产生的退信,这些退信需要作分析,得出退信产生的原因. 解决方法 在网上搜了一下发现 .msg文件有其自己的格式,MS提供了格式说明,自己 ...

  7. 2.1 linux中uboot移植

    -- --------------------------------------------------------------------------------------- (一)友善之臂介绍 ...

  8. Spring事务Transaction配置的五种注入方式详解

    Spring事务Transaction配置的五种注入方式详解 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学 ...

  9. POI 中Cell的backgroundcolor和foregroundcolor

    刚开始以为要获得cell的背景色是使用  getFillBackgroundColor()这个函数(这里返回的是调色板的索引,要获得RGB需要先获得系统的Pallete,然后在获得 RGB).结果出来 ...

  10. 函数flst_init

    /** The null file address */UNIV_INTERN fil_addr_t fil_addr_null = {FIL_NULL, 0}; /***************** ...