js基础-面向对象编程

一、js中的this

1、this的概念 

注意:this没有继承

function f(){
    console.log(this.x)
};
var obj = {
    f:f,
    x:1
};
var x = 2;
f();
obj.f();

 若不使用箭头函数,使用临时变量保存一下this

let foo = function(){
    var self = this;//this 就是obj对象
    console.log(this===obj);
    f();
    function f(){
        console.log(this===obj);
        console.log(self === obj);
    }
}
var obj = {
    m:foo
}
obj.m()

2、this的指向

  • 全局作用域的this window||global
function sayHello(){
    console.log(this)
}
sayHello()//输出window(非严格模式)或者undefined(严格模式)
  • 函数调用中的this
  • 对象方法中的this 
const ob = {
    name:'aa',
    sayName:function(){
        console.log(this.name)
    }
}
obj.sayName()
  • 构造函数中的this
function Person(name){
    this.name = name
}
const alice = new Person('aa');
console.log(alice.name)
  •  箭头函数中的this(不会创建新的this上下文,而是捕获外层作用域中的this)
const obj = {
    name:'Alice',
    sayName:()=>{
        console.log(this.name)
    }
}
obj.sayName()
  •  事件处理程序中this,this通常指向触发元素对象
document.getElementById('myButton').addEventListener('click',function(){
    console.log(this)//输出<button id="muButton"></button>
})

 3、如何改变this(call\apply\bind)

这些都可以改变函数执行时this的值

function greet(greeting){
  console.log(greeting+','+this.name)
}
const person = {name:'Alice'}
greet.call(person,'Hello')
greet.apply(person,['Hello'])
const boundGreet = greet.bind(person)
boundGreet('Hello')

二、面向对象

1、什么是对象

2、什么是面向对象

  • 面向过程
  • 面向对象(OOP)

3、面向对象的特点

  • 继承
  • 封装
  • 多态 
//处理学生的成绩表,通过面向过程的方式
var stu1 = {name:'aa',score:98};
var stu2 = {name:'bb',score:88};
//处理学生成绩可以通过函数去实现,比如打印
function printScore(student){
  console.log(student)
}
//假如使用面向对象
function Student(name,score){
  this.name = name
  this.score = score
  this.printScore = function(){}
}
//根据模版创建具体实例对象
var std1 = new Student('aa',98)
var std2 = new Student('bb',88)
//打印成绩
std1.printScore()
std2.printScore()

 三、基于函数的面向对象实现

1、创建对象

  • new Object()
  • 对象字面量

2、工厂函数=〉构造函数

如果有10个学生信息,需要var10次对象,所以引入工厂函数

function createPerson(name,age){
  return {
    name,
    age,
    sayName:function(){
      console.log(this.name)
    }
  }
}
var person1 = createPerson('aa',12)
var person2 = createPerson('bb',13)

问题:不能识别对象是什么类型。是否属于Person。 

3、构造函数的问题

用以解决上述person1\person2无法识别引用的是哪个对象的问题

function Person(name,age){
  this.name = name;
  this.age = age
  this.sayName = function(){
    console.log(name)
  }
}
var person1 = new Person('aa',18)
var person2 = new Person('bb',19)

4、new做了哪些事情

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(this指向新对象)
  • 执行构造函数中的代码
  • 返回新对象
function Person(name,age){
  //使用new 调用Person()时,创建一个对象
  //var instance = {}
  //让内部的this指向instance对象
  //this=instance
  //接下来所有针对this的操作就是instance
  //return this

}
console.log(p1.constructor === Person)//true
console.log(p2.constructor === Person)//true
console.log(p1.constructor === p2.constructor)//true

console.log(p1 instanceof Person)//true 推荐使用方式

问题:存在浪费内存(每生成一个实例都会有一段重复的代码,如sayName方法。如果有几十万个学生去初始化这个Person,会造成极大的内存浪费)

function Person(name,age){
  this.name = name;
  this.age = age
  this.type = 'human'
  this.sayName = function(){
    console.log(name)
  }
}
var person1 = new Person('aa',18)
var person2 = new Person('bb',19)
console.log(person1.sayName === person2.sayName)//false

