手记

ES6之class

2020-04-20 14:15:191560浏览

今朝

1实战 · 8手记 · 4推荐


首先,我们需要知道class是用来干什么的?class是用来声明类的。每一种类都有自己的属性和行为。比如说,汽车,都能跑、有四个轮子等等。我有一辆车,那么我的车就是汽车这个类的一个实例对象。再比如说人类,人都有姓名、年龄,会说话,我是一个人,那我就是人类的一个对象实例。class的作用和构造函数一样都是用于创建对象的

那么在js中,我们都有哪些方法来创建对象呢?

第一种,使用字面量创建对象

let person = { 

    name: 'chen', 

    age: 29,

    say: function(){ 

        return 'I am a man'; 

    }

};

console.log(person.say());


使用字面量创建对象,优点在于结构清晰明了,代码量少,但是如果现在的需求是有张三、李四、王五三个人,每个人都有say函数,那么按照字面量的方式就需要将person复制出3份才行。必然会有很多的重复代码。

所以,我们还可以通过构造函数创建对象,使用new操作符创建对象,可以创建很多结构类似的对象

function Person(name, age) {

    this.name = name;

    this.age = age;

    this.say = function() {

        return 'I am a man';

    }

}

let person = new Person(‘chen’, 29);


当我们需要创建多个人的时候,只需要使用new关键字创建多个对象就可以了。

实际上构造器就是一个普通的函数。当使用new 操作符 来作用这个函数时,它就可以被称为构造函数

所以关键在于new操作符。

那么大家还记得new关键字的作用吗?这也是前端面试经常会问到的问题

如果不记得了,没关系,我们自己来写一个new函数来模拟new关键字的作用,

当我们使用new操作符创建对象的时候,new关键字会帮我们做一下的操作:

  1. 创建一个空的简单JavaScript对象(即{});

  2. 将步骤1中创建的对象的__proto__属性绑定到构造函数的prototype属性上 ;

  3. 将步骤1新创建的对象作为this的上下文 ;

  4. 如果该函数没有返回对象,则返回this。

我们可以自己来写一个new函数,同样可以达到new操作符做到的事情

function newFunc(Constructor, …args) {

    // 1.声明变量obj,赋值为空对象

      let obj = {};

      // 继承构造函数的原型

      obj.__proto__ = Constructor.prototype;

// 看到这里的同学可能又会对__proto__和prototype产生疑惑,它们有什么不同吗?

/*

 简单的说,每个对象都有一个__proto__属性,并且指向它的prototype原型对象

每个函数,也只有函数才会有prototype属性

看看上面的let obj = {},当我调用obj.toString()函数的时候,会报错吗,当然不会报错,可是我并没有定义toString函数啊,为什么没有报错呢?我们通过字面量创建的对象,我们可以认为就是使用new Object()来创建的,实际上Object就是一个函数,函数都会有prototype属性的,所以obj对象的__proto__属性会链接到Object函数的prototype属性上,当我们试图访问一个对象的属性时,它不仅仅在该对象上查找,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾也就是null,这就是js中的原型链的概念了,实际上toString函数就是在Object.prototype属性对象上找到的。*/

      // 3.将obj作为Constructor函数的this

    let result = Func.apply(obj, args);

    // 这里的apply就是用于改变Constructor函数的this的

    // 如果没有return则返回obj

    return result || obj;

}

let person = newFunc(Person, 'chen', 29);


现在我们再回到这个Person构造函数中,实际上,这个构造函数是有一点问题的,因为我们每new一个对象时,都会创建一个say函数,这样无疑会增加很多不必要的内存开销。

所以真实情况下,我们都会将函数属性添加到构造函数的原型上去,而不是在构造函数中声明。

function Person(name, age) {

    this.name = name;

    this.age = age;

}

Person.prototype.say = function() {

    return 'I am a man';

}

Let person = new Person();

Person.say();


现在,不管我们调用多少次new,say函数永远只会创建一个,如果一个构造函数有很多个函数属性,那么只需要在这个构造函数的prototype属性上添加函数就可以了。

我们可以看看这个写法,实际上不够优雅,有多个函数属性的时候,需要多次写prototype,而且一个构造函数,也是写的七零八落的。

所以ES6引入了Class(类)这个概念,通过class关键字可以定义类

如果要使用class实现刚刚的构造函数,要如何写呢,我们先使用class来实现,等会再来一一讲解。

class Person {

    constructor(name, age) {

        this.name = name;

        this.age = age;

    }

    

    say() {

        return 'I am a man';

    }

}

let person = new Person(‘chen', 29);


Person类中的constructor是一个构造方法,用来接收参数,在constructor之外的函数就是添加在在Person的原型上的。需要注意的是,使用class创建对象是,一定要加new操作符的,不然会报错,而使用构造函数没有加new操作符也不会报错。

但是,实际上class实际上就是 JavaScript 现有的基于原型的继承的语法糖,只是在构造函数的基础上进行了封装。之所以叫语法糖,是因为没有带来新的语言特性,只是基于之前的功能进行新的封装实现,让代码写起来更加简洁。就像加了糖的牛奶,喝起来味道更好。

像我们之前学习的对象解构、箭头函数等等都是语法糖。

接下来,我们来看看class基本语法

class关键字

类名,如果不写就是匿名类

一个类的类体是一对花括号 {} 中的部分。

constructor方法

是一个特殊的方法,这个方法用于创建和初始化一个由class创建的对象。在一个类中只能有一个构造函数。

有一点需要注意的是class的所有函数都是以严格模式下执行的,所以当this找不到时,this就是undefined

class Person {

    constructor(name, age) {

        this.name = name;

        this.age = age;

    }

    

    say() {

        return this.name;

    }

}

let person = new Person(‘chen', 29);

Let say = person.say;

say();


静态类型/方法

static关键字用来定义一个类的一个静态方法。调用静态方法不需要实力话该类,直接通过类名调用,但不能通过一个类实例调用静态方法。

class Person {

    static address = '地球'

    constructor(name, age) {

        this.name = name;

        this.age = age;

    }

    

    static say() {

        return 'I am a man';

    }

}

2人推荐
随时随地看视频
慕课网APP

热门评论

总结的很好

查看全部评论