Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

对比class与旧构造函数的区别 #39

Open
18888628835 opened this issue Jun 8, 2021 · 0 comments
Open

对比class与旧构造函数的区别 #39

18888628835 opened this issue Jun 8, 2021 · 0 comments

Comments

@18888628835
Copy link
Owner

前言

JavaScript是没有类这个概念的,区别于其他传统的强类型语言,例如Java,JS的类(构造函数)在设计根本上就有本质的不同,Java的类是代码的拷贝,而JS则用了原型链继承而已,所谓的构造函数只不过就是个普通函数,(只是大家习惯在使用时大写,这事也就成了规范)。

ES6的class本质上是构造函数的语法糖,只是这个语法糖写得更像是Java,为了做区分,我将在这篇博客上专门对比class和es5构造函数的不同写法

设置实例对象自身属性

构造函数写法

通过构造函数,我们能更了解JS的原型链设计原理,下面是构造函数的基本用法

function Person(name,age){
   this.name=name
   this.age=age
}
const p=new Person('jack',23)

class写法

class Person{
   constructor(name,age){
      this.name=name
      this.age=age
   }
}
const p=new Person('jack',23)

设置实例对象的共有方法

构造函数写法

Person.prototype={
   constructor:Person,
   fn1(){},
   fn2(){}
}

class写法

class Person{
   constructor(name,age){
   ...
   };
   fn1(){};
   fn2(){};
}

设置实例对象的自有方法

构造函数写法

function Person(name,age){
...
   this.saiHi=function(){console.log(this.name)}
}

class写法

class Person{
    name='';
    age='';
   constructor(name,age){
      ...
   };
   fn1(){};//prototype上的
   fn2(){};
   sayHi=function(){console.log(this.name)} //自有的
}

设置构造函数静态属性

构造函数的静态属性指的是构造函数自己能访问

构造函数写法

Person.prop1='staticProp1'
Person.prop2='staticProp2'

class写法

class Person{
   static prop1='staticProp1'
   static prop2='staticProp2'
   constructor(name,age){
      ...
   };
   fn1(){};//prototype上的
   fn2(){};
   sayHi=function(){console.log(this.name)} //自有的
}

设置构造函数静态方法

构造函数写法

Person.staticFn=function (){}

class写法

class Person{
...
   static staticFn=function(){}
   constructor(name,age){
      ...
   };
  ...
}

设置构造函数的私有字段

构造函数写法

function Person(name,age){
   let _selfName='123456' //构造函数私有属性,无法被外部直接访问
   let _selfFn=()=>{return _selfName} //构造函数私有方法,无法被外部直接访问
   this.saiHi=function(){console.log(_selfFn())} //实例的自有方法
}

在变量名前加_,这种写法是开发者自己定义的,用来区分一下私有字段

class写法

class Person{
   #selfName='123456'
   #selfFn=()=>{return this.#selfName}
   constructor(name,age){
      ...
   };
   sayHi=function(){console.log(this.#selfFn())}

class写法采用#关键字符来定义,如果想访问,需要加上this

由于私有字段无法直接访问,只好通过sayHi方法来变相访问了。

小结

构造函数写法

function Person(name,age){
   let _selfName='123456' //构造函数私有属性,无法被外部直接访问
   let _selfFn=()=>{return _selfName} //构造函数私有方法,无法被外部直接访问
   this.name=name //实例的自有属性
   this.age=age
   this.saiHi=function(){console.log(_selfFn())} //实例的自有方法
}
Person.prototype={ //实例的共有方法
   constructor:Person,
   fn1(){},
   fn2(){}
}
Person.prop1='staticProp1' //构造函数的自有属性
Person.prop2='staticProp2'
Person.staticFn=function (){} //构造函数的自有方法
const p=new Person('jack',23)

class写法

class Person{
    name='';//这里也可以写实例的属性
    age='';
   static prop1='staticProp1'//构造函数的自有属性
   static prop2='staticProp2'
   #selfName='123456'//构造函数私有属性,无法被外部直接访问
   #selfFn=()=>{return this.#selfName}//构造函数私有方法,无法被外部直接访问
   constructor(name,age){
      this.name=name//实例的自有属性
      this.age=age//实例的自有属性
   };
   fn1(){};//实例的共有方法
   fn2(){};//实例的共有方法
   sayHi=function(){console.log(this.#selfFn())}//构造函数的自有方法
}
const p=new Person('jack',23)

继承

构造函数写法

采用构造函数方法可以分成两步实现。

第一步是在子类的构造函数中,调用父类的构造函数。

function Super(name){
   this.name=name
}
function Sub(name,age){
   Super.call(this,name)
   this.age=age
}

上面代码中,Sub是子类的构造函数,this是子类的实例。在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性。

第二步,是让子类的原型指向父类的原型,这样子类就可以继承父类原型。

Super.prototype.sayHi=function (){console.log('hi')}
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;//这句可加可不加,建议加

要注意不要直接Sub.prototype=Super.prototype,这样虽然也是有用的,但是就相当于两个构造函数共用一个原型,万一以后修改Sub或者Super其中一个的原型就会影响双方。

最好的方法就是使用Object.Create直接改造子构造函数的原型,让子构造函数的__proto__连接到父构造函数的原型上。

class写法

class Person{
    name;
    age;
    constructor(name,age){
        this.name=name
        this.age=age
    }
    sayHi(){
        console.log(this.name)
    }
}
class Man extends Person{
    constructor(name,age,prop){
        super(name,age)//这里调用
        this.prop=prop
    }
}
const a=new Man('qiuyanxi',20,'帅')

class的形式非常方便,目前子类已经能使用父类的方法了,而且无需再去关联子类和父类的原型链,extends关键字已经帮我们做好了工作

Man.prototype.__proto__===Person.prototype //true
Man.__proto__ ===Person //true //注意,这是class自动实现的

class方法比ES5的方法多一种关系,ES5的方法并没有把子类的__proto__跟父类做关联,而class的写法则是自动做了关联。不过如果ES5想要实现的话也可以用Object.setPrototypeOf(Man,Person)关联

//传统ES5继承手动挡
//原来
Sub.__proto__ ===> Function.protoyype
Super.__proto__ ===> Function.protoyype
//使用Object.setPrototypeOf(Sub,Super)后
Sub.__proto__ ===>Super===>Super.__proto__===>Function.prototype
//使用Sub.prototype = Object.create(Super.prototype)后;
Sub.prototype.__proto__ ===> Super.prototype

总结

class的语法从未来来看,更多的新人朋友们可能会非常喜欢,这也非常符合学过JAVA的科班生,不过Js跟Java之间的差别还挺大的,还是建议能够在实践class的基础上,了解构造函数的工作原理,这能够帮助我们更好地理解Js这门不完美但是非常优秀的语言

参考文档

https://wangdoc.com/javascript/oop/prototype.html

https://wangdoc.com/es6/class-extends.html

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant