面向对象的程序设计

☞☞ 个人主页欢迎访问 ☜☜

大家好,我是苏日俪格,本文是面向对象的第二部分,纯属个人理解,有哪里不对的地方请在评论区指出,大家一起学习共同进步。

创建对象

在面试中,经常会被问到创建对象都有哪些方式,在创建单个对象的时候通常就用对象字面量,多个对象就用工厂模式、构造函数、原型模式和构造函数原型的混合模式
下面来逐个介绍一下:

  • 对象字面量

栗子如下:

let Person = {
    name: '苏日俪格',
    age: 24,
    job: '前端开发'
}
console.log(Person) // {name: "苏日俪格", age: 24, job: "前端开发"}

优点:通俗易懂,人人都会的一种简单的方法
缺点:只适用于创建单个对象,用同一个接口创建多个对象的话,就会有很多的冗余代码,为了解决这个缺点,我们使用工厂模式

  • 工厂模式

栗子如下:

function createPerson(name, age, job){
    let obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.job = job;
    obj.show = function(){
        console.log(`姓名:${obj.name}, 年龄:${obj.age}, 工作:${obj.job}`);
    }
    return obj;
}
let person1 = createPerson('苏日俪格', 24, '前端开发');
person1.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
let person2 = createPerson('赵云', 27, '救阿斗');
person2.show(); // 姓名:赵云, 年龄:27, 工作:救阿斗

优点:封装了一个函数解决了代码冗余的问题
缺点:无法明确创建的对象的类型,为了解决这个缺点,我们使用构造函数

  • 构造函数

栗子如下:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.show = function(){
        console.log(`姓名:${this.name}, 年龄:${this.age}, 工作:${this.job}`);
    }
}
let person1 = new Person('苏日俪格', 24, '前端开发');
person1.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
let person2 = new Person('赵云', 27, '救阿斗');
person2.show(); // 姓名:赵云, 年龄:27, 工作:救阿斗

和工厂模式的不同之处:

  1. 没有显式的创建对象(new Object())
  2. 没有return
  3. 直接将属性和方法赋给了this对象
  4. Person是一个构造函数,首字母大写(这里注意,由于构造函数和普通函数的区别在于有无返回值,并不是大小写,小写也可以,但是为了语义化也算是行规,必须大写)

优点:由于两个实例共享了show这个全局的方法,就解决了两个函数做一件事的问题
缺点:如果定义了多个全局的函数,那么这个自定义的引用类型就丝毫灭有封装性可言了,而且每个方法都要在每个实例上重新创建一遍,为了解决这个缺点,我们使用原型模式

  • 原型模式

栗子如下:

function Person(){}
Person.prototype.name = '苏日俪格';
Person.prototype.age = 24;
Person.prototype.job = '前端开发';
Person.prototype.show = function(){
    console.log(`姓名:${this.name}, 年龄:${this.age}, 工作:${this.job}`);
}
let person1 = new Person();
person1.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
let person2 = new Person();
person2.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
person2.name = '赵云';
person2.age = 27;
person2.job = '救阿斗';
person2.show(); // 姓名:赵云, 年龄:27, 工作:救阿斗

优点:可以让所有对象的实例共享它所包含的属性和方法,不用再从实例中重新定义信息,直接将信息放在原型对象中
缺点:显而易见,所有实例都是共享的属性,但是实例一般会有自己单独的属性的,这种方法一般不用,那么最后一种就是结合了前面所有的缺点的一种方式,也是最让码农们认同的

这个时候有些人就想了,重复写那么多代码,我们可以简写成这样的啊:

function Person(){}
Person.prototype = {
    name: '苏日俪格',
    age: 24,
    job: '前端开发',
    show: function(){
        console.log(`姓名:${this.name}, 年龄:${this.age}, 工作:${this.job}`);
    }
}
let person1 = new Person();
person1.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
let person2 = new Person();
person2.show(); // 姓名:苏日俪格, 年龄:24, 工作:前端开发
person2.name = '赵云';
person2.age = 27;
person2.job = '救阿斗';
person2.show(); // 姓名:赵云, 年龄:27, 工作:救阿斗

上面折中写法确实清晰了许多,但是这个是在原型模式的情况下,把构造函数的原型等于了以对象字面量的形式创建的对象,这个时候constructor属性就不再指向Person了,为了证实这一点来看一个小东西instanceof

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

这句话是什么意思呢?
来看一个语法:object instanceof constructor
就是用instanceof来检测一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上,即左侧的对象是右侧类的实例
字面理解: constructor.prototype 是否存在于object 的原型链上
在上面加上这四行代码:

console.log(person1 instanceof Person)  // true
console.log(person1 instanceof Object)  // true
console.log(person1.constructor == Person)  // false
console.log(person1.constructor == Object)  // true

很明显,我们要的效果出来了,实例的构造函数已经由Person指向了Object,这个时候需要在代码里加上constructor的指向

Person.prototype = {
    constructor: Person,
    name: '苏日俪格',
    age: 24,
    job: '前端开发',
    show: function(){
        console.log(`姓名:${this.name}, 年龄:${this.age}, 工作:${this.job}`);
    }
}
  • 构造函数原型的混合模式

栗子如下:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype = {
    constructor: Person,
    show: function(){
        console.log(`姓名:${this.name}, 年龄:${this.age}, 工作:${this.job}`);
    }
};
let person1 = new Person('苏日俪格', 24, '前端开发');
person1.show();
let person2 = new Person('赵云', 27, '救阿斗');
person2.show();

console.log(person1.name == person2.name)   // false
console.log(person1.show == person2.show)   // true

做了个实验,看看两个实例到底是怎样的,共享的方法得到了验证,两者的属性并不是共享的,因为在创建实例的同时,系统开辟了单独的内存给它,每个实例也都会给自己的属性创建一个副本,所以他们之前是互不影响的

优点:可以通过构造函数模式来定义实例所需要的属性,用原型来定义实例共享的属性和方法(谨记:本身自带的属性的权重始终高于原型定义的属性),分工明确

对象创建好了,关键的地方来了,在对象继承之前先要搞明白__proto__和prototype的关系,这个懂了,就可以玩原型链继承了_
本文的所有内容均是一字一句敲上去的,希望大家阅读完本文可以有所收获,因为能力有限,掌握的知识也是不够全面,欢迎大家提出来一起分享!谢谢O(∩_∩)O~

欢迎访问我的GitHub,喜欢的可以star,项目随意fork,支持转载但要下标注,同时恭候:个人博客

等一下( •́ .̫ •̀ ),我还有最后一句话:
我爱你,
为了寻找你 ,
我搬进鸟的眼睛,
经常盯着路过的风 ,
也忘了听猎人的枪声 ,
再见…

《面向对象的程序设计 <step 2 ~ 创建对象>》” /></p></div><div style=     原文作者:苏日俪格
    原文地址: https://www.jianshu.com/p/b2e2c0c56e06
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

点赞