zoukankan      html  css  js  c++  java
  • js 面向对象设计之 Function 普通类

    
    
    var test = "Class01";
    
    function Class01(privateValue, publicValue) {
    
        var _this = this;
        if (this.constructor.name !== 'Class01') { throw new Error('类只能被实例化'); }
    
        /*统计实例化次数的自执行函数*/
        (function newClass() {
            Class01.count++; /*统计实例化的次数*/
            Class01.intances.push(_this); /*保存每个实例的引用*/
            console.log(Class01.count);
        })();
    
        /*私有变量和私有方法*/
        function privateMethod() { console.log('private method was called by publicMethod') } //
        var privateVal = privateValue;
        /*私有变量储存接口*/
        this.get = function () { return privateVal; };
        this.set = function (v) { privateVal = v; return this; };
    
        /*实例属性和实例方法(一般并不会创建实例方法,如果一定要定义实例方法,实例化之后自行添加)*/
        this.public = publicValue;
        this.publicMethod = function () {
            console.log('public method and then call private method');
            privateMethod();  /*内部使用私有方法*/
            return this;
        };
        /*实例方法可以使用类的静态属性和方法*/
        this.callClassStaticMethod = function () {
            console.log(Class01.staticValue);
            Class01.staticMethod();
        };
    }
    
    /* 原型属性和方法
     * 1、类被实例化次数和保存引用的数组也可以放在原型中
     * 2、每个实例都拥有其他实例的引用和实例化次数
     */
    Class01.prototype.proValue = 'this is Class01 prototype value';
    Class01.prototype.proMethod = function () {
        console.log('this is Class01 prototype method');
    };
    Class01.prototype.proArray = [1, 2, 3, 4, 5];
    Class01.prototype.proObject = { a:'a' };
    
    /* 静态属性和静态方法
     * 静态属性是否可用于储存该类被实例化的次数,通过在类中加入一个自执行函数即可。
     * 也可以在每次实例化的时候执行某种操作
     * 1、比如当实例化的数量超过某个值的时候,抛出错误,告诉程序内存占用过高。
     * 2、可以在类的静态属性中,保存每个实例的引用(肯定造成内存泄漏)。
     */
    Class01.staticValue = 'this is class static value';
    Class01.staticMethod = function () { console.log('this is class static method') };
    Class01.count = 0;
    Class01.intances = [];
    
    /* 测试 Class01 */
    if (test === "Class01") {
    
        var instance01 = new Class01('private value1', 'public value1');
        var instance02 = new Class01('private value2', 'public value2');
    
        console.log(Class01.intances);
    
        console.log('实例私有属性');
        console.log(instance01.get());
        console.log(instance01.set('change private value1').get());
        console.log(instance02.get());
        console.log(instance02.set('change private value2').get());
    
        console.log('实例属性');
        console.log(instance01.public);
        console.log(instance02.public);
    
        console.log('实例方法');
        instance01.publicMethod();
        instance02.publicMethod();
        console.log(instance01.publicMethod === instance02.publicMethod);
    
        console.log('实例原型属性');
        console.log(instance01.proValue);
        instance01.proValue = 'instance01 change proto value';
        console.log(instance01.proValue);
        console.log(instance02.proValue);
        /*instance01并没有能够修改原型属性,而是在实例上创建了实例属性*/
    
        try {
            /*无法在实例上改变原型上的属性*/
            instance01.prototype.proValue = 'class static value changed';
        } catch (e) {
            console.error(e);
        }
    
        try {
            /*总之实例不允许使用prototype来使用属性和方法*/
            console.log(instance02.prototype.proValue);
        } catch (e) {
            console.error(e);
        }
    
        /*若原型属性是数值/字符串/布尔值,实例是没有手段可以修改。当原型属性是引用时(数值/对象)时,便可以修改从而在所有的实例对象上会反应出来。*/
        console.log(instance01.proArray);
        instance01.proArray.push(6);
        console.log(instance02.proArray);
    
        console.log('类静态方法');
        instance01.callClassStaticMethod();
        instance02.callClassStaticMethod();
    
        try {
            /*不能在实例上设置 prototype 方法(原因很简单,十几个人做一个项目,每个人都想往实例原型上添加方法,项目则无法完成)*/
            instance01.prototype.print = function () {
                console.log('prototype');
            };
        } catch (e) {
            console.error(e);
        }
        try {
            /*尽管 Class01 是 function 但是并不能执行*/
            Class01();
        } catch (e) {
            console.error(e);
        }
    
        try {
            /*显然也不能采用 call 的方式。*/
            var instance03 = {};
            Class01.call(instance03, 'private value3', 'public value3');
        } catch (e) {
            console.error(e);
        }
    
        /*以下这种方法,能够使用 Class01 进行函数式"实例化",但是原型都消失了。*/
        function Class01_t() {
        }
    
        Class01_t.prototype.constructor = {name: 'Class01'};
        var instance04 = new Class01_t();
        Class01.call(instance04, 'private value4', 'public value4');
        console.log(instance04);
    
        /* 下面这种方法能够完美模拟 Class01 实例化
         * 1、以下例子可以看出,在Class01_t2中,可以添加实例新的属性和方法。
         * 下面从继承的角度去看。
         * 2、Class01_t2中定义的属性和方法,显然会被 Class01中的覆盖掉。
         * 3、在Class01_t2原型上添加方法和属性,显然会覆盖Class01的。从而影响所有的由Class01创建的实例
         * 4、无论如何,Class01静态方法和属性都在constructor中
         * 目前的主题并不是类的继承,关于function类的实例化和相关知识目前先介绍这么多。
         */
        function Class01_t2() {
            console.log('Class01_t2 was called');
            Class01.call(this, 'private value5', 'public value5');
            /* 从此处开始可以劫持Class01的公有属性和方法,无法劫持私有的属性和方法(无法取得其引用,自然无法调用)。
             * 使用 Function.prototype.after 的方式可以实现劫持各种方法。
             */
        }
    
        Class01_t2.prototype = Class01.prototype;
        var instance05 = new Class01_t2();
        console.log(instance05);
        instance05.constructor.staticMethod();
        console.log(instance05.constructor === Class01);
        /*构造函数指向 Class01;*/
    
        console.log(instance05.prototype);
        /*undefined*/
        console.log(instance04.prototype);
        /*undefined*/
        console.log(instance01.prototype);
        /*undefined*/
        console.log(Class01_t2.constructor === Class01.constructor);
        /*构造函数相等*/
        console.log(Class01_t2.__proto__ === Class01.__proto__);
        /*true*/
        console.log(instance05.__proto__ === instance01.__proto__);
        /*true*/
        console.log(instance05.constructor.name);
        /*Class01*/
        /*通过实例的 constructor 可以找到类。可以通过new constructor 从而可以从类实例化。*/
        console.log(instance05.__proto__.constructor === Class01);
        /*true*/
        console.log(instance05.constructor === Class01);
        /*true*/
    
        var instance06 = new instance05.constructor('private value6', 'public value6');
        console.log(instance06.get());
    
        /* 总结
         * 1、只有函数才能被实例化,实例化之后得到的变量是实例并不是函数,或者说是object
         * 2、有一种可以不修改 Class01 也可以扩充变量或方法(公有或私有)的方式,上述 Class01_t2
         * 对于这种方式,由相当多的内容可以想象:比如是否可以劫持Class01中的公有方法
         */
    }
    
    
  • 相关阅读:
    VC++SDK编程——字体及位置示例
    VC2008以资源形式实现多语言版本(非Unicode) .转
    跟着编程之美学算法——最长递增子序列(转)
    跟着编程之美学算法——最长公共子序列
    MFC的多国语言界面的实现
    随意输入N个英文字符,找出其中最长连续的排列。
    C++读写EXCEL文件方式比较 .
    操作EXCEL和符号分隔文本的类CSpreadSheet .
    每个程序员都必读的12篇文章
    VC项目配置详解
  • 原文地址:https://www.cnblogs.com/ndos/p/8120073.html
Copyright © 2011-2022 走看看