面向对象
是一种思路。
面向对象编程三大优点:继承、封装、多态
// 产品:共性、个性
// 人:共性:头、一双手、一双脚、一双眼睛、鼻子、耳朵 {共性}
// 个性:性格、
在ES5之前,js【函数式编程】不是完成的支持面向对象写法【模拟】。
ES6之后新增了一个关键词:class
, 只是对上面ES5的写法在语言层面做了一定包装。
写面向对象:记住万物皆对象【类】。
类就相当于工厂,对象是工厂的产物。
创建类【构造函数】
// 创建类
class CName {
constructor () {
// 私有属性
// 初始化阶段需要做的事
}
// 共有方法
say () {
}
}
// 调用类去创建一个新对象
let cn = new CName()
上述的cn对象也叫做实例对象,new执行CName的过程叫做:实例化
constructor
ES6的面向对象中,constructor是用于存放"私有的"属性和方法,是类的初始化函数。
constructor之外的是共有的属性
new
new的作用:
- 在执行函数【类】时,函数内部会被new默认创建一个object对象【json】
- 函数【类】内的this默认就自动指向了该对象【new创建的这个】
- new执行完函数后,会将该对象作为函数【类】的默认返回值
原型
就是存储类上所有的公有方法的空间(是一个对象)。
在类发生继承行为时,主要就是继承【复制】原型(这个空间)
原型在哪
- 对象的
__proto__
属性可以指向该对象原型 - 从对象所对应的类的
prototype
属性也指向了由该类生产出的对象的原型
原型空间是一个“对象”
原型身上的constructor保存着对应类
JS中所有的数据[对象]都由对应的类所产生,所有的数据的祖先类Object
原型链
从对象身上,依次顺着原型向上查找,最终会查找到Object上。
静态方法
静态方法和私有方法以及公有方法主要区别:私有和公有的方法是被实例对象所对用。而静态方法是被类所调用。
class Fn {
// 这是Fn的静态方法
static fnName () {
}
}
// 调用只能通过Fn
Fn.fnName()
私有方法
ES6的class中,并没有语言层面的私有方法的定义方式。使用的是原型上的公有方法进行书写,书写时,命名使用业内约定俗成的写法:在方法名前面加上_
, 从本质上来说,加了下划线的"私有方法"跟原型上普通的公有方法没有任何区别。
继承
// 父类 基类
class Fn {
constructor (n) {
this.name = n
}
sayName () {
console.log(this.name)
}
}
// 父类的实例
let f1 = new Fn('afeng')
// f1.sayName()
// Fn为基类 Fn2子类
class Fn2 extends Fn{
constructor (n, age) {
// 继承基类this 子类在继承过程中,默认没有this
super(n)
// 在子类中新增的私有属性,不会影响父类
this.age = age
}
// 子类新增的公有方法,同样不会影响父类的公有方法
sayAge () {
console.log(this.age)
}
}
let f2 = new Fn2('ayu', 18)
// 子类继承了父类的原型方法,子类实例可以调用
f2.sayName()
继承时,父类静态方法会被继承
Object.getPrototypeOf()
此方法用于通过子类找到其所继承的父类
Object.getPrototypeOf(子类) // 返回对应的父类
可以用于判断一个类是否继承自另外一个类
super
子类内的super是一个特殊的存在,super既可以当作函数使用,也可以当作对象使用。在两种不同的使用环境中,它的含义不一样。
当作函数使用时:
代表父类、在ES6的继承中,规定必须在子类中调用以此super以便于让子类继承父类的this(因为子类默认没有this,子类想要有this只能调用super,此时super虽然代表父类,但是返回的却是子类的this)
当作对象使用时:
- 可以出现在任意函数内,如果出现在子类的原型方法中:此时super代表父类的原型
- 如果出现在子类的静态方法中,代表父类本身(可以调用父类的静态方法)
包装对象(跟面向对象没关系)
基础类型的值可以设置自定义属性,但是无法正常访问。
原因: 基础值类型数据【必须是字面量】都是不可变型
在对不可变型数据设置自定义属性时,不会报错(此时产生了一个包装对象【临时工】,以确保设置属性的动作正常完成(因为不正常完成会报错)),当设置属性这条代码执行结束后,临时工就下班了。设置的属性随机就丢弃了。