面向对象
面向对象就是把需要解决的问题分解成一个个对象,建立对象不是为了实现一个步骤,而是为了描述每个对象在解决问题中的行为,面向对象的核心是对象。
面向对象的优势:
- 模块化更深,封装性强
- 更容易实现复杂的业务逻辑
- 更容易维护、复用、扩展
面向对象的特征:
- 封装性:对象是属性和行为的结合体
- 多态性:同一消息被不同对象接收后,会产生不同的效果
- 继承性:子类型可继承父类的信息
ES6面向对象语法
ES:是ECMAScript的简写,是JavaScript语法规范
ES6:是在ES5基础上的扩展,增加了如面向对象编程的相关技术
类和对象
- 类:具有相同属性和行为的对象的集合(类是对象的抽象)
- 对象:对象是类的具体化(实例化)
class关键字:用来定义类的
class 类名 {
属性
函数
}
类名是一个用户标识符,建议首字母大写
构造函数
ES6中用constructor( ) 来定义构造函数,作用是初始化对象的成员,即创建对象,并为对象的成员赋初始值
构造函数不是必须定义的。若用户没有定义构造函数,系统会生成一个默认、无参的构造函数
//类的构造函数使用练习
class Person{
constructor(name,age,sex){
this.name=name
this.age=age
this.sex=sex
}
fun=function(){
console.log("姓名:"+this.name)
console.log("年龄:"+this.age)
console.log("性别:"+this.sex)
}
}
var p=new Person("张三",20,'男')
p.fun()
构造函数和类的区别:
类中的成员方法是定义在类中的,使用类创建对象后,这些对象的方法都是引用了同一个方法,这样可以节省内存空间
ES6中类和对象注意:
- 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有属性和方法一定要加this使用
- 类里面的this指向问题:constructor 里面的this指向实例对象, 方法里面的this 指向这个方法的调用
成员函数
函数名([参数]){
函数体语句
}
变量名=function([参数]){
函数体语句
}
//输入半径,求圆的面积和周长
class Circle{
constructor(r){
this.radius=r
}
//圆的面积
area(){
var s=Math.PI*Math.pow(this.radius,2)
return s
}
//圆的周长
Circle_length=function(){
return 2*Math.PI*this.radius
}
}
var c=new Circle(5)
console.log("圆的面积:"+c.area())
console.log("圆的周长:"+c.Circle_length())
//模拟简单计算器,可进行加减乘除运算
class Number{
constructor(n1,n2){
this.n1=n1
this.n2=n2
}
add(){
return this.n1+this.n2
}
sub(){
return this.n1-this.n2
}
mul(){
return this.n1*this.n2
}
div(){
if (this.n2==0) {
return "除数不能为0"
}else{
return this.n1/this.n2
}
}
}
var n=new Number(6,0)
console.log("相加="+n.add())
console.log("相减="+n.sub())
console.log("相乘="+n.mul())
console.log("相除="+n.div())
继承
用来表示两个类之间的关系,子类可以继承父类的一些属性和方法,在继承以后还可以增加自己独有的属性和方法。
class子类名 extends 父类名{
函数体语句
}
- 父类又称基类或超类,必须已经定义
- 子类又称派生类,可以继承父类属性和函数
super关键字:
- 调用父类的构造函数,在子类的构造函数中使用super调用父类的构造函数,且必须作为子类构造函数第一条语句 :super([参数])
- super关键字 用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
- 调用普通成员函数:super.函数名([参数])
方法覆盖: 子类定义函数与父类函数同名时,子类函数覆盖父类
//继承
class Father{
constructor(type,color){
this.type=type
this.color=color
}
money(){
console.log(10)
}
show(){
console.log("类型:"+this.type)
console.log("颜色:"+this.color)
}
}
class Son extends Father{
constructor(type,color,weight){
super(type,color) //调用父类构造函数
this.weight=weight
}
show(){ //子类同名方法
super.show()
console.log("重量:"+this.weight)
}
other(){
return "子类的其他方法"
}
}
var s= new Son('4G手机','土豪金','500g')
s.money()
s.show()
静态成员、实例成员
静态成员:通过类名和构造函数访问的成员
实例成员:是实例对象的成员
区别:
- 静态成员是所有对象共享 ,实例成员属于具体的对象
- 静态成员通过类名访问,实例成员通过对象名访问
静态属性的定义
- ES5中: 创建构造函数,构造函数内部定义静态属性:构造函数名.静态属性名
- ES6中: 创建类,在类的外部定义静态属性: 类名.静态属性名
- ES7中: 创建类,在类定义时,使用static关键字定义静态属性: static 静态属性名
静态方法的定义
举例说明:定义静态属性、方法
static 函数名([参数]){
函数体
}
//ES5定义静态属性,使用构造函数定义
function Student(name,age,sex){
Student.school='XX高中' //ES5中静态属性
this.name=name
this.age=age
this.sex=sex
this.show =function(){
console.log(this.name)
console.log(this.age)
console.log(this.sex)
}
}
var s=new Student('张三','18','女')
s.show()
console.log(Student.school)//如果没有创建对象s,直接打印会输出undefined
//定义静态属性,ES5以后引入class属性后可用类定义
class Foo{
//ES7中定义静态属性 static prop=45
constructor(){
this.color="红色"
}
static sayHello(){ //定义静态方法
console.log("hello")
}
}
// ES6中静态属性
Foo.prop=45 //prop是静态的属性
var f1=new Foo()
console.log("静态属性:"+Foo.prop)
Foo.sayHello()
类的本质
- class本质还是function
- 类的所有方法都定义在类的prototype属性上
- 类创建的实例,里面也有 __ proto__ 指向类的prototype原型对象
- ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
class Star{
}
console.log(typeof Star) //类本质就是一个函数
console.log(Star.prototype) //类有原型对象
console.log(Star.prototype.constructor) //类的原型对象constuctor指向类本身
Star.prototype.sing=function(){ //类可以通过原型对象添加方法
cosnole.log("唱歌")
}
var s=new Star()
console.log(s.__proto__===Star.prototype) //类创建的实例对象有__proto__原型指向类的原型对象
原型内容在之后文章详细讲:JavaScript 原型对象、原型链、成员查找机制