面向对象编程
面向对象是一种编程思想,经常被拿来和面向过程比较。
简单点,面向过程关注的重点是动词,是分析出解决问题需要的步骤,然后编写函数实现每个步骤,最 后依次调用函数。而向对象关注的重点是主谓,是把构成问题的事物拆解为各个对象,而拆解出对象的目的也 是为了实现某个步骤, 而是为了描述这个事物在当前问题中的各种行为。
面向对象的特点:
1、封装 让使用对象的人不考虑内部实现,只考虑功能使用把内部的代码保护起来,只留出一些api接口供用户使用。
2、继承 就是为了代码的复用,从父类上继承出一些方法和属性,子类也有自己的一些属性
3、多态 是不同对象作用于同一操作产生不同的效果。多态的思想实际上是把“想做什么”和“谁去做”分开
什么时候适合使用面向对象
可以看出来,在比较复杂的问题面前,或者参与方较多的时候,面向对象的编程思想可以很好的简化问题,并且能够更好的扩展和维护。
Js中的面向对象
对象包含方法和属性
创建对象
1、普通方式
const Player = new Obejct();
Player.color = "white"
Player.start = function() {
console.log('start')
}
工厂模式
function createObject() {
const Player = new Obejct();
Player.color = "white"
Player.start = function() {
console.log('start')
}
return Player
}
2、构造函数/实例
通过 this 添加的属性和 法总是指向当前对象的,所以在实例化的时候,通过this添加的属性和方法都会在内存中复制一份,这样就会造成内存的浪费。
但是这样创建的好处是即使改变了某一个对象的属性或方法,不会影响其他的对象(因为每 个对象都是复制的一份)
function Player(color) {
this.color = color
this.start = function() {
console.log(color)
}
}
const player1 = new Player('red')
const player2 = new Player('blue')
console.log(player1 === player2) // false 内存被创建了多次
3、原型
通过原型继承的方法并不是自身的,我们要在原型链上一层一层的查找,这样创建的好处是只在内存中创建一次,实例化的对象都会指向这个prototype对象。
function Player(color) {
console.log(color)
}
Player.prototype.start = function() {
console.log(color)
}
const player1 = new Player('red')
const player2 = new Player('blue')
console.log(player1.start === player2.start) // true
4、静态属性 是绑定在构造函数上的属性方法,需要通过构造函数访问
function Player(color) {
this.color = color
if (!Player.total) {
Player.total = 0
}
Player.total++
}
const player1 = new Player('red')
console.log(Player.total)
const player2 = new Player('blue')
console.log(Player.total)
原型及原型链
function Player(color) {
console.log(color)
}
Player.prototype = {
start: function() {
console.log('start')
},
revert: function() {
console.log('revert')
}
}
找Player的原型对象
const Player1 = new Player('red')
const Player2 = new Player('blue')
console.log(Player1.__proto__) // === Player.prototype {start: ƒ, revert: ƒ}
console.log(Object.getPrototypeOf(Player1)) // Player.prototype {start: ƒ, revert: ƒ}
Object.getPrototypeOf 获取__proto__
console.log(Player.__proto__) // [Function]
流程图
new关键字
- 一个继承自Player.prototype的新对象Player1被创建
- Player1.proto指向Player.prototype
- 将this指向新创建的对象Player1
- 返回新对象
- 如果构造函数没有显式返回值,则返回this
- 如果构造函数有显式返回值,是基本类型, 如 number,string,boolean, 那么还是返回this
- 如果构造函数有显式返回值,是对象类型, 如{ a: 1 }, 则返回这个对象{ a: 1 }
function proPlayer() {
return {a: 1}
}
const pro1 = new proPlayer()
console.log(pro1) // {a: 1}
function proPlayer() {
return 123
}
const pro1 = new proPlayer()
console.log(pro1) // proPlayer {}
function proPlayer() {
return
}
const pro1 = new proPlayer()
console.log(pro1) // proPlayer {}
实现new
function objectFactory() {
let obj = new Object();
let Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
let result = Constructor.apply(obj, arguments)
return typeof result === "object" ? result : obj;
}
原型链
我们都知道当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还 查不到,就去找原型的原型,一直找到最顶层为止。
function Player() {}
Player.prototype.name = 'Tom'
let p1 = new Player()
p1.name = 'Davi'
console.log(p1.name) // Davi
delete p1.name
console.log(p1.name) // Tom
如果我们在Player.prototype中也找不到name属性的化,就会去Player.prototype.__proto__中寻找,也就是{}
delete Player.prototype.name
console.log(p1.name)
继承
1、原型链继承
function Parent() {
this.name = 'parentName'
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
Child.prototype.constructor = Child
let child1 = new Child()
child1.getName()
缺点:
1、如果有属性是引用类型,一旦某个实例修改了这个属性,所有实例都会收到影响
2、创建实例的实例的适合,不能传参
function Parent() {
this.actions = ['parentName', 'play']
}
function Child() {}
Child.prototype = new Parent()
Child.prototype.constructor = Child
let child1 = new Child()
let child2 = new Child()
child1.actions.pop()
console.log(child1.actions) //parentName
console.log(child2.actions) //parentName
2、构造函数
function Parent(name, actions) {
this.actions = actions;
this.name = name;
this.eat = function() {
console.log(name)
}
}
function Child(id, name, actions) {
Parent.call(this, name); // 如果想直接传多个参数, 可以Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
const child1 = new Child(1, "c1", ["eat"]);
const child2 = new Child(2, "c2", ["sing", "jump", "rap"]);
console.log(child1.name); // { actions: [ 'eat' ], name: 'c1', id: 1 }
console.log(child2.name);
console.log(child1.eat === child2.eat)
缺点:浪费内存
组合继承
function Parent(name, actions) {
this.name = name;
this.actions = actions;
}
Parent.prototype.eat = function () {
console.log(`${this.name} - eat`);
};
function Child(id) {
Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
function Child(id) {
Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
缺点: 调用了两次构造函数
寄生式组合继承
function Parent(name, actions) {
this.name = name;
this.actions = actions;
}
Parent.prototype.eat = function () {
console.log(`${this.name} - eat`);
};
function Child(id) {
Parent.apply(this, Array.from(arguments).slice(1));
this.id = id;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child1 = new Child(1, "c1", ["hahahahahhah"]);
const child2 = new Child(2, "c2", ["xixixixixixx"]);
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!