一、对象是什么,为什么要面对对象?
1.对象的特点
- 逻辑迁移更加灵活,代码复用率高,高度的模块化
2.对象的理解
- 对象是对单个物体的抽象
- 对象时一个容器,封装了属性和方法 ** 属性: 对象的状态 ** 方法: 对象的方法
3.两种对象
// 简单对象
const Person = {
name: 'haiyanng',
age: '18',
getFullName: function(surname) {
return `${surname}${this.name}`
}
}
// 函数对象
const Person = function() {
this.name = 'haiyang';
this.age = '18';
this.getFullName = function(surname) {
return `${surname}${this.name}`
}
}
二、构造函数(Constructor)-用于构造对象
1、构造函数的理解
- 对象模板-将一类事物共同的特征,抽象为一个对象
- 类即对象模板
- js本质上不是基于类,而是基于构造函数和原型链
- constructor + prototype
2、函数对象本质就是构造函数
- 函数体内使用的this,指向所要生成的实例
- 生成对象用new进行实例化
- 可以做初始化传参
const Person = function(name,age) {
this.name = name;
this.age = age;
this.getFullName = function(surname) {
return `${surname}${this.name}`
}
}
面试题:
- 如果构造函数不实例化,可以使用吗? --- 无法使用
- 如果项目中需要使用,通常如何解决? ---让其初始化不被外界感知
const Person = function(name,age) {
const _isClass = this instanceof Person; // 是否有实例化
if(!_isClass) {
return new Person(name,age)
}
this.name = name;
this.age = age;
this.getFullName = function(surname) {
return `${surname}${this.name}`
}
}
const person = Person('yao', '19')
启发:如果做底层封装,可以不让外界感知内部的构造函数和类型,只返回api
3、在实例化的时候,new都做了什么?
- 创建了一个空对象,作为对象实例
- 将实例的的原型对象指向构造函数的prototype
- this指向新的实例对象
- 执行构造函数的内容
面试题: 实例属性在多个实例中是相互独立的吗? -独立,实例属性会重复挂载到到不同的实例对象上,因为执行构造函数的初始化代码时,this的指向不同
4、constructor
function Person() {};
const person1 = new Course();
const person2 = new Course();
- 构造函数: 用来创建对象并初始化一部分属性的函数 - Person
- 每个对象在创建时,都会有一个construtor属性
- constructor继承自对象的构造函数的原型对象,指向所继承的构造函数
面试题: 使用构造函数创建对象有没有什么性能上的问题? -有,会重复挂载所有可能有的实例属性和方法。比较耗费资源
5、原型对象prototype
实例对象会重复挂载,原型对象各个实例与其构造函数共享
function Course() {};
const course1 = new Course();
const course2 = new Course();
- 每个构造函数都会被赋予一个属性prototype,该属性等于实例对象的原型对象
- 实例对象: course1是实例对象,根据原型对象创建出来的实例对象,每个都有一个原型对象__proto__ 每个都有一个构造函数constructor,构造函数constructor由继承而来,指向当前的构造函数
- 原型对象:Course.prototype,实例的原型对象指向构造函数的原型对象,即person1.proto === Person.prototype
function Person(name) {
this.name = name;
}
// 方法挂载于prototype上
Person.prototype.setAge = function(age) {
this.age = age;
return `${this.name}今年${age}了!`;
}
const person1 = new Person('xiaoming');
const person2 = new Person('xiaohong');
person1.setAge('18') // xiaoming今年18了!
person1 // {name: 'xiaoming',age: 18}
person2 // {name: 'xiaohong'}
六、继承
1、原型链继承:让子对象冒充实例继承,可继承对象的所有实例属性方法和原型上所有的属性方法
- 实现
// 本质:重写原型对象方式。将父对象的所有属性方法,都作为子对象原型对象的属性和方法。
function Father() {
this.name = "ziaoming";
}
Father.prototype.setAge = function(age) {
this.age = age;
return `${this.name}今年${age}了!`;
}
function Son() {}
Son.prototype = new Father()
Son.prototype.constructor = Son;
const son1= new Son();
- 缺点 1.所有属性和方法(包括原型对象和实例上的属性和方法)都在原型链上,所以所有的属性和方法都是共享的 2.无法通过子对象传参
2、构造函数继承
- 实现
function Father(name) {
this.name = name;
}
Father.prototype.setAge = function(age) {
this.age = age;
return `${this.name}今年${age}了!`;
}
function Son(name) {
Father.call(this,name)
}
const son1= new Son('xiaoming');
- 缺点 原型链上的共享方法无法被读取继承
3、组合继承
- 实现
function Father(name) {
this.name = name;
}
Father.prototype.setAge = function(age) {
this.age = age;
return `${this.name}今年${age}了!`;
}
function Son(name) {
Father.call(this,name)
}
Son.prototype = new Father()
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');
- 缺点 调用两次父类构造函数:函数内部调用一次,new调用一次
4、寄生组合继承
function Father(name) {
this.name = name;
}
Father.prototype.setAge = function(age) {
this.age = age;
return `${this.name}今年${age}了!`;
}
function Son(name) {
Father.call(this,name)
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');
5、如何实现多重继承(同时继承两个构造函数)
function Father(name) {
this.name = name;
}
function Mother(age) {
this.age = age;
}
function Son(name,age) {
Father.call(this,name);
Mother.call(this,age)
}
Son.prototype = Object.create(Father.prototype);
Object.assign(Son.prototype, Mother.prototype)
Son.prototype.constructor = Son;
const son1= new Son('xiaoming');