JavaScript设计模式基础-----封装、继承、多态

// 函数的基本形式
function checkName() {
    "use strict";

}
function checkEmail() {
    "use strict";

}
function checkPassword() {
    "use strict";

}

// 函数的另一种形式
var checkName = function () {
    "use strict";

}
var checkEmail = function () {
    "use strict";

}
var checkPassword = function () {
    "use strict";

}

// 上面两种等于声明了全局变量
// 这个从功能上讲是没有问题的,但是如果别人也定义了同样的方法就会覆盖掉这个函数

/*
 * 用对象收编变量
 * */
var CheckObject = {
    checkName: function () {
        "use strict";

    },
    checkEmail: function () {
        "use strict";

    },
    checkPassword: function () {
        "use strict";

    }
}

// 将所有的函数作为checkObject的方法,这样就只有一个对象 用法:CheckObject.checkName()

/*
 * 对象的另一种形式
 * */
var CheckObject = function () {

}
CheckObject.checkName = function () {
    "use strict";

}
CheckObject.checkEmail = function () {
    "use strict";

}
CheckObject.checkPassword = function () {
    "use strict";

}
//用法:CheckObject.checkName()  不好处就是比人不能复制你的代码,这个对象在用new关键字创建新对象的时候新创建的对象是不能继承这些方法的

/*
 * 实现简单复制
 * */
var CheckObject = function () {
    "use strict";
    return {
        checkName: function () {
            "use strict";

        },
        checkEmail: function () {
            "use strict";

        },
        checkPassword: function () {
            "use strict";

        }
    }
}
// 这样每个人用的时候都是返回一个新对象 通过new 实例化的时候 互不影响
// 用法:var a= CheckObject(); a.checkName();

/*
 * 用类的写法 每次new的时候新创建的对象都会有一套自己的方法,这样很消耗内存
 * */
var CheckObject = function () {
    "use strict";
    this.checkName = function () {

    }
    this.checkEmail = function () {

    }
    this.checkPassword = function () {

    }
}
// 用法:var a = new CheckObject(); a.checkPassword();

/*
 这个对象创建出来的方法就都是相同的,因为他们都需要一来prototype原型一次查找
 * */
var CheckObject = function () {
    "use strict";

}
CheckObject.prototype.checkName = function () {
    "use strict";

}
CheckObject.prototype.checkEmail = function () {

}
CheckObject.prototype.checkPassword = function () {

}
//简写
var CheckObject = function () {
}
CheckObject.prototype = {
    checkName: function () {
        "use strict";

    },
    checkEmail: function () {
        "use strict";

    },
    checkPassword: function () {
        "use strict";

    }
}
// 用法:var a = new CheckObject(); a.checkName();
// =================== 注意==========================
// 这两种方法不能一起用 一起用的话 后面的prototype 方法会覆盖前面的

var CheckObject = {
    checkName: function () {
        "use strict";
        return this;
    },
    checkEmail: function () {
        "use strict";
        return this;
    },
    checkPassword: function () {
        "use strict";
        return this;
    }
}
// 链式调用
// CheckObject.checkName().checkEmail();
// 也可以放到原型中
var CheckObject = function () {
    "use strict";

}
CheckObject.prototype = {
    checkName: function () {
        "use strict";
        return this;

    },
    checkEmail: function () {
        "use strict";
        return this;

    },
    checkPassword: function () {
        "use strict";
        return this;
    }
}
// 用法:var a = new CheckObject(); a.checkName().checkEmail();

/*
 为函数的原型添加方法
 * */
Function.prototype.addMethod = function (name, fn) {
    this[name] = fn; // 如果要添加到prototype上 使用的时候要使用new 关键字 this.prototype[name]=fn; 使用的时候要使用new
    return this;
}
var methods = new function ();
methods.addMethod('checkName', function () {
    // 如果要链式调用 返回this

}).addMethod('checkEmail', function () {

});
methods.chekcName();

// ============================ 面向对象 ============================ //

// 创建一个类
var Book = function (id, bookname, price) {
    this.id = id;
    this.bookname = bookname;
    this.price = price;
}
// 为类添加方法
Book.prototype = {
    display: function () {

    }
}

