-
(一)面向对象
面向对象是一种程序的设计思想,与之相对的编程思想叫面向过程
- 举个例子感受一下:比如我们想用代码描述一个这样的场景,有一只叫做XiaoA的猫,吃了一个苹果,又吃了一条鱼,然后有一只叫做xiaoB的猫,吃了一根香蕉
//面向过程编程
function xiaoAEatApple(){}
function xiaoAEatFish(){}
function xiaoBEatBanana(){}
xiaoAEatApple();
xiaoAEatFish();
xiaoBEatBanana();
//面向对象编程
function Cat(name){
this.name = name;
}
Cat.prototype.eat = function(somthing) {}
var xiaoA = new Cat('xiaoA');
var xiaoB = new Cat('xiaoB');
xiaoA.eat('apple');
xiaoA.eat('fish');
xiaoB.eat('banana');
- 面向对象的特点
- 面向对象注重于抽象事物,而面向过程注重于叙述事物
- JS通过函数和原型,模拟了传统面向对象编程中的类的概念,实现了面向对象的编程模式
- 面向对象的编程思想,主要为了实现 3 件事:封装、继承、多态
封装
var catA = {
name: 'xiaoA',
eat: function(){
console.log('xiaoA eat something');
}
}
var catB = {
name: 'xiaoB',
eat: function(){
console.log('xiaoB eat something');
}
}
var catC = {
name: 'xiaoC',
eat: function(){
console.log('xiaoC eat something');
}
}
//封装
//使用工厂模式进行封装
function CreateCat(name){
var obj = {};
obj.name = name;
obj.eat = function(){
console.log(name + ' eat something');
}
return obj;
}
var xiaoA = CreateCat('xiaoA');
var xiaoB = CreateCat('xiaoB');
var xiaoC = CreateCat('xiaoC');
//使用面向对象进行封装
function CreateCat(name){
this.name = name;
this.eat = function(){
console.log(this.name + 'eat something');
}
}
var xiaoA = new CreatCat('xiaoA');
var xiaoB = new CreatCat('xiaoB');
var xiaoC = new CreatCat('xiaoC');
/*
new 做了啥
1. 创建一个空对象
2. 把构造函数的prototype赋值给新对象的__proto__
3. 把构造函数的this,指向新对象
4. 把构造函数的代码,执行一遍
5. 把新对象返回
*/
/*
如 var xiaoA = new CreatCat('xiaoA') -->
{
__proto__: CreateCat.prototype,
name: 'xiaoA',
eat: function() {console.log(this.name + 'eat something')},
}
*/
继承
//继承
/*
* new 做了哪些操作
* 1.创建一个空对象
* 2.将构造函数的prototype属性赋值给新对象的__proto__
* 3.将构造函数的this指向新对象
* 4.执行构造函数的代码
* 5.将新对象返回
*/
//在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法
function CreateCat(name){
this.name = name;
}
CreateCat.prototype.eat = function(something){
console.log(this.name + ' eat ' + something);
}
var catA = new CreateCat('xiaoA');
// catA.eat('fish');
console.log(catA);
console.log(CreateCat.prototype);
/*
CreateCat.prototype = new Object() -> {
__proto__: Object,
constructor: CreateCat(){...},
eat: function(something){...}
}
catA = {
__proto__: CreateCat.prototype,
name: 'xiaoA'
}
*/
// 在js里规定,访问对象的属性和方法时,如果对象下没有这个属性或方法,则沿着他的__proto__一直往上找,直到尽头
// 一、类式继承
function A(name) {
this.name = name;
this.list = [1,2,3];
}
A.prototype.getName = function(){
console.log(this.name);
}
function SubA(){
this.subName = 'sub' + this.name;
}
//类式继承一波,注意这里莫得参数,导致undefined
SubA.prototype = new A();
var one = new SubA('one');
console.log(one);
console.log(SubA.prototype);
/*
SubA.prototype = new A() -> {
__proto__: A.prototype,
name: undefined,
list: [1,2,3]
}
new SubA('one') -> {
__proto__: SubA.prototype,
subName: 'subundefined'
}
//类式继承的问题
//1.这种方法不支持父构造函数带参数
//2.父构造函数中的属性和方法都变成共有属性
*/
// 二、构造函数继承
function A(name) {
this.name = name;
this.list = [1,2,3];
}
A.prototype.getName = function(){
console.log(this.name);
}
function SubA(name){
//构造函数继承一波
A.call(this, name);
this.subName = 'sub' + this.name;
}
let s1 = new SubA('one');
console.log(s1.name, s1.subName);
console.log(s1);
s1.getName(); //报错
/*
new SubA('one'): -> {
__proto__: SubA.prototype,
name: 'one',
list:[1,2,3],
subName: 'subone'
}
//构造函数的问题:不能继承父构造函数的原型方法
*/
//三、组合式继承:类式继承+构造函数继承
function A(name) {
this.name = name;
this.list = [1,2,3];
}
A.prototype.getName = function(){
console.log(this.name);
}
function SubA(name){
//关键一
A.call(this, name);
this.subName = 'sub' + this.name;
}
//关键二
SubA.prototype = new A();
let one = new SubA('xiaoA');
console.log(one);
one.getName();
/*
SubA.prototype = new A(): ->{
name: undefined,
list: [1,2,3],
__proto__: {
getName: fn
}
}
new SubA("xiaoA"): -> {
name: 'xiaoA',
list: [1,2,3],
subName: 'sub xiaoA',
__proto__: {
name: undefined,
list: [1,2,3],
__proto__: {
getName: fn
}
}
}
//组合式继承的小问题
//1. __proto__里面的属性没有用
//2.执行了两次父构造函数
*/
//四、寄生组合式继承
function A(name) {
this.name = name;
this.list = [1,2,3];
}
A.prototype.getName = function(){
console.log(this.name);
}
function SubA(name){
//关键一
A.call(this, name);
this.subName = 'sub' + this.name;
}
//关键二:直接new太暴力了
// SubA.prototype = new A();
//换这个方式
function inheritPrototype(subClass, superClass) {
function F(){}
F.prototype = superClass.prototype;
subClass.prototype = new F();
// subClass.prototype.constructor = subClass;
}
inheritPrototype(SubA, A);
let one = new SubA('xiaoA');
console.log(one);
one.getName();
/*
new SubA('xiaoA') --> {
__proto__: new F(),
name: 'xiaoA',
list: [1,2,3],
subName: 'subXiaoA'
}
new F() --> {
__proto__: superClass.prototype(A.prototype)
}
*/
多态
//多态: 表示不同对象调用相同方法。会产生不同的结果
function Base(){}
Base.prototype.initial = function(){
this.init();
}
function SubA(){
this.init = function(){
console.log('SubA');
}
}
function SubB(){
this.init = function(){
console.log('SubB');
}
}
SubA.prototype = new Base();
SubB.prototype = new Base();
/*
SubA.prototype = new Base() -->
{
__proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubA } },
init: function(){ console.log('SubA')}
}
同理
SubB.prototype = new Base() -->
{
__proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubB } },
init: function(){ console.log('SubB')}
}
所以SubA和SubB调用initial会有不同的结果
*/
var subA = new SubA();
var subB = new SubB();
subA.initial();
subB.initial();