createjs进阶—createjs的OOP

  • 内容
  • 评论
  • 相关

OOP大家都知道就是面向对象编程,对于程序构建,特别是大项目,可以说是必不可少的。可以用它来降低开发难度,提高代码的重用率等等。在createjs里可以用它特有的写法和api来实现OOP。无论你是从as转到js,还是本来就是写js的,学会在createjs里使用OOP编程都是很重要的,废话不多说,我直接讲下怎么在createjs里使用OOP。

(不懂OOP的请先了解OOP后再看本教程)

1.类一般语言(我先拿as作为例子),生成一个类一般是

public class MainView 然后调用的是 new MainView()这样子,在js里没有类这个概念,但是我们可以模仿,写一个差不多的。

我们先写出类:

function Map(){
    this.name = "中国"
}
var map = new Map();
console.log(map.name)

可以看到我们就输出了地图,这里的Map相当于构造函数

2.闭包

(function() {
    function Map(){
        this.name = "地图"
    }
    var map = new Map();
}());
console.log(map);

大家上面还看到了一个(function() {}());这个格式的语法吧,这个东西干嘛用的呢,做过前端的童鞋肯定知道,它叫闭包。简单的来说吧,就是防止变量之间污染,js与类java语言不一样,类java语言比如as3,他在类里面var的变量只在类里面有用,但是js是都有用,这样的话项目一大变量之间就容易相互污染,而闭包可以很好的解决这问题,写as3转js的童鞋可以把它当做package包。这里的console因为在包外面,所以会报错。

3.继承

继承是非常重要的OOP方法,思考一下你做游戏的时候要new10个不同的角色,如果他们都间接继承与一个基础角色类,那么你要统一改他们的方法,只需要改一个方法,而不是改十个。

这回就要用到createjs的继承api了。

function Map(){
    this.name = "地图"
}
var map = new Map();

var cls = {};

(function() {
    function ChinaMap(){
        this.Map_constructor();//构造
    }
    var p = createjs.extend(ChinaMap,Map);//继承
    p.from = "中国";
    p.changeFrom = function (data)
    {
//        p.from = data;//这样就会出错 输出2个美国
        this.from = data;
    }
    cls.ChinaMap = createjs.promote(ChinaMap, "Map");//提升
}());

var map1 = new cls.ChinaMap();
var map2 = new cls.ChinaMap();
map1.changeFrom("美国");
console.log(map1.from,map2.from,map1.name,map2.name);

输出出来是 美国 中国 地图 地图。

ChinaMap继承了map的属性,所以map1和map2输出name,都能输出Map中的name。这里的createjs.extend相当于,OOP语言里的extend。而我定义的cls相当于是我保存类的一个地方。而这里的p就是继承后对象的原型链,在p中可以定义方法,定义属性,当然在构造中也可以定义方法和属性。

另外大家也看到了,类里面的方法是不能用原型链来调用方法和修改属性的,因为如果调用所有实例化这个类的对象都会被调用到,所有的属性也都会被修改。

注意:animteCC调出来的类,继承需要特殊的继承写法,文章结尾介绍。还有,平时写as的童鞋写显示类的时候通常会继承Sprite 而在createjs中可以选择继承Container,千万不要也继承Sprite flash as的sprite和createjs的sprite不是一种东西 

4.提升

createjs.promote大家可能会觉得陌生,他是createjs特有的处理方法,也是非常聪明的做法,他的作用是“提升”,什么意思呢?其实就是让当前类可以调用其父类爷爷类祖宗类,也就是类名_方法名就可以调用了

function Map(){
    this.name = "地图"
}
var map = new Map();
var cls = {};

(function() {
    function ChinaMap(){
        this.Map_constructor();
        this.city = "北京";
        this.traceCity = function ()//构造中的方法不会被提升
        {
            console.log(this.city,this.from);
        }
    }
    var p = createjs.extend(ChinaMap,Map);
    p.from = "中国";
    p.traceFrom = function traceFrom()
    {
        console.log(this.from,this.city);
    }
    cls.ChinaMap = createjs.promote(ChinaMap, "Map");
}());

(function() {
    function HZMap(){
        this.ChinaMap_constructor();
        this.traceCity = function ()
        {
            console.log(this.ChinaMap_city,this.ChinaMap_from);
        }
    }
    var p = createjs.extend(HZMap,cls.ChinaMap);
    p.traceFrom = function traceFrom()//这里就是重写了父类的方法
    {
        console.log(this.ChinaMap_from,this.ChinaMap_city);
    }
    cls.HZMap= createjs.promote(HZMap, "ChinaMap");
}());

var hzMap = new cls.HZMap();
console.log(hzMap.ChinaMap_from);//undefined 只有方法会被提升
hzMap.ChinaMap_traceFrom();//中国 北京
//hzMap.ChinaMap_traceCity();//这里会出错 只有原型链中的方法会被提升
hzMap.traceFrom();//undefined undefined 只有方法会被提升 内部调用一样不行

在上面的代码中,大家可以看到,子类虽然重写了父类的方法,但是依然可以调用父类的方法,只需要父类_方法就可以了,当然,只有原型链中的方法,才会被提升

很多人会忽视提升的作用,其实提升除了可以调用父类方法,还可以使继承来的属性“合法化”。

var cls = {};
function People(){
    this.name = "李小龙"
}

