资讯专栏INFORMATION COLUMN

<笔记>面向对象的设计模式

warkiz / 2938人阅读

摘要:创建对象什么是工厂模式封装一个函数用来创建对象并给对象中特定的属性添加值优点是可以循环调用缺点是每一个创建出来的对象都是独立的不能确定它是哪个类型的对象或者说是想要将哪个对象作为模板进行创建每个对象都是独立的并且指向的不能辨别基于哪个对象为

创建对象 什么是工厂模式 ?

封装一个函数 , 用来创建对象并给对象中特定的属性添加值 , 优点是可以循环调用 , 缺点是每一个创建出来的对象都是独立的 , 不能确定它是哪个类型的对象 ( 或者说是想要将哪个对象作为模板进行创建 )

function func(name, age) {
    var o = {
        "name" : name,
        "age" : age
    };
    return o;
}
var person = func("oswald", 24);
var person2 = func("oswald", 24);
// {name: "oswald", age: 24}
console.log(person === person2);
// false
console.log(person.__proto__ === Object.prototype);     // true
console.log(person2.__proto__ === Object.prototype);    // true
// 每个对象都是独立的并且指向 Object.prototype 的 , 不能辨别基于哪个对象为原型
什么是构造函数模式 构造函数模式和工厂模式的区别

构造函数模式就是通过构造函数来创建自定义类型的对象 , 创建出来的对象都指向了同一个构造函数的 prototype , 解决了工厂模式中不能识别对象模板的问题

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name);
    };
    /*  没有显式的创建对象
        用 this 代替新对象
        没有 return 语句    */
}
var person1 = new Person("oswald", 24);
console.log(person1);    // {name: "oswald", age: 24}
console.log(person1.__proto__ === Person.prototype);    // true
// person1 指向了 构造函数 func.prototype
console.log(person1 instanceof Person);     // true
// person1 对象是构造函数 Person ( 也可以叫做 Person 类型 ) 的实例
console.log(person1 instanceof Object);     // true
// person1 对象也是 Object 类型的实例 
构造函数模式的缺点

但是 , 上面的构造函数模式也不是没有缺点的 : 单纯的构造函数模式创建对象的时候 , 对象中每个方法都会在实例对象上重新创建一次 , 也就是说每次都会创建一个看起来相同但是完全不是一个"方法"的方法

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name);
    };
}
var person1 = new Person("oswald", 24);
var person2 = new Person("oswald", 24);
console.log(person1.sayName = person2.sayName);     // false
// 每次创建对象的时候 , 都会生成一个功能一样但是是不同 Function 实例的方法
什么是原型模式

每个函数在创建的时候都会有一个 prototype 属性 , 这个属性指向一个对象

所有以这个函数为构造函数创建的实例对象 , 都会连接到构造函数的 prototype 属性指向的这个对象上 , 并且可以访问这个对象的所有属性和方法 , 这个对象就叫做原型对象

原型对象在创建的时候自带一个不可枚举的 constructor 属性 , 指向构造函数

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
    Person.prototype.sayName = function(){
        console.log(this.name);
    };
}

var person1 = new Person();
console.log(person1);
// {} 得到一个空对象 , 因为创建的属性和方法都在实例的原型对象上
console.log(Person.prototype);
// {name: "oswald", age: 24, sayName: f(...)}
console.log(person1.name);
// oswald 得到一个名字 , 因为实例对象可以从它的原型对象上查找属性和方法

var person2 = new Person();
console.log(person2.sayName === person1.sayName);   // true
// person1 和 person2 访问的 sayName 方法都是原型对象上的方法 , 不是它们自身的 , 这样就解决了构造函数模式多次创建方法实例的缺点
原型对象中的属性和方法会和实例对象自有的冲突吗

如果当前实例对象中已经有了想要查找的属性和方法 , 会直接使用实例对象的属性和方法 , 如果没有才去原型对象中查找

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
console.log(person1.name);  // oswald
person1.name = "yin";
console.log(person1.name);  // yin
实例对象怎么访问原型对象

在火狐、谷歌等浏览器中提供了一个 __proto__ 的属性 , 可以访问它的原型对象

ECMAScript 5 中提供了 Object.getPrototypeOf( ) 方法可以检测并返回它的原型对象

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype);
// true
console.log(Object.getPrototypeOf(person1) === Person.prototype);
// true
原型对象和原型属性有什么区别

实例对象 ( person1 ) 的原型对象 ( __proto__ ) 是创建当前对象的构造函数 ( Person ) 的原型属性 ( prototype ) , 个人用来区别访问途径 , 便于理解

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype);
// true

实例对象可以查找它的原型对象 , 但是不能查找它自己的原型属性

function Person(){
}
var person1 = new Person();
person1.prototype = {
    name: "yin",
    age: 23
}
console.log(person1.name);  // undefined
怎么检测属性或者方法在实例对象中是否存在