解决方案: 

function sayName(){
  console.log(this.name)
}
function Person(name,age){
  this.name = name;
  this.age = age
  this.type = 'human'
  this.sayName = sayName
}
var person1 = new Person('aa',18)
var person2 = new Person('bb',19)
console.log(person1.sayName === person2.sayName)//true

 问题:sayName成了全局变量,不够优雅。解决:可放原型上

5、原型和原型链

function Person(name,age){
  this.name = name;
  this.age = age
}
Person.prototype.type='human'
Person.prototype.sayName = function(){
  console.log(this.name)
}
var person1 = new Person('aa',18)
var person2 = new Person('bb',19)
console.log(person1.sayName === person2.sayName)//true
function F(){
  sayHi() {}
}
console.log(F.prototype)//Object
console.log(F.prototype.constructor===F)//true

var instance = new F()
console.log(instance.__proto__ === F.prototype)//true

 

四、es6中的面向对象 

1、Classes(类) 和 Object(对象)

  • 类是一种特定对象中方法和变量的模版定义
  • 对象是类的具体实例,并且在内存中分配

            注意(大部分浏览器原生不支持这种class,一般通过打包工具编译成function之后才能运行) 

//定义类
class Form{
  submit(){
    console.log(this.name+''+this.role+'表单已提交')
  }
  cancel(){
    console.log(this.name+''+this.role+'表单已取消')
  }
  fill(give_name,role){
    this.name=give_name
    this.role = role
  }
}
//创建对象
const student1Form = new Form()
student1Form.fill('aa',14)
const student2Form = new Form()
student2Form.fill('bb',14)

student2Form.cancel()
student1Form.submit()
student2Form.submit()

 2、Constructor(构造函数)

//定义类
class Form{
  constructor(){
    //构造函数初始化默认的name和role
    this.name = 'test';
    this.role = 'Student'
  }
  submit(){
    console.log(this.name+''+this.role+'表单已提交')
  }
  cancel(){
    console.log(this.name+''+this.role+'表单已取消')
  }
  fill(give_name,role){
    this.name=give_name
    this.role = role
  }
}
//创建对象
const student1Form = new Form()
//student1Form.fill('aa',14)
const student2Form = new Form()
//student2Form.fill('bb',14)

student2Form.cancel()
student1Form.submit()
student2Form.submit()

 无参构造函数:没有参数的构造函数

class Example{
  constructor(){
    this.name = 'test'
  }
}

有参构造函数:一个带有参数的构造函数 

class Example{
  constructor(value){
    this.name = value
  }
}

3、Inheritance(继承)

一个类从另一个类中继承的属性和能力

class Animal {
  constructor(name,color,age){
    this.name = name
    this.color = color
    this.age = age
  }
  run(){
    console.log(this.name+'正在跑')
  }
  shout(){
    console.log(this.name+'正在叫')
  }
  sleep(){
    console.log(this.name+'在睡觉')
  }
}
class Monkey {
  constructor(name,color,age){
    this.name = name
    this.color = color
  }
  run(){
    console.log(this.name+'正在跑')
  }
  shout(){
    console.log(this.name+'正在叫')
  }
  sleep(){
    console.log(this.name+'在睡觉')
  }
  eatBanana(){
    console.log(this.name+'在吃香蕉')
  }
}
const animal1 = new Monkey('猴子','棕色',2)
const animal2 = new Animal('狗','白色',3)
animal1.eatBanana()
animal2.shout()

通过继承改写

//父类-基类
class Animal {
  constructor(name,color,age){
    this.name = name
    this.color = color
    this.age = age
  }
  run(){
    console.log(this.name+'正在跑')
  }
  shout(){
    console.log(this.name+'正在叫')
  }
  sleep(){
    console.log(this.name+'在睡觉')
  }
}
//子类-派生类
class Monkey extends Animal{
  eatBanana(){
    console.log(this.name+'在吃香蕉')
  }
  hide(){
    console.log(this.name+'在躲藏')

  }
}
const animal1 = new Monkey('猴子','棕色',2)
const animal2 = new Animal('狗','白色',3)
animal1.eatBanana()
animal2.shout()
animal1.hide()