//(function() {
//    function GodPeople(){
//        this.__proto__.__proto__.constructor();
//    }
//    var p = createjs.extend(GodPeople,People);
//    cls.GodPeople = GodPeople;
//}());

//var people = new cls.GodPeople();
//console.log(people.name);
//console.log(people.hasOwnProperty("name"))//这里输出的是false

(function() {
    function GodPeople(){
        this.People_constructor();
    }
    var p = createjs.extend(GodPeople,People);
    cls.GodPeople= createjs.promote(GodPeople, "People");
}());

var people = new cls.GodPeople();
console.log(people.name);
console.log(people.hasOwnProperty("name"))//这里输出的true

在上面代码中,如果使用上面注释中的代码,检查属性的时候属性就不属于该类本身,原因也很简单,因为这个属性是属于他父类的。(这个问题在很多js框架中都会被忽视,但是createjs却解决了这个问题,说明createjs的团队只是懒,能力还是很强的么^_^)

5.构造

构造简单的讲就是类的初始化方法,在js中constructor相当于构造函数,也就是经过上面的代码提升后,this.Map_construtor就是调用父类的构造函数,是写一个类必须的,相当于as3的this.super();

6.重写

重写的话,直接在构造或者原型链中重新定义属性或者方法就可以了,但是由于构造中的方法不会被提升,所以重写也尽量在原型链中重写

7.公有私有 js没有 public private protected 等控制属性方法权限的语句,私有方法直接写在闭包内就可以了。

(function() {
    var _no;//私有属性
    var _run;//私有方法
    function HZMap(){
        this.ChinaMap_constructor();
        this.from = "中国";
        this.city = "杭州";
        _no = "123456"
        _run = function ()
        {
            console.log("我是一张底图,但是我不会跑。")
        }
    }
    var p = createjs.extend(HZMap,cls.ChinaMap);
    p.traceFrom = function traceFrom()
    {
        //这里是类的内部,可以访问
        console.log(this.from,this.city,_no);
        _run();
    }
    cls.HZMap= createjs.promote(HZMap, "ChinaMap");
}());
var hzMap = new cls.HZMap();
hzMap.traceFrom();
console.log(hzMap._no,hzMap._run);//这里由于是类的外部,访问不到私有属性和方法

但是这和一般语言中的私有还是有区别的,一般语言中的私有,你虽然不能用,但是在查看表达式的时候还是看得到的。但是在这里的私有,你在外面是看不到的。所以从架构的角度讲,不要使用上面那种私有。直接在需要私有的属性或方法的命名上写个下划线“_”,程序员之间做个约束,看到带下划线的属性不要去改他就好了。

(并且你还要保证类只new一次,不然二次以上私有属性方法就会在各个new出来的对象中污染了,总之这种私有方法不推荐)


↑ 封装类必不可少的东西

另外还有一个问题,在没有createjs的环境下也能使用这些oop的api吗,答案是可以的,我还特意把相关代码提取了出来,只要把下面的代码放入项目中,不引入createjs,也能使用oop的api

this.oop = this.oop||{};
oop.extend = function(subclass, superclass) {
    function o() { this.constructor = subclass; }
    o.prototype = superclass.prototype;
    return (subclass.prototype = new o());
};
oop.promote = function(subclass, prefix) {
    var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__;
    if (supP) {
        subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable
        for (var n in supP) {
            if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; }
        }
    }
    return subclass;
};

就这么简单的2个方法……

最后讲一下,animateCC生成的类怎么继承,直接上代码:

var cls = {};
cls.MyMc = function MyMc(){
    this.__proto__ = new lib.mc();
}
var mc = new cls.MyMc();
mc.stop();
stage.addChild(mc);

大家可以看到由于animateCC生成mc的方式不同,导致我们也只能用类似的方式来继承。

本篇文章对于不熟悉OOP的同学来说相当晦涩难懂,没关系,不懂的童鞋可以到官方讨论群咨询。群号:320648191

dashang.jpg

评论

15条评论
  1. Gravatar 头像

    匿名 回复

    其实可以直接引入外部的 js 文件,然后在外部的 js 里面写好复杂的函数,最后导出一个变量到window全局中,最后使用变量就好了,如果是熟悉 es6 的同学,直接使用 class 进行对象创建等操作都可以,AN 中的js好像还是es3,很难受

  2. Gravatar 头像

    彭江 回复

    非常喜欢你的文章,非常。。。好!

  3. Gravatar 头像

    明升m88.com 回复

    便是这个留言板 能够设置成 显示最新的顺序

  4. Gravatar 头像

    m88明升 回复

    请问站长微信编辑页面是怎么做出来的?

  5. Gravatar 头像

    ajex 回复

    可以

  6. Gravatar 头像

    腾博会 回复

    站长写得真是非常好,我要让我的朋友也看一下这篇风趣|有趣的文章

  7. Gravatar 头像

    腾博会 回复

    很久没来看博主的文章了,说的很有道理,支持一下!

  8. Gravatar 头像

    365bet体育在线官网 回复

    你好,请问小编可以让我转载这篇文章内容吗?我会备注原文出处链接的以及作者

  9. Gravatar 头像

    365bet官网 回复

    写得很是独到,把外围的思惟都表白了进去。

发表评论

电子邮件地址不会被公开。