「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
第一部分
面向对象?
总听说面向对象编程,那面向对象到底是什么?
面向对象就是将构成问题的事物分解成多个对象,然后由对象之间分工和合作。
面向过程
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以了
区别
- 面向过程性能比面向对象高,适合跟硬件联系很紧密的东西。例如单片机。
- 没有面向对象易维护、易复用、易扩展。
- 面向对象编程具有灵活、代码可复用、容易维护和开发的优点、更适合多人合作的大型软件项目。
- 可以设计出低耦合的系统,使系统更加灵活。
面向对象的特征
- 封装性
- 继承性
- 多态性
第二部分
创建对象的多种方式
js就是一门面向对象的编程语言
- 字面量创建对象
var person ={
name:'张三',
age:20,
like:function () {
console.log('他喜欢打篮球')
}
}
console.log(person.name);
- new Object()
var person = new Object();
person.name = '张三';
person.age = 20;
person.like = function () {
console.log('他喜欢打篮球');
}
- 自定义函数
function Person(){
this.name = '张三';
this.age = 20;
this.like= function () {
console.log('他喜欢打篮球');
}
}
- 工厂模式创建对象
function Person(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.like= function () {
console.log('他喜欢打篮球');
}
return obj;
}
console.log(Person('张三', 20));
- 构造函数模式创建
class Star {
constructor(name, age) {
this.name = name;
this.age = age;
}
sing(song) {
console.log('我唱歌');
console.log(this.name + song);
}
}
var ldh = new Star("刘德华", 20);
console.log(ldh);
ldh.sing("冰雨");
构造函数和普通函数的区别
- 它们都是函数,构造函数也可以当成普通函数调用,做普通函数调用的时候,this指向window对象。
- 用new的方式去使用一个函数,那么它就是一个构造函数了。
- 为了区别,如果一个函数想作为构造函数,我们经常将首字母大写来表示这是一个构造函数。
//当作普通函数调用
function Person1(){
this.name = "张三"; // 把name属性添加到了window对象上面
alert(this === window); //作为普通函数调用,则是true
}
Person(); // 把构造函数当做普通方法调用。这个时候内部的this指向了weindow
alert(window.name); //张三
function Person2(){
this.name = "Mark";
alert(this instanceof window); // false
alert(this instanceof Human); //true
}
var h = new Human(); //当做构造函数来调用,创建一个对象
alert(h.name);//张三
继承
- 原型链继承 核心:将父类的实例作为子类的原型 缺点:父类新增的原型方法/原型属性,子类都能获取的到。但是父类一旦改变,子类也会跟着改变。
function Person() {}
Person.prototype.name = "john";
Person.prototype.age = 20;
Person.prototype.sayHello = function () {
console.log(this.name); //john
}
function Male() {}
/* Male.prototype = Person.prototype; //Male原型对象就具有了Person原型对象的属性和方法
//但是父类原型和子类原型是同一个,子类的修改会影响到父类
Male.prototype.sexy = "male"; */
Male.prototype = new Person();//这一步实现了Male对Person的继承 成为原型继承
Male.prototype.sexy = "male";
var male = new Male();
/*
male这个实例里面有没有__proto__
male.__proto__== Male.prototype
Male.prototype.__proto__ == Person.prototype
//这时就形成了原型链
*/
male.sayHello();
//male访问sayHello,访问顺序:实例属性->Male.prototype->Person.prototype->……->Object.prototype->undefined
console.log(male.sexy); //male
var person = new Person();
console.log(person.sexy); //undefined
- 构造函数继承 核心:将父类的实例复制给子类(实际上没有用到原型链) 缺点:只能继承父类实例的方法和属性,不能继承原型链上的属性和方法,无法实现函数复用
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function () {
console.log(this.name);
}
}
function Male(name, age) {
Person.call(this, name, age);//利用call方法改变this指向
this.sexy = "male";
}
var male = new Male("john", 20);
console.log(male); //返回是一个对象
- 组合继承
所有的实例都能拥有自己的属性,并且可以使用相同的方法
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后再通过将父类实例作为子类原型,实现函数复用
function Person (name) {
this.name = name;
this.friends = ['andy','edgar'];
};
Person.prototype.getName = function () {
return this.name;
};
function Parent (age) {
Person.call(this,'riemann'); //这一步很关键
this.age = age;
};
Parent.prototype = new Person('riemann'); //这一步也很关键
var result = new Parent(24);
console.log(result.name); //riemann
result.friends.push("小智"); //
console.log(result.friends); //['andy','edgar','max']
console.log(result.getName()); //riemann
console.log(result.age); //26
var result1 = new Parent(26); //通过借用构造函数都有自己的属性,通过原型享用公共的方法
console.log(result1.name); //riemann
console.log(result1.friends); //['andy','edgar']
- 寄生方式 核心:通过寄生方式,砍掉父类实例
function Person(name) {
this.name = name;
this.friends = ['andy','edgar'];
}
Person.prototype.getName = function () {
return this.name;
};
function Parent(age) {
Person.call(this,"riemann");
this.age = age;
}
(function () {
var Super = function () {}; // 创建一个没有实例方法的类
Super.prototype = Person.prototype;
Parent.prototype = new Super(); //将实例作为子类的原型
})();
var result = new Parent(26);
console.log(result.name);
console.log(result.friends);
console.log(result.getName());
console.log(result.age);