面向对象编程

转载自 阮一峰
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

封装数据和方法,以及如何从原型对象生成实例

//一,生成实例对象的原始模式
var Cat={
        name:"",
        color:""
    }
    var cat1={};
    cat1.name="大毛";
    cat.color="黄色";
    var cat2={};
    cat1.name="二毛";
    cat.color="黑色";`
    //实例与原型之间,没有任何办法看出联系
//二,
    function Cat(name,color){
        return {
            name:name,
            color:color
        }
    }
    //然后生成实例对象,就等于在调用函数
        var cat1=Cat("大毛","黄色")
        var cat2=Cat("二毛","黑色")
        //cat1和cat2之间没有内在的联系。不能反映出它们是同一个原型对象的实例
//三,构造函数模式
    //其实就是普通函数,但是内部使用了 this 变量。对构造函数使用 new 运算符,就能生成实例,并且this变量会绑定在实例对象上。
    function Cat(name,color){
        this.name=name;
        this.color=color;
    }
    var cat1 = new Cat("大毛","黄色");
    var cat2 = new Cat("二毛","黑色");
    //这时,cat1和cat2会自动含有一个 constructor 属性,指向他们的构造函数
        alert(cat1.constructor == Cat);//true
        alert(cat2.constructor == Cat);//true
        //js还提供了一个instanceof运算符,验证 原型对象 与 实例对象之间的关系
        alert(cat1 instanceof Cat);//true
        alert(cat2 instanceof Cat);//true
//四。构造函数模式的问题
    //浪费内存   OK 现在我们为Cat对象添加一个不变的属性 type 种类,再添加一个 eat方法。那么 如下
    function Cat(name,color){
        this.name = name;
        this.color = color;
        this.type = "猫科动物";
        this.eat = function(){
            alert("吃猫粮");
        }
    }
    var cat1 = new Cat("大毛","黄色");
    var cat2 = new Cat("二毛","黑色");
    alert(cat1.type);//猫科动物
    cat1.eat()//吃猫粮
    //表面上好像没问题,但是其实有一个很大的弊端。每一个实例对象,type属性 和 eat()方法都是一摸一样的内容,每一次生成一个实例,都是重复的内容,占内存
    alert(cat1.eat == cat2.eat);//false
        //能不能只在内存中生成一次,然后所有的实例指向那个内存地址呢?答案是肯定的
//五,Prototype模式
    //js规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
    //which means,我们可以把那些 不变的 属性和方法,直接定义在 prototype 对象上
    function Cat(name,color){
        this.name = name;
        this.color = color;
    }
    Cat.prototype.type = "猫科动物";
    Cat.prototype.eat = function(){alert("吃猫粮");}
    //然后,生成实例
        var cat1 = new Cat("大毛","黄色");
        var cat2 = new Cat("二毛","黑色");
        alert(cat1.type);//猫科动物
        cat1.eat();//吃猫粮
        //这是所有实例的 type属性 和 eat()方法 ,其实都是同一个内存地址,指向 prototype 对象
        alert(cat1.eat == cat2.eat);//true
//六,prototype模式的验证方法
    //为了配合prototype属性,js定义了一些辅助方法,帮助我们使用它
        //1. isPrototypeOf()
            //这个方法用来判断,某个prototype对象 和 某个实例 之间的关系
            alert(Cat.prototype.isPrototypeOf(cat1));//true
            alert(Cat.protptype.isPrototypeOf(cat2));//true
        //2.hasOwnProperty()
            //每一个实例对象都有一个hasOwnproperty()方法,用来判断某一个属性到底是 本地属性,还是 继承自prototype对象 的属性
            alert(cat1.hasOwnProperty("name"));//true
            alert(cat1.hasOwnProperty("type"));//false
        //3.in运算符
            //可用来判断,某个 实例  是否含有某个属性,不管是不是  本地属性。
            alert("name" in cat1);//true
            alert("type" in cat1);//true
            //还可用来遍历 某个对象 的所有  属性
            for(var prop in cat1){alert("cat1[prop]="+cat[prop])}

//对象之间的”继承”的五种方法

    function Animal(){
        this.species = "动物";
    }
//还有一个"猫"对象的构造函数
    function Cat(name,color){
        this.name = name;
        this.color = color;
    }
//怎么才能使"猫"继承"动物"呢?
    //一,构造函数 绑定
        //最简单的方法,使用call或apply方法,
        //将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
        function Cat(name,color){
            Animal.apply(this,arguments);//apply用法:add.apply(sub,arguments) == add(arguments)
            this.name = name;
            this.color = color;
        }
        vat cat1 = new Cat("大毛","黄色");
        alert(cat1.species);//动物
    //二。prototype模式
        //更常见的是,使用prototype属性
        //如果"猫"的prototype对象,指向一个Animal的实例,那么所有的"猫"的实例,就能继承Animal了。
        Cat.prototype = new Animal();
        Cat.prototype.constructor = Cat;//这句为什么这么写呢,下面有解释。
        var cat1 = new Cat("大毛","黄色");
        alert(cat1.species);
            //首先
            Cat.prototype = new Animal();   //Cat的prototype对象指向一个Animal的实例。相当于完全删除了prototype对象原先的值,然后赋予了一个新值。
            alert(Cat.prototype.constructor);//function Animal()...  //obj.constructor构造器 指向它的构造函数. 指向了Animal()
            var cat1 = new Cat("大毛","黄色");//每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性
            alert(cat1.constructor);//function Animal()...
            //这显然会导致继承链的紊乱(cat1明明是用构造函数Cat生成的),因此我们必须手动纠正,将Cat.prototype对象的constructor值改为Cat.
            //这是很重要的一点,编程时务必要遵守。
                //即使替换了prototype对象:o.prototype={};
                //那么下一步必然是为新的prototype对象加上constructor属性,并将属性指回原来的构造函数
                //o.prototype.constructor = o;

    //三。直接继承prototype 
    //预告:错误的
        //第三种方法是对第二种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。
        //所以,我们也可以让Cat()跳过Animal(),直接继承Animal.prototype.
        //Animal对象改写:
            function Animal(){}
            Animal.prototype.species = "动物";
        //然后,将Cat的prototype对象,指向Animal的prototype对象,完成了继承。
            Cat.prototype = Animal.prototype;
            Cat.prototype.constructor = Cat;
            var cat1 = new Cat("大毛","黄色");
            alert(cat1.species)//动物
        //与前一种方法相比,这样做的优点是效率毕竟比较高(不用执行和Animal的实例了),比较省内存。
            //缺点是:Cat.prototype和Animal.prototype现在指向了同一个对象,那么,任何对Cat.prototype的修改,都会反映到Animal.prototype.
        //所以,上面的代码是有问题的,看第二行
        Cat.prototype.constructor = cat;
            //这一句实际上吧Animal.prototype对象的constructor属性也改掉了
    //四。利用空对象作为中介
        //直接继承prototype存在上述缺点 so 第四种
        var F=function(){}
        F.prototype = Animal.prototype;
        Cat.prototype = new F();
        Cat.prototype.constructor = Cat;
            //F是空对象,几乎不占内存。这是修改Cat.prototype对象,就不会影响到Animal.prototype对象
            alert(Animal.prototype.constructor)//Animal
        //将上面的方法,封装成一个函数,便于使用。
        function extend(Child,Parent){
            var F = function(){};
            F.prototype = Parent.prototype;
            Child.prototype = new F();
            Child.prototype.constructor = Child;
            Child.uber = Parent.prototype;//为子元素设置一个uber属性,这个属性直接只想父对象的prototype属性
                                            //uber德语"向上,上一层"。这等于在子对象上打开一条通道。可以直接调用父对象的方法。这一行只是为了实现继承的完备性,纯属备用性质。
        }
    //五。拷贝继承
        //上面采用的prototype对象,实现继承。我们也可以换一种思路。纯粹采用"拷贝"方法实现继承。
        //简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?
        function Animal(){}
        Animal.prototype.species="动物";
        //然后再写一个函数,实现属性拷贝的目的
        function extend2(Child,Parent){
            var p = Parent.prototype;
            var c = parent.prototype;
            for (var i in p){
                c[i] = p[i];
            }
            c.uber = p;
        }
        //这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype
        //使用时 extend2(Cat,Animal);
        var cat1 = new Cat("大毛","黄色");
        alert(cat1.species)//动物

//非构造函数的继承

//一,什么叫"非构造函数"的继承
    var Chinese = {nation:'中国'};
    var Doctor = {career:'医生'};
    //两个普通对象,如何让医生继承中国人,成为中国医生。
    //注意:不是构造函数,无法使用构造函数方法实现继承
//二,object()方法
    function object(o){
        function F() {}
        F.prototype = o;
        return new F()
    }
    //这个object函数,只做了一件事,就是把子对象的prototype属性,指向父对象,从而使得子对象与父对象连在一起。
    //使用的时候,第一步现在父对象的基础上,生成子对象
        var Doctor = object(Chinese);
        //然后再加上子对象本身的属性
            Doctor.career = '医生';
        alert(Doctor.nation)//中国
//三,浅拷贝
    //除了使用"prototype链"以外,还有一种思路,把父对象的属性,全部拷贝给子对象,也能实现继承。
    function extendCopy(p) {
        var c={};
        for (var i in p){
            c[i] = p[i];
        }
        v.uber = p;
        return c;
    }
    //使用:
    var Doctor = extendCopy(Chinese);
    Doctor.career = '医生';
    alert(Doctor.nation)//中国
    //但是这样的拷贝有一个问题。如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因为存在父对象被篡改的可能。

        //现在给Chinese添加一个"出生地"属性,它的值是一个数组。
        chinese.birthPlaces = ['北京','上海','香港'];
        //通过extendCopy()函数,Doctor继承了Chinese
        var Doctor = extendCopy(Chinese);
        Doctor.birthPlaces.push("厦门");//我们为Doctor的 birthPlaces 添加一个城市
        alert(Doctor.birthPlaces)
        alert(Chinese.birthPlaces)//what Chinese的"出生地"也被改掉了
            //所以,extendCopy()只是拷贝基本类型的数据,我们把这中拷贝叫做'浅拷贝'。
//四。深拷贝
    //所谓'深拷贝',就是能够实现真正意义上的数组和对象的拷贝。她的实现并不难,只要递归调用"浅拷贝"就行了
        function deepCopy(p,c){
            var c = c || {};
            for (var i in p) {
                if (typeof p[i] === 'object'){
                    c[i] = (p[i].constructor === Array) ? [] : {};
                    deepCopy(p[i],c[i]);
                }else{
                    c[i] = p[i];
                }
            }
            return c;
        }
    //使用 :
        var Doctor = deepCopy(Chinese);
        //现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性,这时,父对象就不会受到影响了。

</script>

</body>
独立储能的现货电能量与调频辅助服务市场出清协调机制(Matlab代码实现)内容概要:本文围绕“独立储能的现货电能量与调频辅助服务市场出清协调机制”展开,提出了一种基于Matlab代码实现的优化模型,旨在协调独立储能系统在电力现货市场与调频辅助服务市场中的联合出清问题。文中结合鲁棒优化、大M法和C&CG算法处理不确定性因素,构建了多市场耦合的双层或两阶段优化框架,实现了储能资源在能量市场和辅助服务市场间的最优分配。研究涵盖了市场出清机制设计、储能运行策略建模、不确定性建模及求解算法实现,并通过Matlab仿真验证了所提方法的有效性和经济性。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事电力市场、储能调度相关工作的工程技术人员。; 使用场景及目标:①用于研究独立储能在多电力市场环境下的协同优化运行机制;②支撑电力市场机制设计、储能参与市场的竞价策略分析及政策仿真;③为学术论文复现、课题研究和技术开发提供可运行的代码参考。; 阅读建议:建议读者结合文档中提供的Matlab代码与算法原理同步学习,重点关注模型构建逻辑、不确定性处理方式及C&CG算法的具体实现步骤,宜在掌握基础优化理论的前提下进行深入研读与仿真调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值