带你深入了解 JavaScript 中的 Class 类

JS只是利用了函数的一种特殊特性——所有的函数默认都会拥有一个名为 prototype 的公有并且不可枚举的属性,它会指向另一个对象,来模拟类的行为。

要注意的是,如果使用内置的 bind函数来生成一个硬绑定函数的话,该函数是没有 prototype 属性的,目标函数的 prototype 会代替硬绑定函数的 prototype。在这样的函数上使用 instanceof 或者new的话,相当于直接对目标函数使用。

function Animal() {};
console.log(Animal.prototype);// {}

在JS中,new Animal()看起来像是实例化了Animal类,但是事实上并非如此。

const a = new Animal();
console.log(Object.getPrototypeOf(a) === Animal.prototype);// true

在面向类的语言中,类可以被复制(或者说实例化)多次。实例化一个类就意味着“把类的行为复制到物理对象中”,对于每一个新实例来说都会重复这个过程。

但是在 JS 中,并没有类似的复制机制。你不能创建一个类的多个实例,只能创建多个对象,它们关联的是同一个对象。但是在默认情况下并不会进行复制,因此这些对象之间并不会完全失去联系,它们是互相关联的。

new Animal() 会生成一个新对象(我们称之为 a ),这个新对象的内部链接关联的是Animal.prototype 对象。我们并没有初始化一个类,实际上我们并没有从“类”中复制任何行为到一个对象中,只是让两个对象互相关联。

2.JS中的构造函数是什么?

function Animal() {};
const a = new Animal();

在JS中并没有真正的类,但是在看到这两行代码时,我依然会觉得Animal是一个类。这是为什么呢?在我看来,一个原因在于出现了new操作符,而在面向类的语言中,需要使用new操作符。

另一个原因是,在new Animal()中,Animal的调用方式特别像是调用方式很像实例化类时类构造函数的调用方式。

但是实际上,Animal和你程序中的其他函数没有任何区别。函数本身并不是构造函数,只是当我们在普通的函数调用前面加上new 关键字之后,就会把这个函数调用变成一个“构造函数调用”(new会劫持所有普通函数并用构造对象的形式来调用它) 。

简单地说,在JS中,“构造函数”可以解释为使用new操作符调用的函数。但是,我们需要知道的是,JS中的函数并不是构造函数,只有使用new时,函数调用会变成构造函数调用。

3.JS中的“面向类”

function Animal(name) {
    this.name = name;
}
Animal.prototype.sayName = function () {
    console.log(this.name);
};

const dog = new Animal('dog');
const cat = new Animal('cat');

dog.sayName(); // dog
cat.sayName(); // cat
console.log(dog.constructor); //  [Function: Animal]

1.this.name = name 通过this的隐式绑定给每个对象都添加了 name 属性,有点像类实例封装的数据值。
Animal.prototype.sayName = ... 会给 Animal.prototype 对象添加一个属性(函数)。

2.在创建的过程中, dog 和 cat 的内 ),这个新对象的内部链接都会关联到 Animal.prototype 上。当 dog和 cat 中无法找到 sayName 时,它会在 Animal.prototype 上找到。

需要注意的是,dog.constructor指向了Animal函数,所以dog的constructor属性,似乎在代表着dog是由谁构造的。

但是事实上,这仅仅是看起来如此,因为dog本身并没有constructor属性,constructor属性和sayName一样,同样是Animal.prototype 的属性,这个属性和dog(或者cat)之间没有什么联系。

对于Animal.prototype而言,constructor也仅仅是Animal函数在声明时所产生的一个默认属性而已(它是不可枚举的,但它是可以更改的)。

Animal.prototype.constructor = 'animal';
console.log(dog.constructor); // 'animal'

当改变Animal.prototype的指向时,constructor属性的指向同样变得令人迷惑。这是因为fish上不存在constructor属性,所以查找的是Animal.prototype(即{})上的constructor属性。

但是{}也没有constructor属性,所以会继续查找到Object.prototype 。这个对象有 constructor 属性,指向内置的 Object 函数。

Animal.prototype = {};
const fish = new Animal();
console.log(fish.constructor); // [Function: Object]

如果你想开发小程序或者了解更多小程序的内容,可以通过专业开发公司,来帮助你实现开发需求:厦门在乎科技-专注厦门小程序开发公司、APP开发、网站开发、h5小游戏开发

上一篇:SharePoint 环境配置加域提示网络名不可用[已解决]


下一篇:SharePoint 使用技巧汇总与讨论