function实现class

165 阅读2分钟

将下面的代码使用function实现一遍:

class Person {
  constructor(name) {
    this.name = name;
  }

  getName() {
    console.log(this.name);
  }
}

使用function可以有简单的如下实现:

function myPerson(name) {
  this.name = name;
}

myPerson.prototype.getName = function () {
  console.log(this.name);
};

接下来可以考虑一下,class的特性,为其实现添砖加瓦

  1. class是ES6的特性,是在严格模式下执行的,在行首加入如下内容:
`use strict`;
  1. function可以直接调用,但class不可以直接调用,只能使用new来进行调用,直接调用class看会出现什么结果:
Person("小李");

运行结果:

TypeError: Class constructor Person cannot be invoked without 'new'

处理一下上面的问题,我们知道,class只能使用new调用,new的话会创建一个构造函数的实例,同时会改变this的指向,验证this的指向即可:

function myPerson(name) {
  // 验证this指向
  if (!(this instanceof myPerson)) {
    throw new TypeError(
      "Class constructor Person cannot be invoked without `new`"
    );
  }
  this.name = name;
}

myPerson('小李')
  1. class实例中的function是不可被枚举的,而function实例中的是可以的:
const p1 = new Person("class");
const p2 = new myPerson("function");

for (let key in p1) {
  console.log("class:", key);
}

console.log("------------------------");

for (let key in p2) {
  console.log("function:", key);
}

运行结果如下:

class: name
------------------------
function: name
function: getName

那么需要将myPerson原型上的挂载的方法设置成不可枚举:

Object.defineProperty(myPerson.prototype, "getName", {
  value: function () {
    console.log(this.name);
  },
  enumerable: false,
});
  1. 在JavaScript中只要是function都可以使用new来调用,但class中定义的function不行:
new p1.getName();

执行结果:

new p1.getName();
^

TypeError: p1.getName is not a constructor

同样验证this指向即可,如果this在原型链上找不到的话,那么就是使用了一些奇怪的方式调用这个function

Object.defineProperty(myPerson.prototype, "getName", {
  value: function () {
    if (!(this instanceof myPerson)) {
      throw new TypeError("getName is not a constructor");
    }
    console.log(this.name);
  },
  enumerable: false,
});

new p2.getName();

完整代码:

`use strict`;
function myPerson(name) {
  // 验证this指向
  if (!(this instanceof myPerson)) {
    throw new TypeError(
      "Class constructor Person cannot be invoked without `new`"
    );
  }
  this.name = name;
}

Object.defineProperty(myPerson.prototype, "getName", {
  value: function () {
    if (!(this instanceof myPerson)) {
      throw new TypeError("getName is not a constructor");
    }
    console.log(this.name);
  },
  enumerable: false,
});