// 封装
var Book = function (id, name, price) {
    // 私有属性 相当于php private 定义的方法
    var num = 1;
    // 私有方法
    function checkId() {

    }

    // 特权方法  相当于php为变量设置和获取值的方法
    this.getName = function () {

    }
    this.setName = function () {

    }
    this.getPrice = function () {

    }
    this.setPrice = function () {

    }

    // 公有属性 相当于php的public定义的属性和方法 【这相当于css的style 优先级要比prototype的高】
    this.id = id;
    // 公有方法
    this.copy = function () {

    }

    // 构造器 相当于php的__construct
    this.setName(name);
    this.setPrice(price);
}
// 类外部通过 . 语法定义的属性和方法 称为 静态公有属性和方法 但是对象不能访问 相当于php static 定义的属性和方法 只能通过类名.属性、方法访问
Book.isChinese = true;
Book.resetTime = function () {
    console.log('new time')
}
// 通过prototype定义的属性和方法称为公有属性和方法
Book.prototype = {
    // 公有属性
    isJsBook: false,
    // 公有方法
    display: function () {

    }
}
// 用法 : var b= new Book(11,'JavaScript设计模式',50);

/*
 * 升级版本的封装 function 对象的
 * */

function Person(info) {
    this._init_(info)
}
Person.prototype = {
    constructor: Person,
    _init_: function (info) {
        this.name = info.name;
        this.age = info.age;
        this.sex = info.sex;
    },
    sayHello: function () {
        console.log('hello');
    }
}

/*
 * 升级版本2  仿照jquery
 * */
var Person = (function (window) {
    var Person = function (name) {
        // 直接实例化
        return new Person.fn.init(name);
    }

    Person.fn = Person.prototype = {
        constructor: Person,
        init: function (name) {
            this.name = name;
            this.sayHello = function () {
                this.makeArray();
            }
        },
        makeArray: function () {
            console.log(this.name);
        }
    }

    Person.fn.init.prototype = Person.fn;

    return Person;
})();
/*
 var p = Person('pawn');
 console.log(p);
 p.sayHello();
 */

每个类都有三部分组成
1.
构造函数内部的这是供实例化对象复制用的
2.
构造函数外部的直接通关.语法添加的
只是类使用的
只有类.才可以访问
3.
添加在prototype中的
实例化对象时可以通过原型直接访问到
是给所有实例化对象所共用的

/*
 * 继承 http://www.cnblogs.com/humin/p/4556820.html
 * */
// 定义一个动物类
function Animal(name) {
    // 属性
    this.name = name || 'Animal';
    // 实例方法
    this.sleep = function () {
        console.log(this.name + '正在睡觉!');
    }
}
// 原型方法
Animal.prototype.eat = function (food) {
    console.log(this.name + '正在吃:' + food);
};

//1、原型链继承
//核心: 将父类的实例作为子类的原型

