第十一题:class 用 ES5 实现
KieSun opened this issue · comments
function Animal(name) {
this.name = name;
}
Animal.prototype.bark = function (msg) {
console.log(`${this.name}'s bark: ${msg}`);
};
function Cat(name, color) {
this.color = color;
Animal.call(this, name);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.getColor = function () {
console.log(`${this.name}'s color: ${this.color}`);
};
const tom = new Cat("tom", "red");
tom.bark("miao, miao");
tom.getColor();
// tom's bark: miao, miao
// tom's color: red
// class只可以用new来创建,不可以直接使用
function chunk(obj, constructor) {
if (!(obj instanceof constructor)) {
throw new Error('class只可以用new来调用');
}
}
// class内部定义的方法都是不可枚举的
function defindProperties(target, descriptors) {
for (let desc of descriptors) {
desc.enumerable = desc.enumerable || false;
desc.configurable = true;
if ('value' in desc) {
desc.writable = true;
}
Object.defineProperty(target, desc.key, desc);
}
}
// 构造class
function _createClass(constructor, protoDesc, staticDesc) {
// class内部定义的方法
protoDesc && defindProperties(constructor.prototype, protoDesc);
// class内部定义的静态方法
staticDesc && defindProperties(constructor, staticDesc);
return constructor;
}
const Fn = function () {
function Fn(prop) {
chunk(this, Fn);
this.prop = prop;
}
_createClass(
Fn,
[
{
key: 'show',
value: function () {
console.log(this.prop);
},
},
],
[
{
key: 'show',
value: function () {
console.log('static show', this.prop);
},
},
]
);
return Fn;
}();
根据大佬的实现补习了很多边边角角的属性知识
var Person = (function () {
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
return Person;
})();
var Man = (function () {
function Man(name, height) {
Person.call(this, name);
this.height = height;
}
Man.prototype = new Person();
Man.prototype.construcor = Man;
Man.prototype.getHeight = function () {
return this.name + " " + this.height;
};
return Man;
})();
var man = new Man("张三", 13);
console.log(man.getName());
console.log(man.getHeight());
// class 用 ES5 实现
function A(name) {
this.name = name
}
A.prototype.say = function(word) {
console.log(`${this.name} say ${word}!`)
}
A.prototype.run = function() {
console.log('run!')
}
function B(name) {
A.call(this, name)
this.type = 'B'
}
B.prototype = new A()
B.prototype.run = function() {
console.log(`${this.name} run!`)
}
B.prototype.self = function() {
console.log(this.type)
}
B.prototype.constructor = B
const b = new B('bbbb')
b.say('1231232')
b.run()
b.self()
function defineProperty(constructor, protoProperties) {
if(Array.isArray(protoProperties)) {
for (let i = 0; i < protoProperties.length; i++) {
const {key,...config} = protoProperties[i];
Object.defineProperty(constructor.prototype, key,{
configurable:true,
enumerator: false,
...config
})
}
}
}
const Animal = (function() {
function _CreateClass(name) {
if(!(this instanceof Animal)) {
throw TypeError('Class constructor a cannot be invoked without new')
}
this.name = name;
}
defineProperty(_CreateClass, [{
key: 'sex',
value: '男'
},{
key: 'getName',
value: function() {
return this.name;
}
}]);
return _CreateClass;
})()
// 不可枚举
console.log(Object.keys(Animal.prototype));
let animal = new Animal('动物');
console.log(animal.getName());
console.log(animal.sex);
// 不可单独使用
console.log(Animal());
ES5 模拟 Class 与 extends 继承
- 工厂函数
_extends_
- 将父类
prototype
与 子类prototype
相连接
function _extends_(proto) {
function F() {}
F.prototype = proto;
return new F();
}
function Parent(name) {
this.name = name;
}
Parent.prototype.construtor = Parent;
Parent.prototype.getName = function () {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = _extends_(Parent.prototype);
Child.prototype.construtor = Child;
Child.prototype.getAge = function () {
console.log(this.age);
};
const parent = new Parent("Turdyden");
parent.getName();
const child = new Child("Tanwen", 18);
child.getName();
child.getAge();
输出:
Turdyden
Tanwen
18
ecmaScript 2015 新增class,要实现几个点
- 需要 new 创建 因此要有构造函数
- 类的方法属性需要设置成不可枚举
- 子类可以继承父类的原型链和静态方法
//✅需要有构造函数
function ckTYpe(obj,constructor) {
if(!(obj instanceof constructor)) throw new Error('error')
}
// ✅设置参数不可枚举
function kk (tar, des) {
for (let dr of des) {
dr.enumerable = dr.enumerable || false //设置不可枚举
dr.configurable = true
if ('value' in dr) {
dr.writable = true
}
Object.defineProperty(tar, dr.key, dr)
}
}
function create (con, neBu, static) {
neBu && kk(con.prototype, neBu)//设置内部函数不可枚举
static && kk(con, static)//设置方法不可枚举
return con
}
const Foo = function () {
function Foo(name) {
ckTYpe(this, Foo) // 先检查是不是new调用的
this.name1 = name
}
return create (Foo, [ // 表示在class内部定义的方法
{
key: 'say',
value: function () {
console.log(this.name1,'hhhhhp')
}
}
],[ // 表示在class内部定义的静态方法
{
key: 'say',
value: function () {
console.log('static say')
console.log(this.name)
}
}
])
}()
// ==================子类开始======================================
//父类原型方法被子类继承
function _inherits(cld, par) {
if (typeof par !== 'function' && par !== null) {
throw new TypeError('Super expression must either be null or a function, not')
}
//✅子类继承父类的
cld.prototype = Object.create(par && par.prototype, {
constructor: {
value: cld,
enumerable: false,
writable: true,
configurable: true
}
})
if (par) {
Object.setPrototypeOf ? Object.setPrototypeOf(cld, par) : cld.__proto__ = par
}
}
// 返回父类的this;若为null,则返回自身
function pos(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised")
}
return call && (typeof call === 'object' || typeof call === 'function') ? call : self
}
const Child = function (_Parent) {
_inherits(Child, _Parent) // 继承父类原型上的属性及静态方法的继承
function Child(name, age) {
ckTYpe(this, Child)//先检查是否能被new
// 先使用父类实例对象this,再返回
const _this = pos(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name)) //获取
_this.age = age
return _this
}
return Child
}(Foo)
// ==========================================
const foo = new Foo('aaa')
console.log(foo);
console.log(foo.say());//父类实例待调用内部方法
console.log(Child.say());// 子类继承父类的原型name1
const chid1 = new Child('小明', 12)
console.log(chid1);
console.log(chid1.say());
// class 使用 ES5 来实现。
// ES6 class
// class SuperType {
// static staticFn() {
// console.log('this is SuperType static function');
// }
// constructor(name) {
// this.name = name;
// }
// say() {
// console.log(`this is SuperType prototype function: name is ${this.name}`);
// }
// }
// // ES6 extends
// class SonType extends SuperType {
// constructor(name, type) {
// super(name);
// this.type = type;
// }
// sonSay() {
// console.log(`this is sonType prototype function: name is ${this.name}`);
// }
// }
// ES5 class
function SuperType(name) {
this.name = name;
}
SuperType.staticFn = function () {
console.log('this is SuperType static function');
};
SuperType.prototype.say = function () {
console.log(`this is SuperType prototype function: name is ${this.name}`);
};
// ES5 extends
function SonType(name, type) {
SuperType.call(this, name);
this.type = type;
}
// Object.create() polyfill
function object(prototype) {
function F() {}
F.prototype = prototype;
return new F();
}
SonType.prototype = object(SuperType.prototype);
SonType.prototype.constructor = SonType;
SonType.prototype.sonSay = function () {
console.log(`this is sonType prototype function: name is ${this.name}`);
};
var sup = new SuperType('super');
console.log(sup);
SuperType.staticFn();
console.log(sup.name);
sup.say();
var sonType = new SonType('son', 'sonType');
console.log(sonType);
// 寄生式组合继承
function Person(color) {
this.color = color
}
Person.prototype.getColor = function() {
console.log(this.color)
}
function Student(name, age, color) {
this.age = age
this.name = name
// 即使是引用类型也不会共享
Person.call(this, color)
}
// function object(o) {
// function F() {}
// F.prototype = o
// return new F()
// }
function inhertPrototype(student, person) {
// 让Student.prototype的)__proto__指向Person.prototype
// const prototype = object(person.prototype)
const prototype = Object.create(person.prototype)
Object.defineProperty(prototype, 'constructor', {
configurable: false,
value: Student
})
Student.prototype = prototype
}
inhertPrototype(Student, Person)
Student.prototype.say = function() {
console.log(this.age)
}
const stu = new Student('ceshi', 28, ['red', 'block'])
console.log(stu)
// class 使用 ES5 来实现。
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
// 关键的三步
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
var child1 = new Child('kevin', '18');
console.log(child1);
https://zhuanlan.zhihu.com/p/274856925
个人感觉写的不错,为了不误导大家 放个连接大家自行学习
const define = (target, properties) => {
properties.forEach((property) => {
const { key, ...restConfig } = property;
Object.defineProperty(target, key, {
enumerable: false,
configurable: true,
...restConfig,
});
});
};
const defineProperty = (constructor, protoProperties, staticProperties) => {
// 定义原型上的属性和方法
if (Array.isArray(protoProperties)) {
define(constructor.prototype, protoProperties);
}
// 定义静态属性和方法
if (Array.isArray(staticProperties)) {
define(constructor, staticProperties);
}
};
const MyClass = function (protoProperties = [], staticProperties = []) {
function ClassModal() {
if (!(this instanceof ClassModal)) {
throw TypeError(`Class constructor An cannot be invoked without 'new'`);
}
}
// 定义原型上的属性和静态属性
defineProperty(ClassModal, protoProperties, staticProperties);
return ClassModal;
};
const Animal = MyClass(
[
{
key: "age",
value: 10,
},
{
key: "eat",
value: function () {
console.log("eat");
},
},
],
[
{
key: "chineseName",
value: "佳佳",
},
{
key: "like",
value: function () {
console.log("吃竹子");
},
},
]
);
let animal = new Animal();
console.log(animal.age, "animal.age------"); // 10 "animal.age------"
console.log(animal.eat, "animal.eat------");
/* ƒ () {
console.log("eat");
} "animal.eat------" */
console.log(Animal.chineseName, "Animal.chineseName------"); // 佳佳 Animal.chineseName------
const Person = MyClass(
[
{
key: "name",
value: "张三",
},
{
key: "say",
value: function () {
console.log("say");
},
},
],
[
{
key: "id",
value: "555",
},
]
);
let person = new Person();
console.log(person.name, "person.name------"); // 张三 person.name------
console.log(Person.id, "Person.id------"); // 555 Person.id------
触及知识的盲区,直接写了个用例babel转义扒代码来看(附备注)
/**
* class类使用提前必须是new调用,否则应该报错。
* 这里可以用此区分于「构造函数」,构造函数可以当成普通函数使用
*
* @param {*} instance
* @param {*} Constructor
*/
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
/**
* Object.defineProperty() 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
* 此处作用:用于处理类的内部所有定义的方法不可枚举的特性。
*/
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) {
defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
defineProperties(Constructor, staticProps);
}
return Constructor;
};
}();
/**
* 创建class
*/
var testFn = function () {
function testFn() {
_classCallCheck(this, testFn);
// 这里就是constructor
this.name = 'John';
this.gender = 1;
}
// 数组定义的key是函数方法名,value为处理过程/结果,可直接修改,可return返回
_createClass(testFn, [{
key: 'changeName',
value: function turnOffPreferFuture() {
this.name = 'Mary';
}
}, {
key: 'getGender',
value: function getTimeBase() {
return this.gender;
}
}]);
return testFn;
}();
- 原型继承
- 静态方法继承
- 构造函数继承
function inherit(Sub, Sup) {
// 1、原型继承
const prototype = new Sup()
Sub.prototype = prototype
Sub.prototype.constructor = Sub
// 2、静态属性继承
Sub.__proto__ = Sup
}
function SupType(name) {
this.name = name
this.colors = ['red']
}
SupType.getDefaultValue = function() {
return 'defaultValue'
}
SupType.prototype.getName = function(){
return this.name
};
inherit(SubType, SupType)
function SubType(name,age) {
this.age = age
// 3、构造函数继承
SupType.call(this, name)
}
SubType.prototype.getAge = function() {
return this.age
}
const sub = new SubType('streetex', 25)
没时间了,改天优化,早睡早起
var createClassHelper = {
checkIsNew: function(ins, cl){
if(!(ins instanceof cl)){
throw new TypeError("Class constructor " + cl.name + " cannot be invoked without 'new'")
}
},
setEnumerable(target, props){
var keys = Object.getOwnPropertyNames(props)
for(var i = 0, len = keys.length;i < len; i++){
var key = keys[i]
var value = props[key]
Object.defineProperty(target, key, {
value: value,
enumerable: false
})
}
}
}
var Hp = (function(superClass){
function Hp(){
createClassHelper.checkIsNew(this, Hp)
}
// if('function' === typeof superClass){}
Hp.prototype = {}
// 定义原型
createClassHelper.setEnumerable(Hp.prototype, {
hahaha: function hahaha(){},
isMe: true
})
// 静态变量
createClassHelper.setEnumerable(Hp, {
TYPE: 'HP'
})
return Hp
}(Anam2))
function Parent(age) {
this.age = age
}
function Chlid(name,age) {
Parent.call(this,age)
this.name = name
}
Chlid.prototype = Object.create(Parent.prototype)
Chlid.prototype.constructor = Child
const MyClass = (function () {
function MyClass(args) {
if (!(this instanceof MyClass)) {
throw new TypeError(
"Class constructor MyClass cannot be invoked without 'new'"
);
}
this.args = args;
}
let staticMethods = [
{
key: "staticFunc",
value: function () {
console.log(this.args);
},
},
];
let methods = [
{
key: "func",
value: function () {
console.log(this.args);
},
},
];
defineProperties(MyClass, staticMethods);
defineProperties(MyClass.prototype, methods);
function defineProperties(target, descriptors) {
for (let descriptor of descriptors) {
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return MyClass;
})();
function Parent (name) {
this.name = name;
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name) {
Parent.call(this, name);
}
// 关键的三步
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
function Father(name){
this.name = name
}
Father.staticFatherValue = 'staticFatherValue'
Father.prototype.sayName = function() {
console.log(this.name)
}
function Child(name, age) {
Father.call(this, name)
this.age = age
}
Child.prototype = Object.create(Father.prototype, {
constructor: {
value: Child,
configurable: false,
enumerable: false,
writeable: false
}
})
Child.prototype.sayAge = function(){
console.log(this.age)
}
// 继承静态属性
Child.__proto__ = Father
let child = new Child('Amy', 7)
child.sayName() //Amy
child.sayAge() // 7
console.log(Child.staticFatherValue) // staticFatherValue
function Parent (name, actions) {
this.name = name
this.actions = actions
}
Parent.prototype.getName = function () {
console.log(this.name + '调用了getName');
}
function Child() {
Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const c1 = new Child('xsh', ['eat']);
方法一 借助Babel转义实现
能力实在有限,感觉自己完全写不出来这种问题,手写Class 完全是自己的知识盲区
后面有能力会再写方法和具体实现方式讲解,写在后面更新
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
var Parent = /*#__PURE__*/ (function () {
function Parent() {
_classCallCheck(this, Parent);
_defineProperty(this, "name", 123);
}
_createClass(Parent, [
{
key: "getName",
value: function getName() {
console.log(this.name);
}
}
]);
return Parent;
})();
var child = new Parent();
console.log(child.getName());
function Father() {}
funciton Son() {
Father.call(this);
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;