你们好,我是苏日俪格,本文是面向对象的第二部分,纯属我的理解,有哪里不对的地方请在评论区指出,你们一块儿学习共同进步。前端
在面试中,常常会被问到建立对象都有哪些方式,在建立单个对象的时候一般就用对象字面量,多个对象就用工厂模式、构造函数、原型模式和构造函数原型的混合模式
下面来逐个介绍一下:面试
栗子以下:函数
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
优势:因为两个实例共享了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~