这篇笔记是单纯的用来加深自己写构造函数和使用构造函数的,但是我要是在工作中大脑又宕机了,也可以自己来复习一下。
es5
先贴下es5最基础的创建与使用的代码吧,这个不能忘记吧,这要是忘了,就可以转行了!
// 创建一个构造函数,这里本质上就是一个类
function People (name, age) {
this.name = name
this.age = age
}
// 这里给类添加一个方法,在他的原型链上添加,这样每个实例出来的对象都会拥有这个方法,这是继承
People.prototype.getMyName = function(){
console.log('这是一个实例方法')
console.log('我的名字叫'+this.name)
}
// 使用构造函数来获得一个实例化对象
let p1 = new People('wilson', 28)
console.log(p1)
// {age: 28,name: "wilson"}
p1.getMyName() // 继承方法的使用方式
// 这是一个实例方法
// 我的名字叫wilson
这里为啥在prototype里来创建方法呢?懒得说,听自己一句劝,这个要是忘了真别干了。
说到实例方法,还有一个静态方法,可以直接添加到构造函数上,上代码
// 除了在原型链上添加,在构造函数的本身也可以添加,但是这里的this指向就是构造函数了,而且也不需要使用实例化的对象,这里我们称为静态方法
People.getMyName = function(name){
console.log('这是一个静态方法,不需要创建实例,谁都可以调用哦~')
console.log('我的名字叫'+name)
}
People.getMyName('nameless') // 静态方法的使用方式
// 这是一个静态方法,不需要创建实例,谁都可以调用哦~
// 我的名字叫nameless
这个用的最多的就是Math了,比如Math.max(5,9)获取最大值,想起来了吧?静态方法可以直接使用,和实例对象没啥关系,两码事。
好了,主要说的是继承,上面的例子已经实现了实例对象对原型中实例方法的继承,那么,如果有两个类,一个父类,一个子类,子类创建了一个实例对象,怎么让当前实例对象既有子类的属性方法,又有父类的集成方法呢?
举一个例子,父类是动物,动物都有名字,年龄,但不一定都有毛,所以我们把毛这一独特属性放在子类里,比如子类是狗吧。然后我们实例出一条狗看看。
// 这是父类动物类
function Animal(name, age) {
this.name = name
this.age = age
}
// 这是子类狗类
function Dog(name, age, hairColor) {
Animal.call(this,name,age)
this.hairColor = hairColor
}
let g1 = new Dog('dahuang', 2, 'yellow')
console.log(g1)
// {name:'dahuang', age: 2, hairColor: 'yellow'}
可以看到,这里利用了call方法改变了this的指向,让Dog使用了Animal的方法,这样就实现了继承类的属性,而独特属性就由子类自己实例化。但是实例方法并不能因此继承,现在我在原先的代码基础上加上方法继承,看好了
// 这是父类动物类
function Animal(name, age) {
this.name = name
this.age = age
}
Animal.prototype.getMyName = function(){
console.log('我的名字叫' + this.name)
}
// 这是父类动物类
function Dog(name, age, hairColor) {
Animal.call(this,name,age)
this.hairColor = hairColor
}
Dog.prototype = new Animal() // 让子类prototype指向父类的原型实例,这样就可以使用父类的实例方法了
Dog.prototype.constructor = Dog // 这里需要把prototype的constructor指回自己的原型,避免原型链的紊乱。这样就简单的完成了子类继承父类的方法继承。
let g1 = new Dog('dahuang', 2, 'yellow')
g1.getMyName()
// 我的名字叫dahuang
看到了吧,getMyName方法是父类的,子类创建的实例可以使用父类的实例方法,备注写的清清楚楚了,不描述了。如果你还看不懂,说明你需要把原型链再复习一遍了。
es6
有空了再帮你回忆。。。
现在是2023/2/7 晚上20:48,现在开始整理一下es6怎样写构造函数,在es6中,他叫类,也有了自己的语法糖——class!
// 首先我要创建一个父类,就叫People吧
class People {
// 然后这里是类的属性,使用constructor关键字
constructor(name, age){
this.name = name
this.age = age
}
// 这里定义类的方法
getMyName(){
console.log('我的名字叫' + this.name)
}
}
let p1 = new People('wilson', 28)
console.log(p1) //{name: 'wilson', age: 28}
p1.getMyName() // 我的名字叫wilson
es6真的简写了好多啊,可读性也变高了。总结一下,属性放在constructor里,方法直接在类里创建,简单熬。接下来我们看一个东西
class People {
constructor(name, age, sex = '--'){
this.name = name
this.age = age
this.sex = sex
}
}
let p1 = new People('wilson', 28)
p1.sex = '男'
console.log(p1.sex) // 男
这里我们再定义一个sex属性,可以看到我们直接给属性赋值是可以改变的,但是这样在业务逻辑中太草率了,其实class中提供了更优雅的方式。
get和set
class People {
constructor(name, age, sex = '这是默认性别'){
this.name = name
this.age = age
this._sex = sex
}
get sex(){
return this._sex
}
}
let p1 = new People('wilson', 28)
console.log(p1.sex) // 这是默认性别
p1.sex = '女' // error,这里就已经报错了
console.log(p1.sex)
使用get可以使我们的sex成为只读属性,虽然sex后面有个括号,但是在使用时,他只是个属性,直接使用,不要加括号,然后在看一下set
class People {
constructor(name, age, sex = '这是默认性别'){
this.name = name
this.age = age
this._sex = sex
}
get sex(){
return this._sex
}
set sex(val){
this._sex = val
}
}
let p1 = new People('wilson', 28)
console.log(p1.sex) // 这是默认性别
p1.sex = '女'
console.log(p1.sex) // 女
使用set,给_sex赋值,这样sex成了既可读又可修改的属性。但是注意了,我操作的_sex都是带着下划线的_sex,我们不能直接操作set,必须有个新的变量来接受和修改,因为我们直接修改,会进入死循环,你修改sex,然后调用sex的set,给自己赋值,然后他又调用,又赋值,死循环了。
那么问题来了,我他妈是不是有病,直接用直接赋值不得了,为什么这么费劲多写这么多代码,不是说更优雅吗?
其实在业务场景中,后端更多的返回是一个字段的枚举,比如:1代表男,0代表女;也有可能会返回空字符串或者null,这样的话set和get就会体现出数据拦截和数据预处理的作用。举个例子,当前这个对象是一个user数据,status代表他的状态,0代表工作中,1代表请假
class People {
constructor(name, age, status){
this.name = name
this.age = age
this._status = status
}
get status(){
if(this._status == 0){
return '工作中'
}else if(this._status == 1){
return '请假'
}else{
return '暂无状态'
}
}
set status(val){
if(val == 0 || val == 1){
this._status = val
}
}
}
let p1 = new People('wilson', 28)
console.log(p1.status) // 暂无状态
// 这里假装ajax获取到了最新的user状态
let res = 1
p1.status = res
console.log(p1.status) // 请假
首先get帮助了我们将status默认为"暂无状态",然后我们赋值时,set帮助了我们过滤了非0和1的值,最后再次取值的时候get帮我们把值匹配了对应的字符串“请假”上。
那么es6怎样继承呢
class People {
constructor(name, age, status) {
this.name = name
this.age = age
this._status = status
}
get status() {
if (this._status == 0) {
return '工作中'
} else if (this._status == 1) {
return '请假'
} else {
return '暂无状态'
}
}
set status(val) {
if (val == 0 || val == 1) {
this._status = val
}
}
getMyName() {
console.log('我的名字叫' + this.name)
}
}
// 上面的例子保留,我们给People创建一个子类,叫Niuma
class Niuma extends People { // 这里用了一个关键词,extends就是继承的意思
// 同样是用constructor来构造属性
constructor(name, age, status, sex) {
// 需要继承的属性用super关键词,
super(name, age, status)
this.sex = sex
}
}
// 创建一个牛马
let n1 = new Niuma('wilson', 28, 0, '男')
console.log(n1) // {name: 'wilson', age: 28, _status: '', sex: '男'}
// 连stuts和方法都可以继承
console.log(n1.status) // 工作中
n1.getMyName() // 我的名字叫wilson
是不是一看就懂。啥都不用操作,直接extends一键继承。
然后看看静态属性和静态方法
class People {
static sayHello(){
console.log('hello world')
}
}
People.count = 3
People.sayHello() // hello world
console.log(People.count) // 3
既然是静态方法就不用创建实例,直接调用就可以了。需要注意的是静态方法需要static关键词打头,写在class里面,而静态属性和es5写法一样。
(写的差不多了,看的头疼就算了,反正你工作中也用不到)