设计模式学习(一)--面向对象

1.面向对象和面向过程
小白想要验证用户名、邮箱、密码等

function checkName(){
//验证姓名
}
function checkEmail(){
//验证邮箱
}
function checkPassword(){
//验证密码
}

像这种实现方式,添加了很多全局变量且不利于复用,是面向过程的。
面向对象就是把需求抽象成一个对象,分析其属性与方法,这个对象称作类。
2.面向对象--封装
创建一个,通过this添加属性和方法,也就是构造函数的方式。

var Book=function(id,name,price){
    this.id=id;
    this.name=name;
    this.price=price;
}

也可容易通过在类的原型上添加属性和方法,以下两种方法不能混用

Book.prototype.display=function(){
//展示书
}

或者

Book.prototype={
display:function(){
//展示书
}
}

通过this添加属性和方法和在prototype中添加的区别:
构造函数:每用new创建一次对象实例,都对类的this上的属性复制,新创建的对象都会有自己的一套复制的方法,造成了资源的浪费。
原型扩展创建对象实例,都会通过prototype原型寻找,找到的方法都是同一个,都绑定在Book上面。

3.属性和方法封装--公有和私有

var Book=function(id,name,price){
    //私有变量
    var num=1;
    //私有方法
    function checkID(){};
    //公共属性
    this.id=id;
    //公共方法
    this.getName=function(){console.log(name)};
    //特权方法
    this.setPrice=function(){};
    //构造器
    this.setPrice(price)
}
//类静态公有属性
Book.isChinese=true;

Book.prototype={
    //公有属性
    isJSBook:false
}
var b=new Book(10,'设计模式',20);
console.log(b.num); //undefined
console.log(b.isChinese);//undefined
console.log(b.isJSBook);//false
b.getName();//设计模式

通过以上例子,私有变量和方法外部是访问不到的。通过this创建的属性和方法是公有的。通过this创建的方法不但可以访问公有的还可以访问私有的变量和方法,权力比较大,又称作特权方法。在创建对象时调用的特权方法看作为类的构造器。

4.闭包
将闭包作为创建对象的构造函数,这样看起来更像是一个整体

var Book = (function() {
    //静态私有变量
    var bookNum = 0;
    //静态私有方法
    function checkBook(name) {};
    //创建类
    function _book(newId, newName, newPrice) {
        //私有变量
        var name, price;
        //私有方法
        function checkId(newId){};
        //特权方法
        this.getName = function(){};
        this.getPrice = function(){};
        this.setName = function(name){console.log(name)};
        //公有变量
        this.id = newId;
        //公有方法
        this.copy = function(){};
        //构造器
        this.setName(newName);
    }
    //构建原型
    _book.prototype = {
        //静态共有属性
        isJsBook: false,
        //静态公有方法
        display: function(){}
    }
    //
    return _book;
})()

5.创建对象的安全模式
避免忘记用new创建对象发生的问题

var Book = function(newId, newName, newPrice) {
    this.id = newId;
    this.name = newName;
    this.price = newPrice;
}
var newBook = Book(123,"dfg",444); 
console.log(newBook); //undefined

window.id //123

如果忘记用new来实例化,就相当于执行了这个函数,当前的this指向的是window。
解决方法

var Book = function(newId, newName, newPrice) {
    //判断this指向
    if(this instanceof Book){
        this.id = newId;
        this.name = newName;
        this.price = newPrice;
    }else{
        return new Book(newId, newName, newPrice);
    }
}

6.继承
1.类式继承

//声明父类
function ParentClass() {
    this.parentValue = true;
        this.obj = ["123","234"];
}
//父类添加公有方法
ParentClass.prototype.getParentValue = function() {
    return this.parentValue;
}
//声明子类
function ChildClass() {
    this.childValue = false;
}
//继承父类,子类的原型被赋予父类的实例
ChildClass.prototype = new ParentClass();
//ChildClass = new ParentClass(); //这样肯定不对,人家会问ChildClass是个什么东西?
var instance = new ChildClass();
console.log(instance.getParentValue()); //true

但是为什么要赋值给子类的原型上?
因为子类是不能直接访问父类的属性和方法的,所以需要通过prototype来访问。
用来检测是否属于一个类instanceof

console.log(instance instanceof ChildClass);//true
console.log(instance instanceof ParentClass);//true
console.log(ChildClass instanceof ParentClass);//false
console.log(ChildClass.prototype instanceof ParentClass);//true

缺点:所有的子实例共用一个父类引用类型,如果一个子类实例更改了父类构造函数中继承的公有属性会影响其他子类;在创建父类的时候,不能向父类传递参数,在实例化父类的时候也不能对父类构造函数内的属性初始化。

引用类型和基本类型
基本类型:Underfined ,Null, Boolean,Number,String ,在内存中占有固定大小的空间,值保存在栈空间中,按值访问。
引用类型:Object,Array,Date,Function ,值的大小不固定,栈内存中存放地址指向堆内存中的对象,是按引用访问的。当查询引用类型的变量时,先从栈中读取内存地址,然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。类似于指针但是跟指针不是同一个东西。

//再实例化一个子类
var instance1 = new ChildClass();
instance.parentValue  = false;
console.log(instance1.parentValue);//true,因为改变的并不是引用类型的属性
instance.obj.push("345");
console.log(instance1.parentValue);// ["123", "234", "345"]

2.构造函数继承
用call()的方法改变this指向,子类实例之间不会相互影响,但是违背代码复用原则

//声明父类
function ParentClass(id) {
    this.id = id;
    this.obj = ["123","234"];
}
//声明子类
function ChildClass(id) {
    ParentClass.call(this,id);
}
var instance = new ChildClass(1);
var instance1 = new ChildClass(2);
instance.obj.push("345");
console.log(instance.obj); //["123", "234", "345"]
console.log(instance1.obj); //["123", "234"]
console.log(instance.id); //1
console.log(instance1.id); //2

3.组合继承
将类式继承和构造函数继承结合起来,但是调用了两次父类构造函数。

//声明父类
function ParentClass(id) {
    this.id = id;
    this.obj = ["123","234"];
}
//声明子类
function ChildClass(id) {
    ParentClass.call(this,id);
}
ChildClass.prototype = new ParentClass()
var instance = new ChildClass(1);
var instance1 = new ChildClass(2);
instance.obj.push("345");
console.log(instance.obj);//["123", "234", "345"]
console.log(instance1.obj);//["123", "234"]
console.log(instance.id);//1
console.log(instance1.id);//2

4.原型式继承

function inheritObj(obj) {
    //过渡函数,相当于子类
    function F(){}
    //过渡函数原型继承父类对象
    F.prototype = obj ;
    //返回过渡函数实例
    return new F();
}

var obj = {"name":"zhangsan", "book":["css","js"]}
var Book1 = inheritObj(obj);
Book1.name = "Derek";
Book1.book.push("html");
var Book2 = inheritObj(obj); 
console.log(Book1.name);//Derek
console.log(Book1.book);//["css", "js", "html"]
console.log(Book2.name);//zhangsan
console.log(Book2.book);//["css", "js", "html"]

是类式继承的封装,有同样的问题,值类型的属性被复制,引用类型的属性被共用
5.寄生继承
二次封装原型继承
6.寄生组合继承

参考:《Javascript设计模式》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容