面向对象的程序设计

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

建立对象

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

  • 对象字面量

栗子以下:函数

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, 工做:救阿斗

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

  • 构造函数

栗子以下:prototype

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, 工做:救阿斗

和工厂模式的不一样之处:code

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

优势:因为两个实例共享了show这个全局的方法,就解决了两个函数作一件事的问题
缺点:若是定义了多个全局的函数,那么这个自定义的引用类型就丝毫灭有封装性可言了,并且每一个方法都要在每一个实例上从新建立一遍,为了解决这个缺点,咱们使用原型模式对象

  • 原型模式

栗子以下:blog

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~

个人简书:https://www.jianshu.com/u/72f239ec5d03
等一下( •́ .̫ •̀ ),我还有最后一句话:
我爱你,
为了寻找你 ,
我搬进鸟的眼睛,
常常盯着路过的风 ,
也忘了听猎人的枪声 ,
再见...

相关文章
相关标签/搜索