上面是单继承,还有多继承,一个类继承另一个类,这个类又继承另一个父类

//父类-基类
class Animal {
 
}

class Mammal extends Animal{}
class Dog extends Mammal{}

层次继承:多个类继承同一个类

//父类-基类
class Animal {
 
}
class Mammal extends Animal{}
class Dog extends Animal{}


  • 多重继承:一个子类同时继承多个父类的方法(js不直接支持多重继承,但可以通过mixin实现类似的效果)
//Mixin1 可飞行
const fly = (Base)=>class extends Base{
  fly(){}
}
//Mixin2 可以跑
const run = (Base)=>class extends Base{
  run(){}
}
//基类
class Animal{
  constructor(name){
    this.name = name
  }
  move(){}
}
//可以通过Mixin实现多重继承
class Duck extends fly(run(Animal)){}
  • 混合继承:通过多种继承方式,mixin去实现
//Mixin1 可飞行
const fly = (Base)=>class extends Base{
  fly(){}
}
//基类
class Animal{
  constructor(name){
    this.name = name
  }
  move(){}
}
class FlyAnimal extends fly(Animal){};
class Duck extends FlyAnimal{}

4、重写

class Human { 
  constructor(name, age, bodyType) { 
    this.name = name; 
    this.age = age; 
    this.bodyType = bodyType; 
  } 
  getName(){} 
  getAge(){} 
  getBodyType(){}
}
  • super:用于调用父类的构造函数,以访问其属性和方法
  • 重写构造函数
class Human { 
  constructor(name, age, bodyType) { 
    this.name = name; 
    this.age = age; 
    this.bodyType = bodyType; 
  } 
  getName(){} 
  getAge(){} 
  getBodyType(){}
}
class Student extends Human{
  constructor(){
    super('aa',80,'胖')
  }
}
const std1 = new Student()
std1.getName()

重写方法

class Student extends Human{
  constructor(){
    super('aa',80,'胖')
  }
  //使用super关键字在子类中重写方法 方法名同名,同参,且仅发生在类继承关系中
  getAge(){
    super.getAge()
  }
}

5、重载

class Calculator {
  add(a,b){
    return a+b
  }
  add(a,b,c){
    return a+b+c
  }
}
const calc = new Calculator()
console.log(calc.add(1,2))//NaN

 可以hack

class Calculator {
  add(...args){
    if(args.length>0)return args.reduce((sum,num)=>sum+num,0)
  }
}
// 柯里化 也能解决上述问题
// 经典面试题
// f(1)(2)(3) =>6
// f(1)(2) =>3
// ...

6、访问修饰符

  • public: 可以从其他任何类中访问
  • protected:受保护的成员,可以在同一类及其子类中访问
  • private:私有成员,只能在同一个类中访问

7、静态方法

static:给类定义一个静态方法或字段,静态方法是属于类本身的方法,而不是类的具体实例的方法。也可被继承。

class Animal{
  constructor(){}
  static cap(name){console.log(name)}
  static init(){}
}
class Calc{
  add(){
    return Animal.cap('bb')//在非静态方法中使用静态方法
  }
}
Animal.cap('aa')
Animal.init()

8、Getter和Setter

class Animal{
  constructor(){}
  get getName(){
    return this.name
  }
  set setName(name){
    this.name = name
  }
}
const dog = new Animal()
dog.setName = 'xx';
dog.getName()

9、instanceOf

检查一个对象是否是某个类或者接口的实例

10、封装

是一种限制对对象某些组件或属性直接访问的方式

class Bank { 
  #balance;// 私有字段
}

11、多态

多种继承形式,一种函数的不同表达式

12、抽象

内部方法不展示实现方法,是隐藏的。一种设计思路,用于工具库和组件库的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值