function Person(name) {
this.name = name;
}
Person.prototype.say = function() {
console.log(`I'm ${this.name}`);
}
const xiaoming = new Person('xiaoming');
xiaoming.say();
// 输出
// I'm xiaoming
function _new(fn, ...args) {
// 基于fn的原型创建一个新的对象
const emptyObj = Object.create(fn.prototype);
// 添加属性到新创建的emptyObj上, 并获取fn函数执行的结果.
const newObj = fn.apply(emptyObj, args);
// 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
return newObj instanceof Object ? newObj : emptyObj;
}
const xiaohong = _new(Person, 'xiaohong');
xiaohong.say();
// 输出
// I'm xiaohong
注意
这里使用构造函数的方式定义,不要使用class的方式定义,如下:
class Person {
constructor(name) {
this.name = name;
}
say() {
console.log(this.name);
}
}
const xiaoming = new Person('xiaoming');
xiaoming.say();
function _new(fn, ...args) {
const emptyObj = Object.create(fn.prototype);
const newObj = fn.apply(emptyObj, args);
return newObj instanceof Object ? newObj : emptyObj;
}
const xiaohong = _new(Person, 'xiaohong');
xiaohong.say();
// /data/161414204943248864.js:19
// const newObj = fn.apply(emptyObj, args);
// ^
// TypeError: Class constructor Person cannot be invoked without 'new'
// at _new (/data/161414204943248864.js:19:23)
// at Object. (/data/161414204943248864.js:23:18)
// at Module._compile (internal/modules/cjs/loader.js:776:30)
// at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
// at Module.load (internal/modules/cjs/loader.js:653:32)
// at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
// at Function.Module._load (internal/modules/cjs/loader.js:585:3)
// at Function.Module.runMain (internal/modules/cjs/loader.js:829:12)
// at startup (internal/bootstrap/node.js:283:19)
// at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
原因
虽然class和es5中的构造函数创建的对象,在使用上是一样的,但是还是有些不同的,在报错中很明显可以看出fn.apply这里出错了。注意下面不同的最后两点。
class和es5构造函数的区别
- class在语法上更加贴合面向对象的写法, Class实现继承更加易读、易理解
- class声明内部会启用严格模式
- class的所有方法都是不可枚举的
- class的所有方法都没有原型对象prototype
- class定义的类不能被当做函数调用
网友评论