什么是面向对象
- 用对象的思想去写代码,就是面向对象棉城
面向对象的特点
- 抽象: 抓住核心问题
- 封装:只能通过对象来访问方法
- 继承:从已有对象上继承出新的对象
- 多态:多对象的不同形态
对象的组成
- 方法:对象下面的函数叫做对象的方法
- 属性:对象下面的变量,就叫做对象的属性
构造函数
- 一个函数被new 调用了之后,那这个函数就是一个构造函数
- 当new去调用一个函数的时候,那这个函数体中的this就是创建出来的对象,而且这个函数的返回值就是this(隐式返回)
function createPerson(name) {
this.name = name;
this.showName = function () {
console.log(this.name)
}
// 这里的this就是指p这个对象,并将其返回
}
// 现在这个createPerson这个函数没有return但是这里隐式返回了p这个对象
var p = new createPerson('小明');
p.showName();
对象的引用
-
基本类型
赋值的时候就是值得复制 -
对象类型
不仅是值得复制,还包括地址的引用
var a = [1,2,3];
var b = a; // 将a的值赋值给b,并将a的地址(住的地方)给b
b.push(4); // 修改b: 在b的末尾添加4
console.log(b); // [1,2,3,4]
console.log(a); // [1,2,3,4]
var a = [1,2,3];
var b = a; // 将a的值赋值给b,并将a的地址(住的地方)给b
b = [1,2,3,4]; // 重新给b赋值,相当于在内存中重新生成了一个新的对象,和a对象没有关系了
console.log(b); // [1,2,3]
console.log(a); // [1,2,3,4]
只要在程序中赋值,那必然会在内存中重新生成,相当于将原来的值给删除了,在申明并赋值
原型 prototype
- prototype原型对象: 默认每个函数对象都有prototype属性,prototype对象中默认有一个constructor
- __proto__原型属性:默认每个对象都有__proto__ 属性,改属性默认指向创建对象对应的构造函数中的prototype
- js中的对象都是基于原型的对象,使用prototype的目的就是资源共享
- 对象属性调用:
先在自身空间中查找,如果有就直接使用,没有就在原型中查找; 如果原型不存在,就在原型的原型中查找(这种链式的关系称之为原型链),如果一直不存在,最终会找到原型链的终点(Object.prototype),如果在终点中还没有找到,待调用改属性,则返回undefined
对象的继承
-
构造函数的的继承
缺点:不能继承父类原型的方法
function Parent(name) {
this.name = name
}
Parent.prototype.createMethods = function () {
console.log(this.name);
}
function Child(name,age) {
Parent.call(this, name);
this.age = age;
}
var c = new Child('张山', 18)
console.log(c.name) // 张山
console.log(c.age) // 18
console.log(c.createMethods) // undefined
-
原型连继承
缺点: 当你在子类的原型添加新的方法的时候,在父类的原型上也会有这个方法, 并且父类和子类的constructor都指向父类
function Parent(name) {
this.name = name;
}
Parent.prototype.showName = function () {
return this.name;
}
function Child(name, age) {
Parent.call(this, name);
this.age = '18';
}
Child.prototype = Parent.prototype; // 对象的引用
Child.prototype.showAge = function () {
return this.age
}
var p = new Parent();
var c = new Child('张珊', 18);
console.log(c.name); // 张珊
console.log(c.age); // 18
console.log(c);
console.log(p); // 此时你在p的原型上也可以看到showAge这个方法
console.log(c.constructor === p.constructor) // 父类实例和子类实例的constructor都指向父类
- 组合继承
那种通过这种方式就可以完美的解决问题了面向对象的继承的问题
function Parent(name) {
this.name = name;
}
Parent.prototype.showName = function () {
return this.name;
}
function Child(name, age) {
Parent.call(this, name);
this.age = '18';
}
Child.prototype = Object.create(Parent.prototype); // 实现继承
Child.prototype.constructor = Child; // 指定子类的构造函数为子类
var p = new Parent();
var c = new Child('张珊', 18);
console.log(c.constructor === p.constructor)
console.log(c.name); // 张珊
console.log(c.age); // 18
console.log(c);
console.log(p);