使用继承自 Object 对象的 hasOwnProperty( ) 方法可以检车要查找的属性或方法是否来自实例对象而不是实例对象的原型对象

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
console.log(person1.name);  // oswald
console.log(person1.hasOwnProperty("name"));
// false 当前查找到的 name 属性来自原型对象
person1.name = "yin";
console.log(person1.name);  // yin
console.log(person1.hasOwnProperty("name"));
// true 当前查找到的 name 属性来自实例对象
枚举对象中的属性和方法有哪些方法

for - in 遍历 , 会将当前对象和当前对象的原型对象上所有可以枚举的属性和方法都返回

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
person1.color = "red";
for( poop in person1 ){
    console.log(poop);
    // color, name, age
}

ECMAScript 5 的 Object.key( ) 方法 , 遍历当前对象的可枚举属性和方法 , 不会去找原型对象

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
person1.color = "red";
var p1keys = Object.key(person1);
console.log(p1keys);    // color

Object.getOwnPropertyNames( ) 方法 , 遍历当前对象的所有属性和方法 , 包括不可枚举的 , 不会去找原型对象

function Person(){
    Person.prototype.name = "oswald";
    Person.prototype.age = 24;
}
var person1 = new Person();
person1.color = "red";
var p1keys = Object.getOwnPropertyNames(person1);
console.log(p1keys);
// color
var Ppkeys = Object.getOwnPropertyNames(Person.prototype);
console.log(Ppkeys);
// constructor、name、age
原型模式创建对象的缺点

原型中的所有属性和方法都是共享的 , 如果有多个实例 , 通过其中一个实例改变原型对象中的属性和方法 , 其他实例访问的属性会跟着改变

组合使用构造函数模式和原型模式

将对象的私有属性和方法通过构造函数模式创建 , 将对象的公共属性和方法通过原型模式创建

function Person(name,age){
    /* 私有属性 */
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function(){
    /* 公共方法 */
    console.log(this.name);
}
var person1 = new Person("oswald", 24);
person1.sayName();  // oswald
继承 什么是原型链

原型链就是连接实例对象和原型对象的链接

/* 一般函数的原型链 */
function func(){
    console.log(123);
}

console.log(func.__proto__);    // Function.prototype
// func 函数是 Function 构造函数的实例对象
console.log(func.__proto__.__proto__);  // Object.prototype
// func 函数的原型对象是 Object 构造函数的实例对象
console.log(func.__proto__.__proto__.proto__);  // null
// 这里就是原型链的头了 , 所有原型链查到 Object.prototype 再往上就会返回 null

/* 一般构造函数的原型链 */
function Obj(){
    Func.prototype.name = "oswald";
}
var obj = new Obj();
console.log(obj);    // {}
console.log(obj.name);    // oswald
// obj 对象通过原型链查找到了 name 属性
console.log(Obj.__proto__);    // Obj.prototype
// obj 对象是 Obj 构造函数的实例对象
console.log(Obj.__proto__.__proto__);    // Object.prototype
// obj 对象的原型对象是 Object 构造函数的实例
console.log(Obj.__proto__.__proto__.__proto__);    // null
// 到头了
原型链继承

原型链继承的原理就是实例对象可以访问原型对象的属性和方法 , 并通过原型链向上查找

function Oswald(){
    this.color = "red";
    Oswald.prototype.sayName = function(){
        console.log(this.name)
    };
}
var oswald = new Oswald();

function Yin(name, age){
    this.name = name;
    this.age = age;
    Yin.prototype.sayAge = function(){
        console.log(this.age);
    }
}
Yin.prototype = oswald;
/*
原型链继承的核心 , 把父类型 ( Oswald ) 的实例对象 ( oswald )
设置为子类型 ( Yin ) 的原型属性 ( Yin.prototype )
*/

var yin = new Yin("oswald", 24);
// 必须要先继承再创建实例 , 否则会出现 Yin.prototype != yin.__proto__ 的情况

yin.sayName();    // oswald  继承了 Oswald 类型原型上的方法
yin.sayAge();     // 24      继承了 Yin 类型原型上的方法
借用构造函数式继承

我们之前讨论的原型链继承 , 不能在创建子类型的实例对象的时候 , 给父类型的构造函数传递参数 , 如果要给父类型的构造函数传递参数 , 就会影响所有的子类型实例对象

如果我们想要解决这个问题 , 可以借调父类型的构造函数 , 在新创建的对象上执行构造函数

function Oswald(color){
    this.color = color;
    this.sayName = function(){
        console.log(this.name)
    };
}

function Yin(name, age, color){
    Oswald.call(this, color);
    // 在 Yin 构造函数创建的新对象中调用 Oswald 函数
    this.name = name;
    this.age = age;
}

var yin = new Yin("yin", 24, "red");

yin.sayName();      // yin
组合式继承

但是借用构造函数继承只能够继承父类型自己的属性和方法 , 不能继承原型链上 , 这个时候我们可以使用原型链和借用构造函数的组合式继承 , 但是这个方法会调用两次父类型构造函数

function Super(color){
    this.color = color;
    // 自己的属性
    Super.prototype.sayName = function(){
        console.log(this.name)
    };
    // 原型链上的方法
}

function Sub(name, age, color){
    Super.call(this, color);        // 第二次调用 Super , 被当做普通函数调用
    // 继承 Super 构造函数自己的属性和方法
    this.name = name;
    this.age = age;
}
Sub.prototype = new Super();        // 第一次调用 Super , 被当做构造函数调用
// 继承 Super 原型链上的属性和方法
var yin = new Sub("yin", 24, "red");

yin.sayName();      // yin
原型式继承

ES 5 中使用 Object.create( o ) 方法规范了原型式继承 , 这个方法会返回一个新对象 , 新对象的原型对象指向传入的参数对象 o

function obj(o){    // Object.create( ) 方法的原理
    function F(){};
    F.prototype = o;
    return new F();
}
var person = {
    name: "oswald",
    color: ["red"]
}

var person1 = obj(person);
var person2 = Object.create(person);

console.log(person1 === person2);   // false
console.log(person1.__proto__ === person2.__proto__);   // true
寄生组合式继承

目前最优的继承模式

function Super(color){
    this.color = color;
    Super.prototype.sayName = function(){
        console.log(this.name);
    }
}
function Sub(name, color){
    Super.call(this, color);
    // 借调 Super 构造函数继承实例属性
    this.name = name;
}

var F = Object.create(Super.prototype);
F.constructor = Sub;
Sub.prototype = F;


var yin = new Sub("oswald","red");

yin.sayName();      // oswald

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108272.html

相关文章

  • &lt;&lt;深入PHP面向对象模式与实践&gt;&gt;读书笔记:面向对象设计和过程式编程

    摘要:注本文内容来深入面向对象模式与实践中节。面向对象设计与过程式编程面向对象设计和过程式编程有什么不同呢可能有些人认为最大的不同在于面向对象编程中包含对象。面向对象编程和过程式编程的一个核心区别是如何分配职责。 注:本文内容来中6.2节。 6.2 面向对象设计与过程式编程   面向对象设计和过程式编程有什么不同呢?可能有些人认为最大的不同在于面向对象编程中包含对象。事实上,这种说法不准确。...

    xiao7cn 评论0 收藏0
  • Python超细腻研究面向对象设计

      面向对象设计是一类编程方式,此编程方式的落地式需要使用类和目标来达到,因此,面向对象设计本身就是对类和目标的应用,今日给大家介绍一下python面向对象设计开发设计及本质特征,感兴趣的小伙伴一起了解一下吧  序言  面向对象设计对新手而言不难理解但无法运用,尽管我们给大家汇总过面向对象战略部署方式(定义类、创建对象、给目标发信息),可是看似简单其实不简单。大量程序编写训练与阅读高质量的编码有可...

    89542767 评论0 收藏0
  • Python面向对象三大特性封装、继承、多态

      小编写这篇文章的主要目的,主要是来给大家介绍关于Python的一些事情,主要还是涉及到面对面对象编程的一些实例,其中,主要涉及到的内容涵盖封装、继承、多态等多种形式,就具体的形式,下面就给大家详细解答下。  Python是一门面向对象的语言。面向对象都有三大特性:封装、继承、多态。  下面分别来说说这三大特性:  1、封装  隐藏对象的属性和实现细节,仅对外提供公共访问方式。在python中用...

    89542767 评论0 收藏0
  • python命令 – 解释器、交互式、面向对象编程语言

    Python 是一种解释型的、交互式的、面向对象的编程语言,它结合了非凡的功能和非常清晰的语法。Python Library Reference 记录了内置的和标准的类型、常量、函数和模块。语法格式:python [参数]常用参数:参数 描述-c 直接运行 python 语句-v 会输出每一个模块引用信息-i 运行完 python 脚本文件以后打开一个 python 环境-m 将模块按照脚本执行命...

    社区管理员 评论0 收藏0
  • Python学习笔记

    入坑 Python自从进入公司,到现在也有半年的时间。这半年的时间从 python 到入门到开发了几个小项目,类型涵盖了web应用 程序、爬虫程序 (scrapy),python脚本工具,自动化工具。对 python 语言也越来越熟悉,当然也有所感悟和总结。首先 Python 真的让语言成 了一个工具,入门代价很小,上手能够开发出小工具,可以更快体验到编程的乐趣。但是做到pythonic需要更多的...

    社区管理员 评论0 收藏0

发表评论

0条评论

warkiz

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<