function Cat() {
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
//instanceof主要的目的是检测引用类型
//typeof 是一个操作符,主要的目的是检测一个变量是不是基本数据类型的变量
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true

/*特点:

 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
 父类新增原型方法/原型属性,子类都能访问到
 简单,易于实现

 缺点:

 要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
 无法实现多继承
 来自原型对象的引用属性是所有实例共享的(详细请看附录代码: 示例1)
 创建子类实例时,无法向父类构造函数传参
 推荐指数:★★(3、4两大致命缺陷)*/

//2、构造继承
//核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Cat(name) {
    "use strict";
    Animal.call(this);
    this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

/*特点:

 解决了1中,子类实例共享父类引用属性的问题
 创建子类实例时,可以向父类传递参数
 可以实现多继承(call多个父类对象)
 缺点:

 实例并不是父类的实例,只是子类的实例
 只能继承父类的实例属性和方法,不能继承原型属性/方法
 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
 推荐指数:★★(缺点3)*/

//3、实例继承
//核心:为父类实例添加新特性,作为子类实例返回
function Cat(name) {
    "use strict";
    var instance = new Animal();
    instance.name = name || 'Tom';
    return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
/*
 特点:

 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
 缺点:

 实例是父类的实例,不是子类的实例
 不支持多继承
 推荐指数:★★*/


//4、拷贝继承

function Cat(name) {
    var animal = new Animal();
    for (var p in animal) {
        Cat.prototype[p] = animal[p];
    }
    Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
/*特点:

 支持多继承
 缺点:

 效率较低,内存占用高(因为要拷贝父类的属性)
 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
 推荐指数:★(缺点1)*/

/*
 5、组合继承

 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
 */

function Cat(name) {
    Animal.call(this);
    this.name = name || 'Tom';
}
Cat.prototype = new Animal();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
/*特点:

 弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
 既是子类的实例,也是父类的实例
 不存在引用属性共享问题
 可传参
 函数可复用
 缺点:

 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
 推荐指数:★★★★(仅仅多消耗了一点内存)*/

/*
 6、寄生组合继承

 核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
 */

function Cat(name) {
    Animal.call(this);
    this.name = name || 'Tom';
}
(function () {
    // 创建一个没有实例方法的类 在js 中 继承是依赖于原型prototype链实现的
    var Super = function () {
    };
    Super.prototype = Animal.prototype;
    //将实例作为子类的原型
    Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
/*
 特点:

 堪称完美
 缺点:

 实现较为复杂
 推荐指数:★★★★(实现复杂,扣掉一颗星)
 */

//=============================================javascript 多继承========================================================
// 在JavaScript中继承是一来与prototype链实现的。因为只有一条原型链。理论上是不能继承多个父类,但是js是很灵活的。通过一些
//技巧和方法可以实现多继承
/**
 * 作用就是将传入的多个对象的属性复制到源对象中 这样就可以实现对多个对象属性的继承
 * 使用的时候第一个参数----需要传入要继承的对象
 * @returns {*}
 */
var mix = function () {
    var i = 1,// 从第一个参数起为被继承的对象
        len = arguments.length,// 获取参数长度
        target = arguments[0],// 第一个对象为目标对象
        arg;// 缓存参数对象
    for (; i < len; i++) {
        // 缓存当前对象
        arg = arguments[i];
        // 遍历被继承对象中的属性
        for (var property in arg) {
            // 将被继承对象中的属性复制的目标对象中
            target[property] = arg[property];
        }
    }
    return target;
};

Object.prototype.mix = function () {
    var i = 0, // 从第一个参数起为被继承的对象
        len = arguments.length, // 获取参数长度
        arg;// 缓存参数对象
    // 遍历被继承的对象
    for (; i < len; i++) {
        // 缓存当前对象
        arg = arguments[i];
        // 遍历被继承对象中的属性
        for (var property in arg) {
            // 将被继承对象中的属性复制的目标对象中
            this[property] = arg[property];
        }
    }
};

var book1 = {
    name: 'book1',
    alike: ['css', 'js', 'java']
};
var book3 = {
    names: 'book1',
    alikes: ['css', 'js', 'java']
};
var book2 = {
    ccc: 'ccccccc'
};
var outhorBook = {
    color: 'red'
};
outhorBook.mix(book1, book2, book3);
console.log(outhorBook);

/*
 * ============================================= 多态 =============================================
 * 指的是同一种方法多种调用方式
 * */
function add() {
    // 获取参数
    var arg = arguments,
    // 获取长度
        len = arg.length;
    switch (len) {
        // 如果没有传参数
        case 0:
            return 10;
        case 1:
            return 10 + arg[0];
        case 2:
            return arg[0] + arg[1];
    }
}
console.log(add()); // 10
console.log(add(5)); // 15
console.log(add(6, 7)); // 13

// or
function Add() {
    function zero() {
        return 10;
    }

    function one(num) {
        return 10 + num;
    }

    function two(num1, num2) {
        return num1 + num2;
    }

    // 相加共有方法
    this.add = function () {
        var arg = arguments,
            len = arg.length;
        switch (len) {
            case 0:
                return zero();
            case 1:
                return one(arg[0]);
            case 2:
                return two(arg[0], arg[1])
        }
    }
}
var a = new Add();
console.log(a.add());
console.log(a.add(5));
console.log(a.add(6, 7));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值