1. 重点提炼
- 面向过程
- 面向对象
- es5/es6中的类与继承等基本使用
2. 面向过程与面向对象
面向过程 => 分析需求整个过程由哪个几个步骤组成,逐步实现。
面向对象 => 分析需求中由哪几个对象组成,分析每种对象应该由哪些属性和方法 / 行为组成。
如下:
隐藏对象 => 可能是人、手、或者其他工具将大象放入冰箱
JavaScript是一种基于对象(object-based)的语言
对于面向对象编程而言,更关注类的声明、属性、方法、静态方法、继承、多态、私有属性。
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。
2.1 类与对象
狗这个范围比较大,很抽象 => 代表类
我家的狗,很具体到实体 => 对象
类(class)是对象(object)的模版,定义了同一组对象共有的属性和方法。
3. ES5中的类与继承
一般定义函数
的首字母
小写
,约定俗成类
的首字母
定为大写
。
类与构造函数 =>
// 构造函数
function People(name, age) {
console.log(this)
// 实例属性
this.name = name
this.age = age
}
// 实例化对象
let p1 = new People('张三', 24)
console.log(p1)
let p2 = new People('李四', 20)
console.log(p2)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.02
Branch: branch02commit description:a2.02(ES5中的类与继承——类与构造函数 )
tag:a2.02
类的方法 =>
// 类
// 构造函数
function People(name, age) {
console.log(this)
// 实例属性
this.name = name
this.age = age
// 方法
this.showName = function () {
console.log('我的名字是' + this.name)
}
}
// 实例化对象
let p1 = new People('张三', 24)
console.log(p1)
p1.showName()
let p2 = new People('李四', 20)
console.log(p2)
p2.showName()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.03
Branch: branch02commit description:a2.03(ES5中的类与继承——类的方法 )
tag:a2.03
但是一般情况下,不会把方法定义在构造函数中,因为每次new
一个对象,就会new
出一个方法,这样都放在对象下并不好,很累赘。实际应该放在类的原型下 =>
// 类
// 构造函数
function People(name, age) {
console.log(this)
// 实例属性
this.name = name
this.age = age
}
// 实例方法
People.prototype.showName = function () {
console.log('我的名字是' + this.name)
}
// 实例化对象
let p1 = new People('张三', 24)
console.log(p1)
p1.showName()
let p2 = new People('李四', 20)
console.log(p2)
p2.showName()
如此就不会每次new
一个实例,再new
方法,避免都是一个东西,却占了很多内存。原型实际是一个类共有的,每个实例无需再多开辟的内存。它属于这个类所有实例共享的公共空间
。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.04
Branch: branch02commit description:a2.04(ES5中的类与继承——原型方法)
tag:a2.04
静态方法 =>
使用Math.max
时,并没有先new
,而是直接调用了。
// 静态方法
console.log(Math.max(4, 5))
console.log(Math.random())
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.05
Branch: branch02commit description:a2.05(ES5中的类与继承——静态方法)
tag:a2.05
静态属性、方法 是定义在类下的,而实例属性定义在构造函数中
构造函数中的this
指向实例化对象,静态方法中this
指向当前构造函数,而非实例化对象,因此没有age
属性。
// 类
// 构造函数
function People(name, age) {
console.log(this)
// 实例属性
this.name = name
this.age = age
// 静态属性
People.count++
}
// 静态属性
People.count = 0
// 静态方法
People.getCount = function(){
console.log(this)
console.log(this.age) // undefined
console.log('当前共有' + People.count + '个人')
}
// 实例方法
People.prototype.showName = function () {
console.log('我的名字是' + this.name)
}
// 实例化对象
let p1 = new People('张三', 24)
console.log(p1)
p1.showName()
let p2 = new People('李四', 20)
console.log(p2)
p2.showName()
// 查看实例化次数
console.log(People.count)
People.getCount()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.06
Branch: branch02commit description:a2.06(ES5中的类与继承——静态属性、方法特点)
tag:a2.06
ES5
继承 =>
父类.call(this, 父类属性对应参数)
=> 构造函数继承
也可
Dog.prototype = deepCopy(Animal.prototype);
。注意这里必须进行深拷贝才行。
// 父类
function Animal(name) {
this.name = name
}
Animal.prototype.showName = function () {
console.log('名字是:' + this.name)
}
// 组合继承 => 属性 + 方法
// 子类
function Dog(name, color) {
Animal.call(this, name) // 继承属性
this.color = color
}
// 继承方法(原型继承)
Dog.prototype = new Animal()
Dog.prototype.constuctor = Dog
let d1 = new Dog('wangcai', 'white')
console.log(d1)
d1.showName()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.07
Branch: branch02commit description:a2.07(ES5中的类与继承——ES5继承)
tag:a2.07
4. ES6中的类与继承
es6
提供了关键字class
=> 声明类
class
的方式是 function
方式的语法糖。
虽然 ES6
在类的定义上仅是 ES5
定义类的语法糖,但是从开发者的角度而言,开发更有效率了,代码可阅读性大大提升。
关键字construct
=> 构造函数
方法直接定义在类中即可 =>
class People {
constructor(name, age) {
this.name = name
this.age = age
}
showName() {
console.log(this.name)
}
}
let p1 = new People('zhangsan', 30)
console.log(p1)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.08
Branch: branch02commit description:a2.08(ES6中的类与继承——ES6类基本使用)
tag:a2.08
综上class
关键字实际就是语法糖,实际还是function
。
es6
实现继承 => extends
关键字
继承父类属性 => super
class People {
constructor(name, age) {
this.name = name
this.age = age
}
showName() {
console.log(this.name)
}
}
let p1 = new People('zhangsan', 30)
console.log(p1)
class Coder extends People {
constructor(name, age, company) {
super(name, age)
this.company = company
}
showCompany() {
console.log(this.company)
}
}
let c1 = new Coder('lisi', 25, 'Tecent')
console.log(c1)
c1.showName()
c1.showCompany()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.09
Branch: branch02commit description:a2.09(ES6中的类与继承——ES6类继承)
tag:a2.09
之前的实例属性都是定义在construct
里的,实际在es6
中可把属性定义在类的最顶层,即在大括号里的第一层,而以上是construct
在大括号里的第二层了。
es6
中可把属性定义在类的最顶层 => 通过get
、set
关键字,相当于java
、c#
中set
、get
。
注意:set
函数不可以写成如下形式,会掉入死循环,不停地压栈,致使栈内存奔溃。
set sex(val) {
this.sex = val
}
应该直接return
。
实际一般都会在构造函数中设定set
对应属性的初始值,通过_sex
临时属性,set
的时候就可以直接this._sex = val
,get
的时候也获取它的值即可。
并且取值、赋值时,set
、get
相当于属性拦截,可引入业务逻辑操作 =>
class People {
constructor(name, age) {
this.name = name
this.age = age
this._sex = -1
}
get sex() { // 属性
if (this._sex === 1) {
return 'male'
} else if (this._sex === 0) {
return 'female'
} else {
return 'error'
}
}
set sex(val) { // 1:male 0:female
if (val === 0 || val === 1) {
this._sex = val
}
}
showName() {
console.log(this.name)
}
}
let p1 = new People('zhangsan', 30)
console.log(p1)
p1.sex = 5
console.log(p1.sex)
class Coder extends People {
constructor(name, age, company) {
super(name, age)
this.company = company
}
showCompany() {
console.log(this.company)
}
}
let c1 = new Coder('lisi', 25, 'Tecent')
console.log(c1)
c1.showName()
c1.showCompany()
c1.sex = 1
console.log(c1.sex)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.10
Branch: branch02commit description:a2.10(ES6中的类与继承——ES6类中的set与get)
tag:a2.10
静态方法 和 属性
静态 => 关键字static
class People {
constructor(name, age) {
this.name = name
this.age = age
this._sex = -1
}
get sex() { // 属性
if (this._sex === 1) {
return 'male'
} else if (this._sex === 0) {
return 'female'
} else {
return 'error'
}
}
set sex(val) { // 1:male 0:female
if (val === 0 || val === 1) {
this._sex = val
}
}
showName() {
console.log(this.name)
}
// 静态方法
static getCount() {
return 5
}
}
let p1 = new People('zhangsan', 30)
console.log(p1)
p1.sex = 5
console.log(p1.sex)
console.log(People.getCount())
class Coder extends People {
constructor(name, age, company) {
super(name, age)
this.company = company
}
showCompany() {
console.log(this.company)
}
}
let c1 = new Coder('lisi', 25, 'Tecent')
console.log(c1)
c1.showName()
c1.showCompany()
c1.sex = 1
console.log(c1.sex)
console.log(Coder.getCount())
子级也可以调用的到父级的静态方法。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.11
Branch: branch02commit description:a2.11(ES6中的类与继承——ES6类中的静态方法)
tag:a2.11
静态属性 => es6
明确规定在class
内部只能定义静态方法
,没有静态属性
。
class People {
constructor(name, age) {
this.name = name
this.age = age
this._sex = -1
}
static count = 0
get sex() { // 属性
if (this._sex === 1) {
return 'male'
} else if (this._sex === 0) {
return 'female'
} else {
return 'error'
}
}
set sex(val) { // 1:male 0:female
if (val === 0 || val === 1) {
this._sex = val
}
}
showName() {
console.log(this.name)
}
// 静态方法
static getCount() {
return 5
}
}
不支持在类内定义静态属性。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.12
Branch: branch02commit description:a2.12(ES6中的类与继承——不支持在类内定义静态属性)
tag:a2.12
静态属性实际和es5
一样,直接通过类名在类外定义即可。
class People {
constructor(name, age) {
this.name = name
this.age = age
this._sex = -1
}
get sex() { // 属性
if (this._sex === 1) {
return 'male'
} else if (this._sex === 0) {
return 'female'
} else {
return 'error'
}
}
set sex(val) { // 1:male 0:female
if (val === 0 || val === 1) {
this._sex = val
}
}
showName() {
console.log(this.name)
}
// 静态方法
static getCount() {
return 5
}
}
// 静态属性
People.count = 9
console.log(People.count)
console.log(typeof People) // function
let p1 = new People('zhangsan', 30)
console.log(p1)
p1.sex = 5
console.log(p1.sex)
console.log(People.getCount())
class Coder extends People {
constructor(name, age, company) {
super(name, age)
this.company = company
}
showCompany() {
console.log(this.company)
}
}
console.log(Coder.count)
let c1 = new Coder('lisi', 25, 'Tecent')
console.log(c1)
c1.showName()
c1.showCompany()
c1.sex = 1
console.log(c1.sex)
console.log(Coder.getCount())
可以看到虽然有了关键字class
,但还是基于function
原型的语法糖,底层还是es5
。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.13
Branch: branch02commit description:a2.13(ES6中的类与继承——静态属性)
tag:a2.13