没有合适的默认构造函数可用_前端面试必备:JavaScript中构造函数与class的区别总结

c8bca7cec9a3708211d52b868d3cd8d5.png

一、构造函数

首先,构造函数其实就是JavaScript程序中定义好的函数,我们可以直接使用。构造函数实际也是一种函数,它是专门用于生成定义对象,通过构造函数生成的对象,称为实例化对象。

构造函数分为两种,一种是JavaScript程序定义好的构造函数,我们成为称为内置构造函数,另外一种是程序员自己定义的构造函数,称为自定义构造函数。

构造函数虽然也是一种函数,但是和普通函数是区别的: 

1、构造函数一定要和关键词new一起使用,new关键词会自动的给构造函数定义一个对象,并且返回这个对象,我们只要对这个对象设定属性,设定方法就可以使用。  

2、构造函数为了和其他函数区别,语法规范规定构造函数的函数名称,第一个字母必须大写,使用大驼峰命名法。  

3、构造函数给对象定义属性和方法的语法,与一般函数不同

//自定义构造函数function Person(name,sex,age,addr){  // 定义属性  this.name = name;  this.sex = sex;  this.age = age;  this.addr = addr;  // 定义方法  this.fun = function(){    console.log(this.name,this.sex,this.age,this.addr);  }}// 生成实例化对象const person = new Person('终结者','男',28,'杭州');console.log(person); //输出实例化对象

普通构造函数实现继承

//普通构造函数继承//动物function Animal() {    this.eat = function () {        console.log('animal eat')    }} //狗function Dog() {    this.bark = function () {        console.log('dog bark')    }}//绑定原型,实现继承Dog.prototype = new Animal()//哈士奇var hashiqi = new Dog()
bd7ec2d3ec64af948bd788dcac3212ec.png

二、class

ES6构造函数语法:ES6与ES5构造函数语法对比,其功能作用完全相同,只是语法不同。ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

class Perosn{// ES6class方法定义构造函数  //constructor是构造器,定义实例化对象的属性和属性值, ()中的是参数  constructor (name,age,sex){    this.name = name;    this.age = age;   this.sex = sex;}  //定义方法,虽然没声明,但是也是定义在构造函数中的prototype中  printAll(){  console.log(this.name,this.age,this.sex);}}// 生成实例化对象const test = new Perosn('终结者','男',28,'杭州');console.log(person);//输出实例化对象person.printAll();  //输出方法

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数Person,对应ES6的Person类的构造方法。

定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。

Class实现继承

class Animal{    constructor(name){        this.name=name    }    eat(){        console.log(this.name +'eat');    }}class Dog extends Animal{    constructor(name){        super(name)//访问和调用Dog对象的父对象Animal上的函数。        this.name=name      // 在派生类中, 必须先调用 super() 才能使用 "this",忽略这个,将会导致一个引用错误。    }    bark(){        console.log(this.name+'bark');    }}const dog=new Dog("泰迪");dog.eat();dog.bark();

构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。

ES6中的class语法就是ES5中构造函数的另一种写法,一种更高级的写法,

class语法的底层还是ES5中的构造函数,只是把构造函数进行了一次封装而已。

ES6出现的目的为了让我们的让对象原型的写法更加清晰、在语法上更加贴合面向对象的写法、更像面向对象编程让JavaScript更加的符合通用编程规范,即大部分语言对于类和实例的写法,class实现继承更加容易理解,更易于后端语言使用。

42da65060e4e310b80d9162b0524d063.png

三、构造函数与Class的区别

  • Class 类中不存在变量提升

类不存在变量提升(hoist),这一点与 ES5 完全不同。

 // ES5var bar  = new Bar(); // 可行function Bar() {  this.bar = 42;}    //ES6const foo = new Foo(); // Uncaught ReferenceErrorclass Foo {  constructor() {    this.foo = 42;  }}
  • class内部会启用严格模式

类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。

// ES5function Bar() {  // 引用一个未声明的变量  baz = 42; // it's ok}var bar  = new Bar(); // ES6class Foo {  constructor(){    // 引入一个未声明的变量    fol = 42;    // Uncaught ReferenceError: fol is not defined  }}let foo = new Foo();
  • class的所有方法都是不可枚举的

ES6 中的 class,它的方法(包括静态方法和实例方法)默认是不可枚举的,而构造函数默认是可枚举的。细想一下,这其实是个优化,让你在遍历时候,不需要再判断 hasOwnProperty 了

// ES5function Bar() {}   Bar.answer = function () {};Bar.prototype.print = function () {};console.log(Object.keys(Bar));// ["answer"]console.log(Object.keys(Bar.prototype))// ["print"]// ES6class Foo {constructor(){}  static answer() {}  print(){}}console.log(Object.keys(Foo))// []console.log(Object.keys(Foo.prototype));// []
  • class 必须使用new调用

class 必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。

// ES5function Bar(){ }var bar = Bar();// it's ok;// ES6class Foo {}let foo = Foo();// Uncaught TypeError: Class constructor Foo cannot be invoked without 'new'
  • class 内部无法重写类名
// ES5 function Bar() {Bar = 'Baz';this.bar = 42;}var bar = new Bar();console.log(bar);// Bar {bar: 42}console.log(Bar);// 'Baz'// ES6class Foo {constructor(){this.foo = 42;Foo = 'Fol'; // Uncaught TypeError: Assignment to constant variable.}}let foo = new Foo();Foo = 'Fol';// it's ok
  • class 的继承有两条继承链

一条是:子类的__proto__指向父类

另一条:子类prototype属性的__proto__属性指向父类的prototype属性.

ES6的子类可以通过__proto__属性找到父类,而ES5的子类通过__proto__找到Function.prototype

// ES5function Super() {}function Sub() {}Sub.prototype = new  Super();Sub.prototype.constructor = Sub;var sub = new Sub();console.log( Sub.__proto__ === Function.prototype);// true// ES6class Super{}class Sub extends Super {}let sub = new Sub();console.log( Sub.__proto__ === Super);// true
  • ES5与ES6子类this的生成顺序不同。

ES5的继承是先建立子类实例对象this,再调用父类的构造函数修饰子类实例(Surper.apply(this))。

ES6的继承是先建立父类实例对象this,再调用子类的构造函数修饰this。即在子类的constructor方法中必须使用super(),之后才能使用this.

  • 正是因为this的生成顺序不同,所有ES5不能继承原生的构造函数,而ES6可以继承
// ES5function MyES5Array() {Array.apply(this, arguments);  // 原生构造函数会忽略apply方法传入的this,  //即this无法绑定,先生成的子类实例,拿不到原生构造函数的内部属性。}MyES5Array.prototype = Object.create(Array.prototype, {constructor: {    value: MyES5Array,    writable: true,    configurable: true,    enumerable: true   }})var arrayES5 = new MyES5Array();arrayES5[0] = 3;console.log(arrayES5.length);// 0 arrayES5.length = 0;console.log(arrayES5[0]);// 3// ES6class arrayES6 extends Array {constructor(...args){super(...args);}}let arrayes6 = new arrayES6();arrayes6[0] = 3;console.log(arrayes6.length);// 1arrayes6.length = 0;console.log(arrayes6[0]);// undefined
  • ES6可以继承静态方法,而构造函数不能
  • class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]],不能使用new来调用。

需要注意一点:

ES6的class语法无法执行预解析,是不能被提前调用;

ES5的function函数可以提前调用,但是只能调用属性不能调用方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值