inherits-ex
Advanced tools
Comparing version 1.3.6 to 1.4.0
@@ -6,2 +6,16 @@ module.exports = extend; | ||
/** | ||
* Copies properties from one or more source objects to a target object. | ||
* | ||
* The extend function takes an object target as its first argument, and any | ||
* number of additional objects as subsequent arguments. It copies all properties | ||
* from each source object to the target object, and returns the modified target object. | ||
* | ||
* Only copies properties that are directly on the source object (not inherited). | ||
* | ||
* @param {Object} target - The target object to copy properties to. | ||
* @param {...Object} sources - One or more source objects to copy properties from. | ||
* @returns {Object} The modified target object. | ||
*/ | ||
function extend(target) { | ||
@@ -8,0 +22,0 @@ for (var i = 1; i < arguments.length; i++) { |
var createFunction = require('./createFunction'); | ||
var isString = function(v){return typeof v === 'string';}; | ||
//create a contructor function dynamically. | ||
module.exports = function(name, args, body) { | ||
/** | ||
* Creates a constructor function dynamically with the given name, arguments, and body. | ||
* If the arguments are a string, it is assumed to be the body and the arguments are set to an empty array. | ||
* If the body is null or undefined, a default body is created that calls the parent constructor. | ||
* | ||
* @param {string} name - The name of the constructor function. | ||
* @param {Array|string} args - The arguments of the constructor function. | ||
* @param {string|null|undefined} body - The body of the constructor function. | ||
* @returns {Function} - The constructor function. | ||
*/ | ||
function createCtor(name, args, body) { | ||
if (isString(args)) { | ||
@@ -10,4 +19,7 @@ body = args; | ||
} | ||
if (body == null) body = 'return ' + name + '.__super__.constructor.apply(this, arguments);' | ||
var parentPrototype = '(' + name + '.__super__||Object.getPrototypeOf(' + name + ').prototype)'; | ||
if (body == null) body = 'var p=' + parentPrototype + ';return p?p.constructor.apply(this, arguments):undefined;' | ||
return createFunction(name, args, body); | ||
}; | ||
module.exports = createCtor |
@@ -18,3 +18,16 @@ //Write by http://stackoverflow.com/users/1048572/bergi | ||
module.exports = function(name, args, body, scope, values) { | ||
/** | ||
* Creates a new function with the given name, arguments, body, scope, and values. | ||
* | ||
* @param {string} name - The name of the function. | ||
* @param {string|string[]} args - The argument names of the function if it's `string[]`, else it's the function body without arguments. | ||
* @param {string} body - The body of the function. | ||
* @param {string[]|Object=} scope - The scope of the function. | ||
* @param {Array=} values - The values of the `scope` if the `scope` is `string[]``. | ||
* @returns {Function} - The created function. | ||
* | ||
* @example | ||
* var fn = createFunction('yourFuncName', ['arg1', 'arg2'], 'return log(arg1+arg2);', {log:console.log.bind(console)}); | ||
*/ | ||
function createFunction(name, args, body, scope, values) { | ||
if (arguments.length === 1) return Function('function ' + name + '(){}\nreturn ' + name + ';')(); | ||
@@ -39,4 +52,7 @@ if (isString(args)) { | ||
} | ||
if (typeof body !== 'string') body = '' | ||
return Function(scope, | ||
'function ' + name + '(' + args.join(', ') + ') {\n' + body + '\n}\nreturn ' + name + ';').apply(null, values); | ||
}; | ||
module.exports = createFunction |
@@ -7,3 +7,20 @@ var setPrototypeOf = require('./setPrototypeOf'); | ||
module.exports = function(aClass) { | ||
/** | ||
* Creates a new instance of the given class using the specified arguments. | ||
* @param {Function} aClass - The class to instantiate. | ||
* @param {...*} args - The arguments to pass to the constructor of the class. | ||
* @returns {*} - A new instance of the class. | ||
* @example | ||
* // Define a class | ||
* class Person { | ||
* constructor(name, age) { | ||
* this.name = name; | ||
* this.age = age; | ||
* } | ||
* } | ||
* // Create a new instance of the Person class | ||
* const john = createObject(Person, 'John', 30); | ||
* console.log(john); // Output: Person { name: 'John', age: 30 } | ||
*/ | ||
function createObject(aClass) { | ||
var result = new (Function.prototype.bind.apply(aClass, arguments)); | ||
@@ -40,1 +57,2 @@ if (aClass !== Object && aClass !== Array && aClass !== RegExp) { | ||
module.exports = createObject |
@@ -6,3 +6,23 @@ var hasNativeReflect = require('./isNativeReflectConstruct').hasNativeReflect | ||
module.exports = function(aClass, aArguments) { | ||
/** | ||
* Creates a new instance of the given class using the specified arguments. | ||
* | ||
* @param {function} aClass - The class to create an instance of. | ||
* @param {Array} aArguments - Arguments to pass to the class constructor. | ||
* @returns {object} A new instance of the class. | ||
* | ||
* @example | ||
* // Define a class | ||
* class Person { | ||
* constructor(name, age) { | ||
* this.name = name; | ||
* this.age = age; | ||
* } | ||
* } | ||
* | ||
* // Create a new instance of the Person class | ||
* const john = createObjectWith(Person, ['John', 30]); | ||
* console.log(john); // Output: Person { name: 'John', age: 30 } | ||
*/ | ||
function createObjectWith(aClass, aArguments) { | ||
var args = [aClass]; | ||
@@ -40,1 +60,3 @@ if (aArguments) | ||
}; | ||
module.exports = createObjectWith |
@@ -1,52 +0,86 @@ | ||
(function() { | ||
var defineProperty, isObject; | ||
var _defineProperty = Object.defineProperty; | ||
isObject = function(o) { | ||
return o && typeof o === 'object'; | ||
if (!_defineProperty) { | ||
_defineProperty = function(obj, key, descriptor) { | ||
var value; | ||
if (descriptor) { | ||
value = descriptor.value; | ||
} | ||
obj[key] = value; | ||
return obj; | ||
}; | ||
} | ||
defineProperty = Object.defineProperty; | ||
if (!defineProperty) { | ||
defineProperty = function(obj, key, descriptor) { | ||
var value; | ||
if (descriptor) { | ||
value = descriptor.value; | ||
} | ||
obj[key] = value; | ||
}; | ||
} | ||
module.exports = function(object, key, value, aOptions) { | ||
var descriptor, isAccessor, writable; | ||
writable = true; | ||
descriptor = { | ||
configurable: true, | ||
enumerable: false | ||
}; | ||
if (aOptions) { | ||
descriptor.enumerable = aOptions.enumerable === true; | ||
descriptor.configurable = aOptions.configurable !== false; | ||
if (aOptions.get) { | ||
isAccessor = true; | ||
descriptor.get = aOptions.get; | ||
} | ||
if (aOptions.set) { | ||
isAccessor = true; | ||
descriptor.set = aOptions.set; | ||
} | ||
writable = aOptions.writable !== false; | ||
if (value === void 0) { | ||
value = aOptions.value; | ||
} | ||
/** | ||
* Define the object's property and value. The property is not enumerable | ||
* by default. | ||
* | ||
* @param {object} object The object to define the property on. | ||
* @param {string} key the property name. | ||
* @param {*} value the property value. | ||
* @param {*} aOptions the property descriptor. | ||
* @param {boolean} [aOptions.enumerable=false] - Whether the property is enumerable. | ||
* @param {boolean} [aOptions.configurable=true] - Whether the property is configurable. | ||
* @param {boolean} [aOptions.writable=true] - Whether the property is writable. | ||
* @param {function} [aOptions.get] - The getter function. | ||
* @param {function} [aOptions.set] - The setter function. | ||
* @returns The object that was passed to the function, with the specified property added or modified. | ||
* | ||
* @example | ||
* // Define a non-enumerable data property. | ||
* defineProperty(myObject, "myProperty", 42); | ||
* | ||
* @example | ||
* // Define an enumerable accessor property. | ||
* defineProperty(myObject, "myAccessorProperty", null, { | ||
* enumerable: true, | ||
* get: function() { | ||
* return this._myValue; | ||
* }, | ||
* set: function(newValue) { | ||
* this._myValue = newValue; | ||
* } | ||
* }); | ||
* | ||
* @example | ||
* // Define a non-enumerable, read-only data property. | ||
* defineProperty(myObject, "myReadOnlyProperty", "hello", { | ||
* writable: false | ||
* }); | ||
* | ||
* @example | ||
* // Define an enumerable, configurable data property. | ||
* defineProperty(myObject, "myConfigurableProperty", 42, { | ||
* enumerable: true, | ||
* configurable: true | ||
* }); | ||
*/ | ||
module.exports = function defineProperty(object, key, value, aOptions) { | ||
var descriptor, isAccessor, writable; | ||
writable = true; | ||
descriptor = { | ||
configurable: true, | ||
enumerable: false | ||
}; | ||
if (aOptions) { | ||
descriptor.enumerable = aOptions.enumerable === true; | ||
descriptor.configurable = aOptions.configurable !== false; | ||
if (aOptions.get) { | ||
isAccessor = true; | ||
descriptor.get = aOptions.get; | ||
} | ||
if (!isAccessor) { | ||
descriptor.writable = writable; | ||
descriptor.value = value; | ||
if (aOptions.set) { | ||
isAccessor = true; | ||
descriptor.set = aOptions.set; | ||
} | ||
return defineProperty(object, key, descriptor); | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=defineProperty.js.map | ||
writable = aOptions.writable !== false; | ||
if (value === undefined) { | ||
value = aOptions.value; | ||
} | ||
} | ||
if (!isAccessor) { | ||
descriptor.writable = writable; | ||
descriptor.value = value; | ||
} | ||
return _defineProperty(object, key, descriptor); | ||
}; |
@@ -1,6 +0,15 @@ | ||
var extend = require('./_extend'); | ||
var _extend = require('./_extend'); | ||
module.exports = function(ctor, superCtors) { | ||
extend(ctor.prototype, superCtors.prototype); | ||
/** | ||
* Extends the prototype of the given constructor with the prototypes of one or more super constructors. | ||
* | ||
* @param {function} ctor - The constructor to extend the prototype of. | ||
* @param {...function} superCtors - The super constructors whose prototypes should be copied onto the extended prototype. | ||
* @returns {function} The extended constructor `ctor`. | ||
*/ | ||
function extend(ctor, superCtors) { | ||
_extend(ctor.prototype, superCtors.prototype); | ||
return ctor; | ||
}; | ||
module.exports = extend |
@@ -1,56 +0,54 @@ | ||
(function() { | ||
var getClass, isArray, isObject, isString; | ||
var isArray = Array.isArray; | ||
isArray = Array.isArray; | ||
isString = function(v) { | ||
return typeof v === 'string'; | ||
}; | ||
isObject = function(v) { | ||
return v && typeof v === 'object'; | ||
}; | ||
getClass = function(aClassName, aScope, aValues) { | ||
var vKeys; | ||
if (isArray(aScope)) { | ||
if (!isArray(aValues)) { | ||
aValues = aScope; | ||
aScope = aValues.map(function(k) { | ||
var result; | ||
result = k.name; | ||
if (result == null) { | ||
throw TypeError('No Scope Name for ' + k); | ||
} | ||
return result; | ||
}); | ||
} | ||
} else if (isObject(aScope)) { | ||
vKeys = Object.keys(aScope); | ||
aValues = vKeys.map(function(k) { | ||
return aScope[k]; | ||
function getClass(aClassName, aScope, aValues) { | ||
var vKeys; | ||
if (typeof aScope === 'function') { | ||
return aScope(aClassName) | ||
} else if (isArray(aScope)) { | ||
if (!isArray(aValues)) { | ||
aValues = aScope; | ||
aScope = aValues.map(function(k) { | ||
var result; | ||
result = k.name; | ||
if (result == null) { | ||
throw TypeError('No Scope Name for ' + k); | ||
} | ||
return result; | ||
}); | ||
aScope = vKeys; | ||
} else { | ||
} | ||
return Function(aScope, 'return ' + aClassName).apply(null, aValues); | ||
} else if (typeof aScope === 'object') { | ||
vKeys = Object.keys(aScope); | ||
aValues = vKeys.map(function(k) { | ||
return aScope[k]; | ||
}); | ||
aScope = vKeys; | ||
} else { | ||
return | ||
}; | ||
var ix = aScope.indexOf(aClassName); | ||
return aValues[ix]; | ||
// return Function(aScope, 'return ' + aClassName).apply(null, aValues); | ||
}; | ||
module.exports = function(aClassName, aScope, aValues) { | ||
var result; | ||
if (aClassName != null) { | ||
if (typeof aClassName === 'function') { | ||
result = aClassName; | ||
} else if (typeof aClassName === 'string') { | ||
if (!/[, {}();.]+/.test(aClassName)) { | ||
result = getClass(aClassName, aScope, aValues); | ||
} | ||
/** | ||
* Retrieve a class from the registered classes in the scope by its name. | ||
* | ||
* @param {string|Function} aClassName The class name or class. if it's class return it directly. | ||
* @param {Function|string[]|Function[]|{[name: string]: Function}=} aScope The scope with all registered classes. | ||
* it'll be called to find the class if the aScope is a `function(className):Function` | ||
* @param {Function[]=} aValues If `aScope` is an array of strings, then `aValues` must exist and can only be an array of corresponding classes. | ||
* @returns {Function|undefined} return the found class or undefined | ||
*/ | ||
module.exports = function getClassByName(aClassName, aScope, aValues) { | ||
var result; | ||
if (aClassName != null) { | ||
if (typeof aClassName === 'function') { | ||
result = aClassName; | ||
} else if (typeof aClassName === 'string') { | ||
if (!/[, {}();.]+/.test(aClassName)) { | ||
result = getClass(aClassName, aScope, aValues); | ||
} | ||
} | ||
return result; | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=get-class-by-name.js.map | ||
} | ||
return result; | ||
}; |
@@ -6,7 +6,13 @@ var isEmptyFunction = require('./isEmptyFunction') | ||
//get latest non-empty constructor function through inherits link: | ||
module.exports = function (ctor) { | ||
//get latest non-empty constructor function through inherits link | ||
/** | ||
* Returns the first(latest) non-empty constructor in the inheritance chain of the given constructor that has own properties. | ||
* | ||
* @param {function} ctor - The constructor to get the first non-empty constructor of. | ||
* @returns {function} The first(latest) non-empty constructor in the inheritance chain of the given constructor. | ||
*/ | ||
function getConstructor(ctor) { | ||
var result = ctor; | ||
var isEmpty = isEmptyFunction(result); | ||
// console.log('getConstructor', result.toString(), isEmpty) | ||
var v = result.super_ || getPrototypeOf(result); | ||
@@ -18,6 +24,5 @@ while (isEmpty && v && v !== objectSuperCtor) { | ||
} | ||
// console.log('getConstructor', result.toString()) | ||
//if (isEmpty) result = null; | ||
return result; | ||
} | ||
module.exports = getConstructor |
@@ -1,24 +0,24 @@ | ||
(function() { | ||
var getPrototypeOf; | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
getPrototypeOf = require('./getPrototypeOf'); | ||
/** | ||
* Traverses the prototype chain of a given class to find the class(ctor) that contains a given property, returning the real class that owns the property. | ||
* @param {Function} aClass The class to start the search from | ||
* @param {string} aPropertyName The name of the property | ||
* @returns {Function|undefined} return the class of OwnProperty, or undefined if not found | ||
*/ | ||
module.exports = function getCtorOfOwnProperty(aClass, aPropertyName) { | ||
var result; | ||
var vPrototype = aClass.prototype; | ||
module.exports = function(aClass, aPropertyName) { | ||
var result, vPrototype; | ||
vPrototype = aClass.prototype; | ||
while (vPrototype && !vPrototype.hasOwnProperty(aPropertyName)) { | ||
vPrototype = getPrototypeOf(vPrototype); | ||
while (vPrototype && !vPrototype.hasOwnProperty(aPropertyName)) { | ||
vPrototype = getPrototypeOf(vPrototype); | ||
} | ||
if (vPrototype) { | ||
if (vPrototype.hasOwnProperty('Class')) { | ||
result = vPrototype.Class; | ||
} else { | ||
result = vPrototype.constructor; | ||
} | ||
if (vPrototype) { | ||
if (vPrototype.hasOwnProperty('Class')) { | ||
result = vPrototype.Class; | ||
} else { | ||
result = vPrototype.constructor; | ||
} | ||
} | ||
return result; | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=getCtorOfProperty.js.map | ||
} | ||
return result; | ||
}; |
@@ -1,45 +0,57 @@ | ||
(function() { | ||
var getProtoChain, getPrototypeOf, objectSuperCtor; | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
objectSuperCtor = getPrototypeOf(Object); | ||
module.exports = getProtoChain = function(ctor, deepth) { | ||
var lastCtor, mctors, name, result; | ||
if (deepth == null) { | ||
deepth = 0; | ||
/** | ||
* Returns an array of the names of constructors in the prototype chain of the given constructor. | ||
* | ||
* **Note**: the `getProtoChain.maxDepth` for `mixinCtors` is 10, You can change it. | ||
* | ||
* @param {function} ctor - The constructor to get the prototype chain of. | ||
* @throws {Error} If the maximum depth of nesting is reached. | ||
* @returns {string[]} An array of the names of constructors in the prototype chain of the given constructor. | ||
* The last element is always the string "Base," which represents the `Object` class that serves as the base for all | ||
* prototype chains. | ||
* | ||
* @example | ||
* | ||
* // Define a class hierarchy | ||
* class Animal {} | ||
* class Mammal extends Animal {} | ||
* class Cat extends Mammal {} | ||
* | ||
* // Get the prototype chain of the Cat class | ||
* const protoChain = getProtoChain(Cat); | ||
* console.log(protoChain); // Output: ["Cat", "Mammal", "Animal", "Base"] | ||
*/ | ||
function getProtoChain(ctor, depth) { | ||
if (depth == null) { | ||
depth = 0; | ||
} | ||
if (depth >= getProtoChain.maxDepth) { | ||
throw new Error('The maximum depth of nesting is reached.'); | ||
} | ||
var result = [] | ||
var lastCtor; | ||
while (ctor && ctor !== objectSuperCtor) { | ||
var mCtors, name; | ||
if (lastCtor && (mCtors = lastCtor.mixinCtors_)) { | ||
mCtors = mCtors.map(function(m) { | ||
return getProtoChain(m, ++depth); | ||
}); | ||
name = mCtors; | ||
} else { | ||
name = ctor === Object ? "Base" : ctor.name; | ||
} | ||
if (deepth >= getProtoChain.maxDeepth) { | ||
throw new Error('The maximum depth of nesting is reached.'); | ||
} | ||
result = (function() { | ||
var results; | ||
results = []; | ||
while (ctor && ctor !== objectSuperCtor) { | ||
if (lastCtor && (mctors = lastCtor.mixinCtors_)) { | ||
mctors = mctors.map(function(m) { | ||
return getProtoChain(m, ++deepth); | ||
}); | ||
name = mctors; | ||
} else { | ||
if (ctor === Object) { | ||
name = "Base"; | ||
} else { | ||
name = ctor.name; | ||
} | ||
} | ||
lastCtor = ctor; | ||
ctor = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
results.push(name); | ||
} | ||
return results; | ||
})(); | ||
return result.reverse(); | ||
}; | ||
lastCtor = ctor; | ||
ctor = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
result.push(name); | ||
} | ||
getProtoChain.maxDeepth = 10; | ||
return result.reverse(); | ||
}; | ||
}).call(this); | ||
getProtoChain.maxDepth = 10; | ||
//# sourceMappingURL=getProtoChain.js.map | ||
module.exports = getProtoChain | ||
@@ -1,16 +0,9 @@ | ||
(function() { | ||
var getPrototypeOf; | ||
var getPrototypeOf = Object.getPrototypeOf; | ||
getPrototypeOf = Object.getPrototypeOf; | ||
if (!getPrototypeOf) { | ||
getPrototypeOf = function(obj) { | ||
return obj.__proto__; | ||
}; | ||
} | ||
if (!getPrototypeOf) { | ||
getPrototypeOf = function(obj) { | ||
return obj.__proto__; | ||
}; | ||
} | ||
module.exports = getPrototypeOf; | ||
}).call(this); | ||
//# sourceMappingURL=getPrototypeOf.js.map | ||
module.exports = getPrototypeOf; |
@@ -0,137 +1,146 @@ | ||
var getClassByName = require('./get-class-by-name'); | ||
var inherits = require('./inherits'); | ||
/* | ||
The enhanced dynamical `inherits` implementation. | ||
function isFunction(value) { | ||
return typeof value === 'function'; | ||
}; | ||
```js | ||
var InheritsEx = require('inherits-ex/lib/inherits-ex') | ||
var defaultRequire = InheritsEx.requireClass; | ||
// You should return the proper class(ctor) here. | ||
InheritsEx.requireClass = function(className, scope){return defaultRequire.apply(null, arguments)}; | ||
var inherits = InheritsEx() | ||
``` | ||
function isString(value) { | ||
return typeof value === 'string'; | ||
}; | ||
The enhanced dynamical `inherits` implementation. | ||
function isObject(value) { | ||
return typeof value === 'object'; | ||
}; | ||
+ load the class via dynamical name. | ||
* requireClass *(Function)*: | ||
* scope *(Object)*: collects the register classes. | ||
* the inherits ctor will be added into the scope automatically. | ||
var isArray = Array.isArray; | ||
The default requireClass is `getClassByName`. | ||
/** | ||
* The enhanced dynamical `inherits` implementation. | ||
* | ||
* + load the class via dynamical name. | ||
* * requireClass *(Function)*: | ||
* * scope *(Object)*: collects the register classes. | ||
* * the inherits ctor will be added into the scope automatically. | ||
* | ||
* The default requireClass is `getClassByName`. | ||
* | ||
* @param {Function=} aDefaultRequire custom the requireClass function. | ||
* @returns {Function} the `inherits` function | ||
* | ||
* @example | ||
* | ||
* var InheritsEx = require('inherits-ex/lib/inherits-ex') | ||
* var defaultRequire = InheritsEx.requireClass; | ||
* // You should return the proper class(ctor) here. | ||
* InheritsEx.requireClass = function(className, scope){return defaultRequire.apply(null, arguments)}; | ||
* var inherits = InheritsEx() | ||
* | ||
* const requireClass = (aClassName, aScope) => getClassViaName(aClassName) | ||
* const InheritsEx = require('inherits-ex/lib/inherits-ex') | ||
* const inherits = InheritsEx(requireClass) | ||
* | ||
* class RootClass {} | ||
* class Parent {} | ||
* InheritsEx.setScope([RootClass, Parent]) | ||
* | ||
* class MyClass3 {} | ||
* inherits(MyClass3, RootClass) | ||
* | ||
*/ | ||
function InheritsEx(aDefaultRequire) { | ||
if (isFunction(aDefaultRequire)) { | ||
InheritsEx.requireClass = aDefaultRequire; | ||
} | ||
return InheritsEx.execute; | ||
} | ||
usage: | ||
InheritsEx.requireClass = getClassByName; | ||
```coffee | ||
requireClass = (aClassName, aScope)-> | ||
getClassViaName aClassName | ||
InheritsEx = require('inherits-ex/lib/inherits-ex') | ||
inherits = InheritsEx(requireClass) | ||
InheritsEx.scope = {}; | ||
class RootClass | ||
class Parent | ||
InheritsEx.setScope RootClass:RootClass, Parent:Parent | ||
InheritsEx.setScope = function(aScope) { | ||
if (Array.isArray(aScope)) { | ||
for (var j = 0; j < aScope.length; j++) { | ||
var k = aScope[j]; | ||
var vName = k.name; | ||
if (vName == null) { | ||
throw TypeError('No Scope Name for ' + k); | ||
} | ||
InheritsEx.addClass(vName, k) | ||
} | ||
} else if (isObject(aScope) || isFunction(aScope)) { | ||
InheritsEx.scope = aScope; | ||
} | ||
}; | ||
class MyClass3 | ||
inherits MyClass3, RootClass | ||
``` | ||
/** | ||
* Get the class from class name in scope | ||
* @param {*} aClassName the class name to find | ||
* @param {Function|string[]|Function[]|{[name: string]: Function}=} aScope The optional additional scope with all | ||
* registered classes. It'll be called to find the class if the aScope is a `function(className):Function`. | ||
* @param {Function[]=} aValues If `aScope` is an array of strings, then `aValues` must exist and can only be an array of corresponding classes. | ||
* @returns {Function|undefined} the found class or undefined. | ||
*/ | ||
InheritsEx.getClass = function(aClassName, aScope, aValues) { | ||
var requireClass, result; | ||
requireClass = InheritsEx.requireClass; | ||
if (aScope != null) { | ||
result = requireClass(aClassName, aScope, aValues); | ||
} | ||
if (!result && (aScope = InheritsEx.scope)) { | ||
result = requireClass(aClassName, aScope); | ||
} | ||
return result; | ||
}; | ||
(function() { | ||
var InheritsEx, getClassByName, inherits, isArray, isFunction, isObject, isString; | ||
getClassByName = require('./get-class-by-name'); | ||
inherits = require('./inherits'); | ||
isFunction = function(value) { | ||
return typeof value === 'function'; | ||
}; | ||
isString = function(value) { | ||
return typeof value === 'string'; | ||
}; | ||
isObject = function(value) { | ||
return typeof value === 'object'; | ||
}; | ||
isArray = Array.isArray; | ||
module.exports = InheritsEx = (function() { | ||
InheritsEx.requireClass = getClassByName; | ||
InheritsEx.scope = {}; | ||
InheritsEx.setScope = function(aScope) { | ||
var j, k, len, vName; | ||
if (isArray(aScope)) { | ||
for (j = 0, len = aScope.length; j < len; j++) { | ||
k = aScope[j]; | ||
vName = k.name; | ||
if (vName == null) { | ||
throw TypeError('No Scope Name for ' + k); | ||
} | ||
InheritsEx.scope[vName] = k; | ||
InheritsEx.execute = function(ctor, superCtors, aScope, aValues) { | ||
var isStrCtor; | ||
var getClass = InheritsEx.getClass; | ||
if (isStrCtor = isString(ctor)) { | ||
ctor = getClass(ctor, aScope, aValues); | ||
} | ||
if (isString(superCtors)) { | ||
superCtors = getClass(superCtors, aScope, aValues); | ||
} else if (isArray(superCtors)) { | ||
superCtors = (function() { | ||
var results = []; | ||
for (var j = 0; j < superCtors.length; j++) { | ||
var i = superCtors[j]; | ||
if (isString(i)) { | ||
results.push(getClass(i, aScope, aValues)); | ||
} else { | ||
results.push(i); | ||
} | ||
} else if (isObject(aScope)) { | ||
InheritsEx.scope = aScope; | ||
} | ||
}; | ||
return results; | ||
})(); | ||
} | ||
var result = inherits(ctor, superCtors); | ||
if (result && !isStrCtor) { | ||
InheritsEx.addClass(ctor.name, ctor); | ||
} | ||
return result; | ||
}; | ||
InheritsEx.getClass = function(aClassName, aScope, aValues) { | ||
var requireClass, result; | ||
requireClass = InheritsEx.requireClass; | ||
if (aScope != null) { | ||
result = requireClass(aClassName, aScope, aValues); | ||
} | ||
if (!result && (aScope = InheritsEx.scope)) { | ||
result = requireClass(aClassName, aScope); | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Add the class to the scope | ||
* | ||
* @internal | ||
* @param {string} aName the class name | ||
* @param {*} ctor the class | ||
*/ | ||
InheritsEx.addClass = function(aName, ctor) { | ||
var scope; | ||
scope = InheritsEx.scope; | ||
switch (typeof scope) { | ||
case 'function': | ||
scope(aName, ctor); | ||
break; | ||
case 'object': | ||
scope[aName] = ctor; | ||
break; | ||
} | ||
}; | ||
InheritsEx.execute = function(ctor, superCtors, aScope, aValues) { | ||
var getClass, i, isStrCtor, result; | ||
getClass = InheritsEx.getClass; | ||
if (isStrCtor = isString(ctor)) { | ||
ctor = getClass(ctor, aScope, aValues); | ||
} | ||
if (isString(superCtors)) { | ||
superCtors = getClass(superCtors, aScope, aValues); | ||
} else if (isArray(superCtors)) { | ||
superCtors = (function() { | ||
var j, len, results; | ||
results = []; | ||
for (j = 0, len = superCtors.length; j < len; j++) { | ||
i = superCtors[j]; | ||
if (isString(i)) { | ||
results.push(getClass(i, aScope, aValues)); | ||
} else { | ||
results.push(i); | ||
} | ||
} | ||
return results; | ||
})(); | ||
} | ||
result = inherits(ctor, superCtors); | ||
if (result && !isStrCtor) { | ||
InheritsEx.scope[ctor.name] = ctor; | ||
} | ||
return result; | ||
}; | ||
function InheritsEx(aDefaultRequire) { | ||
if (isFunction(aDefaultRequire)) { | ||
InheritsEx.requireClass = aDefaultRequire; | ||
} | ||
return InheritsEx.execute; | ||
} | ||
return InheritsEx; | ||
})(); | ||
}).call(this); | ||
//# sourceMappingURL=inherits-ex.js.map | ||
module.exports = InheritsEx; |
@@ -6,25 +6,20 @@ var isArray = Array.isArray; | ||
var defineProperty = require('./defineProperty'); | ||
var getParentCtor = require('./getParentClass'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
* Inherit the prototype methods from one constructor into another. | ||
* Inherit the prototype properties and methods from one constructor into another. | ||
* | ||
* | ||
* The Function.prototype.inherits from lang.js rewritten as a standalone | ||
* function (not on Function.prototype). NOTE: If this file is to be loaded | ||
* during bootstrapping this function needs to be rewritten using some native | ||
* functions as prototype setup using normal JavaScript does not work as | ||
* expected during bootstrapping (see mirror.js in r114903). | ||
* | ||
* @param {function} ctor Constructor function which needs to inherit the | ||
* prototype. | ||
* @param {function} superCtor Constructor function to inherit prototype from. | ||
* @param {boolean} staticInherit whether allow static members inheritance,defaults to true. | ||
* @param {function} ctor the class which needs to inherit the prototype. | ||
* @param {function} superCtor the parent class to inherit prototype from. | ||
* @param {boolean=true} staticInherit whether allow static members inheritance, defaults to true. | ||
* @returns The function returns true if inheritance was successful. | ||
*/ | ||
function inherits(ctor, superCtor, staticInherit) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
function _inherits(ctor, superCtor, staticInherit) { | ||
var v = getParentCtor(ctor); | ||
var mixinCtor = ctor.mixinCtor_; | ||
if (mixinCtor && v === mixinCtor) { | ||
ctor = mixinCtor; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
v = getParentCtor(ctor); | ||
} | ||
@@ -40,3 +35,3 @@ var result = false; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
v = getParentCtor(ctor); | ||
} | ||
@@ -57,8 +52,81 @@ result = true; | ||
module.exports = function(ctor, superCtors, staticInherit) { | ||
if (!isArray(superCtors)) return inherits(ctor, superCtors, staticInherit); | ||
/** | ||
* A powerful tool for implementing class inheritance that supports dynamic inheritance and multiple inheritance. | ||
* | ||
* **Features**: | ||
* | ||
* * Supports dynamic inheritance. | ||
* * Preserves existing methods and properties in the child class's prototype instead of overwriting them. | ||
* * Avoids circular dependencies by checking if the parent class has already inherited from the child class. | ||
* * Avoids duplicate inheritance by checking if the child class has already inherited from the parent class. | ||
* * Supports multiple inheritance by allowing an array of parent classes to be passed in. | ||
* * Optional static members inheritance. | ||
* | ||
* The function is compatible with both ES5 and ES6, as well as older browsers that do not support these | ||
* versions of JavaScript. The function also supports CoffeeScript-generated classes. | ||
* | ||
* **Note**: | ||
* | ||
* * When using the `inherits` function, these two properties are added to the constructor function(`ctor`). | ||
* * The `super_` property refers to the parent constructor. | ||
* * The `__super__` property refers to the parent's prototype object, | ||
* which can be used for the `super` keyword in CoffeeScript. | ||
* * In addition, the `Class` property is added to the prototype object of the constructor function (`ctor`). | ||
* * This property points to the current class(`ctor`). | ||
* * This property can also be accessed by instances of the class. | ||
* * It is important to note that for the empty constructor, the instance of `ctor` may not be the current class, | ||
* but the `Class` property is always set to the current class for instance. | ||
* | ||
* | ||
* @param {Function} ctor the child class that needs to inherit from the parent class. | ||
* @param {Function|Function[]} superCtors the parent class that the child class needs to inherit from. | ||
* The first class is the parent of child class ctor, the left classes will be chained(inherits) one by one, | ||
* if `superCtors` is an array of classes. | ||
* @param {boolean=true} staticInherit optional indicating whether or not the static properties of the parent class should be inherited as well. | ||
* @returns {boolean} returns true if inheritance was successful. | ||
* | ||
* @example | ||
* | ||
* class Animal { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* | ||
* speak() { | ||
* console.log(this.name + ' makes a noise.'); | ||
* } | ||
* } | ||
* | ||
* class Dog extends Animal { | ||
* constructor(name, breed) { | ||
* super(name); | ||
* this.breed = breed; | ||
* } | ||
* | ||
* speak() { | ||
* console.log(this.name + ' barks.'); | ||
* } | ||
* } | ||
* | ||
* function Cat(name, breed) { | ||
* this.name = name; | ||
* this.breed = breed; | ||
* } | ||
* | ||
* Cat.prototype.meow = function() { | ||
* console.log(this.name + ' meows.'); | ||
* }; | ||
* | ||
* inherits(Cat, [Animal]); | ||
* | ||
* const fluffy = new Cat('Fluffy', 'Siamese'); | ||
* fluffy.speak(); // Output: Fluffy makes a noise. | ||
* fluffy.meow(); // Output: Fluffy meows. | ||
*/ | ||
module.exports = function inherits(ctor, superCtors, staticInherit) { | ||
if (!isArray(superCtors)) return _inherits(ctor, superCtors, staticInherit); | ||
for (var i = superCtors.length - 1; i >= 0; i--) { | ||
if (!inherits(ctor, superCtors[i], staticInherit)) return false; | ||
if (!_inherits(ctor, superCtors[i], staticInherit)) return false; | ||
} | ||
return true; | ||
} |
@@ -6,3 +6,15 @@ var newPrototype = require('./newPrototype'); | ||
//just replace the ctor.super to superCtor, | ||
module.exports = function(ctor, superCtor, staticInherit) { | ||
/** | ||
* Enables dynamic prototypal inheritance between classes, allowing for flexible and reusable code. | ||
* | ||
* The `inheritsDirectly` function is compatible with both ES5 and ES6, as well as older browsers that do not support these versions of JavaScript. | ||
* The function also supports CoffeeScript-generated classes | ||
* | ||
* **Note**: If a parent class already exists on the class, it will be replaced by the new parent class. | ||
* | ||
* @param {Function} ctor The child class that will inherit from the parent class. | ||
* @param {Function} superCtor The parent class from which the child class will inherit. | ||
* @param {boolean=} staticInherit Optional A boolean flag indicating whether the child class should also inherit static properties and methods from the parent class. The default value is `true`. | ||
*/ | ||
module.exports = function inheritsDirectly(ctor, superCtor, staticInherit) { | ||
defineProperty(ctor, 'super_', superCtor); | ||
@@ -9,0 +21,0 @@ defineProperty(ctor, '__super__', superCtor.prototype);//for coffeeScript super keyword. |
@@ -5,6 +5,34 @@ var inherits = require('./inherits'); | ||
//make sure the aClass.prototype hook to the aObject instance. | ||
module.exports = function(aObject, aClass, staticInherit) { | ||
// ES6: Object.getPrototypeOf / Object.setPrototypeOf | ||
/** | ||
* Sets the prototype of an object to a new prototype, and inherits from a given class. | ||
* | ||
* make sure the aClass.prototype hook to the aObject instance. | ||
* | ||
* @param {Object} aObject - The object whose prototype needs to be set. | ||
* @param {Function} aClass - The class to inherit from. | ||
* @param {boolean} staticInherit - Whether to inherit static properties or not. | ||
* @returns {boolean} - Whether the prototype was successfully set or not. | ||
* @example | ||
* ```js | ||
* class Person { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* | ||
* sayHello() { | ||
* console.log(`Hello, my name is ${this.name}`); | ||
* } | ||
* } | ||
* | ||
* const john = new Person('John'); | ||
* const jane = {name: 'Jane'}; | ||
* | ||
* // make object Inherit from Person | ||
* inheritsObject(jane, Person); | ||
* | ||
* // Now jane's prototype is Person, and she can call sayHello | ||
* jane.sayHello(); // logs "Hello, my name is Jane" | ||
* ``` | ||
*/ | ||
function inheritsObject(aObject, aClass, staticInherit) { | ||
var vOldProto = getPrototypeOf(aObject); | ||
@@ -19,1 +47,3 @@ var result = false; | ||
}; | ||
module.exports = inheritsObject |
@@ -1,2 +0,8 @@ | ||
module.exports = function(vStr) { | ||
/** | ||
* Determines whether the given string represents an empty constructor. | ||
* | ||
* @param {string} vStr - The string to check. | ||
* @returns {boolean} - Returns true if the string represents an empty constructor, otherwise false | ||
*/ | ||
function isEmptyCtor(vStr) { | ||
var isClass = /^class\s+/.test(vStr); | ||
@@ -12,1 +18,3 @@ var result | ||
}; | ||
module.exports = isEmptyCtor |
@@ -0,3 +1,9 @@ | ||
/** | ||
* Determines whether the given string represents an empty constructor. | ||
* | ||
* @param {string} vStr - The string to check. | ||
* @returns {boolean} - Returns true if the string represents an empty constructor, otherwise false | ||
*/ | ||
module.exports = function(aFunc) { | ||
return /^function\s*\S*\s*\((.|[\n\r\u2028\u2029])*\)\s*{[\s;]*}$/g.test(aFunc.toString()); | ||
}; |
var isEmptyCtor = require('./isEmptyCtor'); | ||
module.exports = function(aFunc, istanbul) { | ||
/** | ||
* Checks whether a given function is empty or not. | ||
* @param {Function} aFunc - The function to be checked. | ||
* @param {boolean} istanbul - whether has istanbul TODO: remove this! | ||
* @returns {boolean} - True if the function is empty, false otherwise. | ||
*/ | ||
module.exports = function isEmptyFunction(aFunc, istanbul) { | ||
var vStr = aFunc.toString(); | ||
@@ -5,0 +11,0 @@ var result = /^function\s*\S*\s*\((.|[\n\r\u2028\u2029])*\)\s*{[\s;]*}$/g.test(vStr); |
@@ -6,3 +6,11 @@ var isInheritedFromStr = require('./isInheritedFromStr'); | ||
module.exports = function(ctor, superCtor, throwError) { | ||
/** | ||
* Determines if a constructor(class) is inherited from a given super constructor(class). | ||
* @param {Function} ctor - The constructor function to check. | ||
* @param {Function|string} superCtor - The super constructor to check for inheritance. Can be the name of the super constructor. | ||
* @param {boolean=false} throwError - If true, an error will be thrown if a circular inheritance is found. | ||
* @returns {boolean|Function} - If the constructor is inherited from the super constructor, returns the constructor. | ||
* Otherwise, returns false. | ||
*/ | ||
module.exports = function isInheritedFrom(ctor, superCtor, throwError) { | ||
if (typeof superCtor === 'string') return isInheritedFromStr(ctor, superCtor, throwError); | ||
@@ -9,0 +17,0 @@ if (ctor === superCtor) { |
var getPrototypeOf = require('./getPrototypeOf'); | ||
module.exports = function(ctor, superStr, throwError) { | ||
/** | ||
* Determines if a constructor(class) is inherited from a given the name of super constructor(class). | ||
* @param {Function} ctor - The constructor function to check. | ||
* @param {string} superStr - The super constructor's name to check for inheritance. | ||
* @param {boolean=false} throwError - If true, an error will be thrown if a circular inheritance is found. | ||
* @returns {boolean|Function} - If the constructor is inherited from the super constructor, returns the constructor. | ||
* Otherwise, returns false. | ||
*/ | ||
module.exports = function isInheritedFromStr(ctor, superStr, throwError) { | ||
if (ctor.name === superStr) { | ||
@@ -5,0 +13,0 @@ if (throwError) |
var isMixinedFromStr = require('./isMixinedFromStr'); | ||
module.exports = function(ctor, superCtor) { | ||
/** | ||
* Check if a constructor is mixed from a specific constructor. | ||
* @param {function} ctor - The constructor to check. | ||
* @param {function|string} superCtor - The constructor to check if the `ctor` is mixed from. Can be the name of the constructor. | ||
* @returns {boolean} - True if `ctor` is mixed from `superCtor`, otherwise false. | ||
*/ | ||
module.exports = function isMixinedFrom(ctor, superCtor) { | ||
if (typeof superCtor === 'string') return isMixinedFromStr(ctor, superCtor); | ||
@@ -5,0 +11,0 @@ var mixinCtors = ctor.mixinCtors_; |
@@ -1,2 +0,8 @@ | ||
module.exports = function(ctor, superStr) { | ||
/** | ||
* Check if a constructor is mixed from a specific constructor. | ||
* @param {function} ctor - The constructor to check. | ||
* @param {string} superStr - The name of constructor to check if the `ctor` is mixed from. | ||
* @returns {boolean} - True if `ctor` is mixed from `superCtor`, otherwise false. | ||
*/ | ||
module.exports = function isMixinedFromStr(ctor, superStr) { | ||
var result = false; | ||
@@ -3,0 +9,0 @@ var mixinCtors = ctor.mixinCtors_; |
@@ -0,1 +1,5 @@ | ||
/** | ||
* Checks if the current environment supports native Reflect.construct method. | ||
* @returns {boolean} True if the current environment supports native Reflect.construct method, false otherwise. | ||
*/ | ||
function isNativeReflectConstruct() { | ||
@@ -2,0 +6,0 @@ if (typeof Reflect === "undefined" || !Reflect.construct) return false; |
194
lib/mixin.js
@@ -9,7 +9,22 @@ var inheritsDirectly = require('./inheritsDirectly'); | ||
var extendPrototype = require('./extend'); | ||
var getParentCtor = require('./getParentClass'); | ||
var getOwnPropertyNames = Object.getOwnPropertyNames; | ||
/** | ||
* Enum for filter type | ||
* @readonly | ||
* @enum {number} | ||
*/ | ||
var filterOpts = { | ||
/** | ||
* Include all members from the superCtor | ||
*/ | ||
'all': 0, | ||
/** | ||
* Throw error if the method of superCtor using the `super()` | ||
*/ | ||
'errSuper': 1, | ||
/** | ||
* Skip the method if the method of superCtor using the `super()` | ||
*/ | ||
'skipSuper': 2 | ||
@@ -30,3 +45,3 @@ }; | ||
/** | ||
/* | ||
* Mixin multi classes to ctor. | ||
@@ -57,39 +72,45 @@ * mixin(Class, ParentClass1, ParentClass2, ...) | ||
```coffee | ||
class Root | ||
m: -> | ||
@example | ||
```js | ||
class Root { | ||
m() { | ||
console.log 'root' | ||
console.log '----' | ||
class C | ||
inherits C, Root | ||
m: -> | ||
console.log "c" | ||
super | ||
class B | ||
inherits B, Root | ||
m: -> | ||
console.log "b" | ||
super | ||
class B11 | ||
inherits B11, B | ||
m: -> | ||
console.log 'b11' | ||
super | ||
} | ||
} | ||
class C extends Root { | ||
m() { | ||
console.log("c") | ||
super.m() | ||
} | ||
} | ||
class B extends Root { | ||
m() { | ||
console.log("b") | ||
super.m() | ||
} | ||
} | ||
b = new B11 | ||
class B11 extends B { | ||
m() { | ||
console.log('b11') | ||
super.m() | ||
} | ||
} | ||
let b = new B11 | ||
b.m() | ||
mixin B11, C | ||
mixin(B11, C) | ||
b = new B11 | ||
b.m() | ||
# The console results: | ||
# b11 | ||
# b | ||
# root | ||
# ---- | ||
# b11 | ||
# c | ||
# root | ||
# ---- | ||
// The console results: | ||
// b11 | ||
// b | ||
// root | ||
// ---- | ||
// b11 | ||
// c | ||
// root | ||
// ---- | ||
``` | ||
@@ -107,3 +128,3 @@ | ||
var vStr = aMethod.toString(); | ||
return vStr.indexOf('__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
return vStr.indexOf('.__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
} | ||
@@ -120,3 +141,3 @@ // function isSuperInFunction(aMethod) { | ||
function _mixinGenMethod(aMixinSuper, aMethod, src) { | ||
var oldSuper = src.__super__; | ||
// var oldSuper = src.__super__; | ||
return function() { | ||
@@ -182,3 +203,3 @@ // src.__super__ = aMixinSuper; | ||
var value = filter(k, src[k]); | ||
if (value !== void 0) dest[k] = value; | ||
if (value !== undefined) dest[k] = value; | ||
} | ||
@@ -191,6 +212,6 @@ } | ||
if (n === name) { | ||
value = void 0; | ||
value = undefined; | ||
break; | ||
} | ||
if (value !== void 0) value = filter(name, value); | ||
if (value !== undefined) value = filter(name, value); | ||
} | ||
@@ -208,6 +229,6 @@ return value; | ||
if (n === name) { | ||
value = void 0; | ||
value = undefined; | ||
break; | ||
} | ||
if (value !== void 0) value = filter(name, value); | ||
if (value !== undefined) value = filter(name, value); | ||
} | ||
@@ -228,3 +249,3 @@ return value; | ||
// console.log(k, value) | ||
if (value !== void 0) dp[k] = value; | ||
if (value !== undefined) dp[k] = value; | ||
// continue; | ||
@@ -237,3 +258,3 @@ | ||
// just override the property simply. | ||
// if (mixinedMethod !== void 0 && typeof mixinedMethod !== 'function') { | ||
// if (mixinedMethod !== undefined && typeof mixinedMethod !== 'function') { | ||
// // Already be defined as property in the mixin ctor | ||
@@ -297,6 +318,32 @@ // continue; | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
* @callback FilterFn | ||
* @param {string} name | ||
* @param {any} value | ||
* @returns {any} include it return value directly or return undefined | ||
*/ | ||
/** | ||
* | ||
* @param {Function} ctor the class that needs to mixin from the `superCtor` class. | ||
* @param {Function} superCtor The super class that the `ctor` needs to inherit from. | ||
* @param {FilterFn|string[]|filterOpts=} options.filter (optional) A filter that specifies which members to include | ||
* from the superCtor. | ||
* | ||
* * This can be a function that takes a `name` and `value` parameter and returns a value to include or `undefined` | ||
* * an array of strings that represent member names to include | ||
* * or the filter options (`filterOpts`) available (`all`, `errSuper`, or `skipSuper`) | ||
* * `all`: include all members from the superCtor without check whether the method used the `super()`. | ||
* * `errSuper`: Throw error if the method of superCtor using the `super()` | ||
* * `skipSuper`: skip the method if the method of superCtor using the `super()` | ||
* | ||
* @returns return true if successful | ||
*/ | ||
function mixin(ctor, superCtor, options) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); // original superCtor | ||
var v = getParentCtor(ctor); // original superCtor | ||
var result = false; | ||
// Check if the two classes are already related in some way to avoid circular or duplicate inheritance | ||
if (!isMixinedFrom(ctor, superCtor) && !isInheritedFrom(ctor, superCtor) && !isInheritedFrom(superCtor, ctor)) { | ||
// Create a mixin constructor function for the child class if one doesn't already exist | ||
var mixinCtor = ctor.mixinCtor_; | ||
@@ -328,3 +375,62 @@ var mixinCtors = ctor.mixinCtors_; | ||
var mixins = module.exports = function(ctor, superCtors, options) { | ||
/** | ||
* Mixes the methods and properties from one or more classes to the target class. | ||
* | ||
* By default, all properties and methods from the `superCtors` will be cloned into the internal `mixinCtor_` | ||
* constructor of the target class(`ctor`). This can be customized by providing the `options.filter` parameter. | ||
* | ||
* If the target class does not already have a `mixinCtor_` constructor it'll create the new constructor | ||
* `mixinCtor_` which is then inherited by the `ctor`(target class). The `mixinCtor_` is also set as a property of the | ||
* `ctor`. | ||
* | ||
* **Note**: | ||
* | ||
* 1. If a property or method exists with the same name in both `superCtors` and `ctor`'s `mixinCtor_`, the property | ||
* or method in the `superCtor` takes precedence. The last one will overwrite the previous one. | ||
* 2. the `mixin` does not create a prototype chain between "`superCtors`"(just copy the members from `superCtors`), so | ||
* you cannot clone these methods of `superCtor` which use the `super()`. If you need to use `super()` in these | ||
* methods, you should use `inherits` instead of `mixin`. | ||
* | ||
* @param {Function} ctor the target class that needs to mixin from the `superCtors` class. | ||
* @param {Function|Function[]} superCtors The class(es) to be used as sources of properties and methods. | ||
* @param {FilterFn|string[]|filterOpts=} options.filter (optional) A filter that specifies which members to include | ||
* from the `superCtor`. If no filter is specified, all properties and methods from `superCtor` will be mixed in. | ||
* | ||
* * It could be a function that takes a `name` and `value` parameter and returns a value to include or `undefined` | ||
* * Or an array of strings that represent member names to include | ||
* * Or the filter options (`filterOpts`) available (`all`, `errSuper`, or `skipSuper`) | ||
* * `all`: include all members from the superCtor without check whether the method used the `super()`. | ||
* * `errSuper`: Throw error if the method of superCtor using the `super()` | ||
* * `skipSuper`: skip the method if the method of superCtor using the `super()` | ||
* | ||
* @returns return true if successful | ||
* | ||
* @example | ||
* | ||
* class MixinA { | ||
* methodA() { | ||
* console.log('Method A called'); | ||
* } | ||
* } | ||
* | ||
* class MixinB { | ||
* methodB() { | ||
* console.log('Method B called'); | ||
* } | ||
* } | ||
* | ||
* class MyClass { | ||
* constructor() { | ||
* } | ||
* } | ||
* | ||
* // mixin both MixinA and MixinB | ||
* mixins(MyClass, [MixinA, MixinB]); // == mixins(MyClass, MixinA); mixins(MyClass, MixinB); | ||
* | ||
* const myObj = new MyClass(); | ||
* | ||
* myObj.methodA(); // logs 'Method A called' | ||
* myObj.methodB(); // logs 'Method B called' | ||
*/ | ||
function mixins(ctor, superCtors, options) { | ||
if (typeof superCtors === 'function') return mixin(ctor, superCtors, options); | ||
@@ -339,1 +445,3 @@ for (var i = 0; i < superCtors.length; i++) { | ||
mixins.filterOpts = filterOpts; | ||
module.exports = mixins |
@@ -5,3 +5,9 @@ var getConstructor = require('./getConstructor'); | ||
module.exports = function (aClass, aConstructor) { | ||
/** | ||
* Creates a new object with a prototype chain from a given class and constructor function. | ||
* @param {Function} aClass - The class to use as prototype chain. | ||
* @param {Function} [aConstructor] - The constructor function for the new object. | ||
* @returns {Object} - The newly created prototype object. | ||
*/ | ||
module.exports = function newPrototype(aClass, aConstructor) { | ||
//Object.create(prototype) only for ES5 | ||
@@ -37,4 +43,3 @@ //Object.create(prototype, initProps) only for ES6 | ||
extend(result, aConstructor.prototype); | ||
// console.log('TCL:: ~ file: newPrototype.js ~ line 36 ~ result', result, aConstructor); | ||
return result; | ||
}; |
@@ -6,3 +6,35 @@ var getPrototypeOf = require('./getPrototypeOf'); | ||
//just replace the object's constructor | ||
module.exports = function(aObject, aClass) { | ||
/** | ||
* Replace the prototype of an object with the prototype of a given class | ||
* @param {Object} aObject - The object whose prototype needs to be replaced | ||
* @param {Function} aClass - The class whose prototype should be used to replace the object's prototype | ||
* @returns {boolean} - Returns true if the object's prototype was successfully replaced, otherwise returns false | ||
* | ||
* @example | ||
* | ||
* class Person { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* greet() { | ||
* console.log('Hello, my name is '+ this.name); | ||
* } | ||
* } | ||
* | ||
* class Student { | ||
* constructor(name, major) { | ||
* super(name); | ||
* this.major = major; | ||
* } | ||
* greet() { | ||
* console.log("Hello, I'm student. My name is " + this.name); | ||
* } | ||
* } | ||
* const mary = new Person('Mary'); | ||
* mary.greet(); // logs "Hello, my name is Mary" | ||
* replaceCtor(mary, Student); // returns true | ||
* mary.greet(); // logs "Hello, I'm student. My name is Mary" | ||
*/ | ||
module.exports = function replaceCtor(aObject, aClass) { | ||
var vOldProto = getPrototypeOf(aObject); | ||
@@ -9,0 +41,0 @@ var result = false; |
@@ -1,16 +0,10 @@ | ||
(function() { | ||
var setPrototypeOf; | ||
var setPrototypeOf = Object.setPrototypeOf; | ||
setPrototypeOf = Object.setPrototypeOf; | ||
if (!setPrototypeOf) { | ||
setPrototypeOf = function(obj, prototype) { | ||
obj.__proto__ = prototype; | ||
return obj; | ||
}; | ||
} | ||
if (!setPrototypeOf) { | ||
setPrototypeOf = function(obj, prototype) { | ||
return obj.__proto__ = prototype; | ||
}; | ||
} | ||
module.exports = setPrototypeOf; | ||
}).call(this); | ||
//# sourceMappingURL=setPrototypeOf.js.map | ||
module.exports = setPrototypeOf; |
{ | ||
"name": "inherits-ex", | ||
"description": "Browser-friendly enhanced inheritance fully compatible with standard node.js and coffee-script", | ||
"description": "Enhanced inheritance for dynamic inheritance and mixin.", | ||
"homepage": "https://github.com/snowyu/inherits-ex.js", | ||
"version": "1.3.6", | ||
"version": "1.4.0", | ||
"author": { | ||
@@ -10,2 +10,3 @@ "name": "Riceball LEE", | ||
}, | ||
"types": "./types", | ||
"files": [ | ||
@@ -17,2 +18,3 @@ "README.md", | ||
"test", | ||
"types", | ||
"src", | ||
@@ -35,3 +37,3 @@ "lib" | ||
], | ||
"main": "./index.js", | ||
"main": "./lib/index.js", | ||
"repository": "git://github.com/snowyu/inherits-ex.js", | ||
@@ -43,18 +45,9 @@ "bugs": { | ||
"devDependencies": { | ||
"chai": "~1.10.0", | ||
"coffee-coverage": "^2.0.1", | ||
"coffee-script": "^1.12.7", | ||
"grunt": "^1.3.0", | ||
"grunt-contrib-clean": "*", | ||
"grunt-contrib-coffee": "^1.0.0", | ||
"grunt-contrib-copy": "*", | ||
"grunt-contrib-watch": "*", | ||
"grunt-mocha-test": "*", | ||
"grunt-newer": "*", | ||
"istanbul": "^0.4.5", | ||
"mocha": "~2.1.0", | ||
"pre-commit": "1.1.3", | ||
"sinon": "~1.12.2", | ||
"sinon-chai": "~2.6.0", | ||
"source-map-support": "*" | ||
"chai": "~4.3.7", | ||
"mocha": "~10.2.0", | ||
"sinon": "~15.0.2", | ||
"sinon-chai": "~3.7.0", | ||
"typedoc": "^0.23.28", | ||
"typedoc-plugin-markdown": "^3.14.0", | ||
"typescript": "^5.0.2" | ||
}, | ||
@@ -65,6 +58,14 @@ "pre-commit": [ | ||
"scripts": { | ||
"test": "grunt test", | ||
"test-cov": "istanbul cover node_modules/.bin/_mocha --report lcovonly -- --reporter dot" | ||
"build": "npm run build.ts && mkdir -p lib && cp src/*.js lib/", | ||
"build.ts": "tsc", | ||
"clean": "rm -fr web docs types lib", | ||
"clean.doc": "rm -fr web docs", | ||
"clean.ts": "rm -fr types", | ||
"clean.lib": "rm -fr lib", | ||
"doc": "typedoc --plugin none --out web ./src", | ||
"doc.md": "typedoc --plugin typedoc-plugin-markdown --out docs ./src", | ||
"release": "npx standard-version", | ||
"release.alpha": "npx standard-version --prerelease alpha", | ||
"test": "mocha" | ||
}, | ||
"dependencies": {}, | ||
"browser": { | ||
@@ -71,0 +72,0 @@ "./lib/isEmptyFunction.js": "./lib/isEmptyFunction-cli.js" |
352
README.md
@@ -21,10 +21,11 @@ # Inherits-Ex [![npm](https://img.shields.io/npm/v/inherits-ex.svg)](https://npmjs.org/package/inherits-ex) | ||
+ coffee-script supports | ||
+ static inheritance | ||
+ multi-inheritances(inheritance chain) supports | ||
+ inherits at anytime. | ||
+ Static inheritance | ||
+ Multi-inheritances(inheritance chain) supports | ||
+ Mixin-inheritances(inheritance chain) supports | ||
+ Inherits at anytime. | ||
* you can not declare method/property before inherits in the standard way for it will replace the prototype object. | ||
+ duplication inheritance check | ||
+ Duplication inheritance check | ||
+ Es6 Class supports | ||
+ more helper functions | ||
+ Coffee-script supports | ||
+ More helper functions | ||
* `isInheritedFrom(ctor, superCtor|superCtorName)` Check the ctor whether inherited from superCtor | ||
@@ -37,2 +38,3 @@ * `mixin(ctor, superCtor|superCtor[])` Mixin the methods and properties of the SuperCtor: | ||
* `createFunction(name, [args,] body[, scope[, values]])` Create Function dynamically | ||
* ... | ||
@@ -44,6 +46,26 @@ The standard `inherits` implementation is in `inherits-ex/lib/inheritsDirectly`, | ||
### inherits(ctor, superCtor|superCtor[], staticInherit = true) | ||
Full API see the folder: [docs](docs/modules.md) | ||
* `staticInherit` (*boolean*): whether static inheritance,defaults to true. | ||
### inherits | ||
`function inherits(ctor, superCtor|superCtor[], staticInherit = true): boolean` | ||
A powerful tool for implementing class inheritance that supports dynamic inheritance and multiple inheritance. | ||
**Features**: | ||
* Supports dynamic inheritance. | ||
* inherits at anytime. | ||
* you can not declare method/property before inherits in the standard way for it will replace the prototype object. | ||
* Multi-inheritances(inheritance chain) supports | ||
* Preserves existing methods and properties in the child class's prototype instead of overwriting them. | ||
* Avoids circular dependencies by checking if the parent class has already inherited from the child class. | ||
* Avoids duplicate inheritance by checking if the child class has already inherited from the parent class. | ||
* Supports multiple inheritance by allowing an array of parent classes to be passed in. | ||
* Optional static members inheritance. | ||
* Argument `staticInherit` (*boolean*): whether static inheritance,defaults to true. | ||
The function is compatible with both ES5 and ES6, as well as older browsers that do not support these | ||
versions of JavaScript. The function also supports CoffeeScript-generated classes. | ||
```js | ||
@@ -53,21 +75,21 @@ const inherits = require('inherits-ex/lib/inherits') | ||
The enhanced `inherits` implementation. | ||
**Note**: | ||
+ coffee-script supports | ||
+ multi-inheritances(inheritance chain) supports | ||
+ inherits at anytime. | ||
* you can not declare method/property before inherits in the standard way for it will replace the prototype object. | ||
+ duplication inheritance check | ||
+ add the `super_` property(the super ctor) to the ctor. | ||
+ add the `__super__` property(the super's prototype) to the ctor for the coffeeScirpt `super` keyword. | ||
+ add the `Class` property(point to the current class) to the object's prototype. | ||
* just be care: the ctor may not be the current class. | ||
* When using the `inherits` function, two properties, `super_` and `__super__`, are added to the constructor function (`ctor`). | ||
* The `super_` property refers to the parent constructor. | ||
* The `__super__` property refers to the parent's prototype object, which can be used for the `super` keyword in CoffeeScript. | ||
* In addition, the `Class` property is added to the prototype object of the constructor function (`ctor`). | ||
* This property points to the current class(`ctor`). | ||
* This property can also be accessed by instances of the class. | ||
* It is important to note that for the empty constructor, the instance of `ctor` may not be the current class, but the `Class` property is always set to the current class for instance. | ||
#### Known Issues | ||
The default constructor(empty) chain failed for ES6 Class can not call constructor directly if no `Reflect.construct(target, args, newTarget)` native supports | ||
The default constructor chain in ES6 Class may fail if the constructor is empty, because the constructor cannot be directly called if the `Reflect.construct(target, args, newTarget)` native method is not supported. In such a case, you may need to manually define a constructor or use a polyfill to support the `Reflect.construct()` method. | ||
```javascript | ||
const inherits = require('inherits-ex/lib/inherits') | ||
const getPrototypeOf = require('inherits-ex/lib/getPrototypeOf') | ||
const defineProperty = require('inherits-ex/lib/defineProperty') | ||
@@ -88,8 +110,12 @@ // Or use function class instead of ES6 class: | ||
/* | ||
// Workaround: must add the constructor in the derived class if you use inherits | ||
// Or use function Root instead of ES6 class | ||
// MUST BE EXISTS constructor to call parent constructor if it's ES6 class | ||
// */ | ||
If you encounter issues with the inherits function and the default constructor chain in ES6 class, you may need to add a constructor function to the derived class in order to call the parent constructor. Alternatively, you can use the traditional function syntax to define your classes and implement inheritance, rather than the ES6 class syntax. For example, you can define a root function and a derived function using the traditional syntax, and then use the inherits function to implement inheritance between them. This way, you can avoid the issue of needing to define a constructor in the derived class. | ||
*/ | ||
constructor() { | ||
if (!this.Class) this.Class = getPrototypeOf(this).constructor | ||
// this `Class` prop is only created by the `inherits` function or `newPrototype` function. | ||
if (!this.Class) { | ||
const proto = getPrototypeOf(this) | ||
const cls = proto.constructor | ||
defineProperty(this, 'Class', cls) | ||
if (!cls.__super__) defineProperty(cls, '__super__', getPrototypeOf(proto)) | ||
} | ||
const Parent = getParentClass(this.Class) | ||
@@ -114,38 +140,52 @@ // create the instance by calling the parent constructor | ||
#### usage | ||
#### Usage | ||
```coffee | ||
```javascript | ||
const assert = require('assert') | ||
const inherits = require('inherits-ex/lib/inherits') | ||
const isInheritedFrom = require('inherits-ex/lib/isInheritedFrom') | ||
const getParentClass = require('inherits-ex/lib/getParentClass') | ||
const log = console.log.bind console | ||
# Coffee@1 | ||
assert = require('assert') | ||
inherits = require('inherits-ex/lib/inherits') | ||
isInheritedFrom = require('inherits-ex/lib/isInheritedFrom') | ||
log = console.log.bind console | ||
function getSuper(obj) { | ||
return getParentClass(obj).prototype | ||
} | ||
class Root | ||
m: -> log('root') | ||
class Root{ | ||
m() {log('root')} | ||
} | ||
class A | ||
inherits A, Root | ||
m: -> | ||
class A{ | ||
m(){ | ||
log('A') | ||
super | ||
getSuper(this).m.call(this) | ||
// super.m() | ||
} | ||
} | ||
inherits(A, Root) | ||
class B | ||
inherits B, Root | ||
m: -> | ||
class B { | ||
m() { | ||
log('B') | ||
super | ||
getSuper(this).m.call(this) | ||
// super.m() | ||
} | ||
} | ||
inherits(B, Root) | ||
class MyClass | ||
# MyClass -> A -> Root | ||
inherits MyClass, B | ||
# MyClass -> A -> B -> Root | ||
inherits MyClass, A | ||
assert.notOk inherits(A, Root) #duplication inheritances prohibited. | ||
assert.ok isInheritedFrom(MyClass, A) | ||
assert.ok isInheritedFrom(MyClass, Root) | ||
assert.ok isInheritedFrom(MyClass, B) | ||
class MyClass { | ||
} | ||
// MyClass -> A -> Root | ||
inherits(MyClass, B) | ||
// MyClass -> A -> B -> Root | ||
inherits(MyClass, A) | ||
// duplication inheritances prohibited. | ||
assert.notOk(inherits(A, Root)) | ||
assert.ok(isInheritedFrom(MyClass, A)) | ||
assert.ok(isInheritedFrom(MyClass, Root)) | ||
assert.ok(isInheritedFrom(MyClass, B)) | ||
``` | ||
@@ -155,31 +195,40 @@ | ||
```coffee | ||
```javascript | ||
class Root { | ||
static static = 1 | ||
m() {log('root')} | ||
} | ||
class Root | ||
@static: 1 | ||
m: -> log('root') | ||
class A | ||
m: -> | ||
class A { | ||
m() { | ||
log('A') | ||
super | ||
super.m() | ||
} | ||
} | ||
class B | ||
m: -> | ||
class B { | ||
m() { | ||
log('B') | ||
super | ||
super.m() | ||
} | ||
} | ||
class MyClass | ||
# create inheritances chain: | ||
# MyClass -> A -> B -> Root | ||
inherits MyClass, [A, B, Root] | ||
class MyClass { | ||
} | ||
assert.ok isInheritedFrom(MyClass, A) | ||
assert.ok isInheritedFrom(MyClass, Root) | ||
assert.ok isInheritedFrom(MyClass, B) | ||
assert.equal MyClass.static, 1 | ||
// Create inheritances chain: MyClass -> A -> B -> Root | ||
inherits(MyClass, [A, B, Root]) | ||
assert.ok(isInheritedFrom(MyClass, A)) | ||
assert.ok(isInheritedFrom(MyClass, Root)) | ||
assert.ok(isInheritedFrom(MyClass, B)) | ||
assert.equal(MyClass.static, 1) | ||
``` | ||
### inheritsDirectly(ctor, superCtor, staticInherit = true) | ||
### inheritsDirectly | ||
Enables dynamic prototypal inheritance between classes, allowing for flexible and reusable code. | ||
`inheritsDirectly(ctor:Function, superCtor:Function, staticInherit = true)` | ||
* `staticInherit` (*boolean*): whether static inheritance,defaults to true. | ||
@@ -191,7 +240,13 @@ | ||
The standard `inherits` implementation in node.js environment with coffee-script supports | ||
and browser-friendly. | ||
The `inheritsDirectly` function is compatible with both ES5 and ES6, as well as older browsers that do not support these versions of JavaScript. | ||
The function also supports CoffeeScript-generated classes | ||
### isInheritedFrom(ctor, superCtor|superCtorName, raiseError=false) | ||
**Note**: If a parent class already exists on the class, it will be replaced by the new parent class. | ||
### isInheritedFrom | ||
Determines if a constructor(class) is inherited from a given super constructor(class). | ||
`isInheritedFrom(ctor, superCtor|superCtorName, raiseError=false)` | ||
```js | ||
@@ -206,6 +261,18 @@ var isInheritedFrom = require('inherits-ex/lib/isInheritedFrom') | ||
### mixin(ctor, superCtor|superCtor[], options:{ filter: number|function}) | ||
### mixin | ||
`mixin(ctor:Function, superCtor:Function|Function[], options:{ filter: number|function})` | ||
Mixin the methods and properties of the SuperCtor: Clone(Copy) all `superCtor`'s properties(methods) to ctor. | ||
Mixes the methods and properties from one or more classes to the target class. | ||
By default, all properties and methods from the `superCtors` will be cloned into the internal `mixinCtor_` | ||
constructor of the target class(`ctor`). This can be customized by providing the `options.filter` parameter. | ||
If the target class does not already have a `mixinCtor_` constructor it'll create the new constructor | ||
`mixinCtor_` which is then inherited by the `ctor`(target class). The `mixinCtor_` is also set as a property of the | ||
`ctor`. | ||
* options: | ||
@@ -218,4 +285,4 @@ * filter: defaults to 0. | ||
* `function(name, value){return value}` the callback function of filter. | ||
* name: the property name | ||
* value: the property value. | ||
* `name`: the property name | ||
* `value`: the property value. | ||
@@ -228,3 +295,3 @@ ```js | ||
* duplication mixin or inheritance check | ||
* Duplication mixin or inheritance check | ||
* **NOTE:**:the methods in mixins using `super()` will jump to the old class(not stay on the class). | ||
@@ -235,35 +302,42 @@ * The mixined properties(methods) are cloned(copied) from superCtors(includes the static members) | ||
``` coffee | ||
## Coffee@2.x | ||
mCallOrder = [] | ||
class Root | ||
```javascript | ||
const mCallOrder = [] | ||
class Root {} | ||
class C extends Root | ||
m: -> | ||
mCallOrder.push 'C' | ||
super | ||
class C extends Root { | ||
m() { | ||
mCallOrder.push('C') | ||
super() | ||
} | ||
} | ||
class A | ||
m: -> | ||
mCallOrder.push 'A' | ||
class A { | ||
m() { | ||
mCallOrder.push('A') | ||
} | ||
} | ||
class A1 extends A | ||
m: -> | ||
mCallOrder.push 'A1' | ||
super | ||
class A1 extends A { | ||
m() { | ||
mCallOrder.push('A1') | ||
super() | ||
} | ||
} | ||
class B | ||
inherits B, Root | ||
class B {} | ||
inherits(B, Root) | ||
class B1 extends B | ||
m: -> | ||
mCallOrder.push 'B1' | ||
super | ||
class B1 extends B { | ||
m() { | ||
mCallOrder.push('B1') | ||
super() | ||
} | ||
} | ||
mixin(B1, [A1, C]).should.be.equal true, 'mixin' | ||
o = new B1() | ||
o.m("a", 12) # call chain: B1::m -> C::m | ||
mixin(B1, [A1, C]).should.be.equal(true, 'mixin') | ||
const o = new B1() | ||
o.m("a", 12) // call chain: B1::m -> C::m | ||
A::m.should.have.been.calledOnce | ||
A::m.should.have.been.calledWith "a", 12 | ||
mCallOrder.should.be.deep.equal ['B1', 'C'] | ||
A::m.should.have.been.calledWith("a", 12) | ||
mCallOrder.should.be.deep.equal(['B1', 'C']) | ||
``` | ||
@@ -274,6 +348,8 @@ | ||
### isMixinedFrom(ctor, superCtor|superCtorName) | ||
### isMixinedFrom | ||
check the ctor whether is mixined from superCtor. | ||
`isMixinedFrom(ctor: Function, superCtor: Function|string)` | ||
Check if a constructor(`ctor`) is mixed from a specific constructor(`superCtor`). | ||
```js | ||
@@ -283,6 +359,13 @@ var isMixinedFrom = require('inherits-ex/lib/isMixinedFrom') | ||
### createCtor(name, args, body) | ||
### createCtor | ||
`createCtor(name: string, args: Array|string, body: string|null|undefined): Function` | ||
Create a constructor(class) dynamically. | ||
* Creates a constructor function dynamically with the given name, arguments, and body. | ||
* If the arguments are a string, it is assumed to be the body and the arguments are set to an empty array. | ||
* If the body is null or undefined, a default body is created that calls the parent constructor. | ||
* `name`(*string*): the class name | ||
@@ -299,4 +382,6 @@ * `args`(*any[]*): the optional constructor's args. | ||
### createObject(ctor, args...) | ||
### createObject | ||
`createObject(ctor: Function, ...args)` | ||
The helper function to create the object dynamically and arguments provided individually. | ||
@@ -338,19 +423,24 @@ | ||
```coffee | ||
```javascript | ||
class RefObject { | ||
constructor() {this.initialize.apply(this, arguments)} | ||
} | ||
class MyObject { | ||
initialize(a, b) { | ||
this.a = a | ||
this.b = b | ||
} | ||
} | ||
inherits(MyObject, RefObject) | ||
class RefObject | ||
constructor: -> @initialize.apply @, arguments | ||
class MyObject | ||
inherits MyObject, RefObject | ||
initialize: (@a,@b)-> | ||
super | ||
obj = createObject(MyObject, "a", "b") | ||
# obj = new MyObject("a", "b") # it will have no property a and b. | ||
assert.equal obj.a "a" | ||
assert.equal obj.b "b" | ||
// obj = new MyObject("a", "b") // it will have no property a and b. | ||
assert.equal(obj.a, "a") | ||
assert.equal(obj.b, "b") | ||
``` | ||
### createObjectWith(ctor, [args...]) | ||
### createObjectWith | ||
`createObjectWith(ctor, args: Array)` | ||
The helper function to create the object dynamically. provides the arguments as an array (or an array-like object). | ||
@@ -365,4 +455,6 @@ | ||
### createFunction(name, [args,] body[, scope[, values]]) | ||
### createFunction | ||
`createFunction(name: string, [args,] body[, scope[, values]])` | ||
* arguments: | ||
@@ -382,21 +474,1 @@ * `name` *(String)*: the function name | ||
``` | ||
Usage: | ||
```coffee | ||
class RefObject | ||
constructor: -> @initialize.apply @, arguments | ||
class MyObject | ||
inherits MyObject, RefObject | ||
initialize: (@a,@b)-> | ||
super | ||
obj = createObject(MyObject, "a", "b") | ||
#obj = new MyObject("a", "b") # it will have no property a and b. | ||
assert.equal obj.a "a" | ||
assert.equal obj.b "b" | ||
``` |
@@ -6,2 +6,16 @@ module.exports = extend; | ||
/** | ||
* Copies properties from one or more source objects to a target object. | ||
* | ||
* The extend function takes an object target as its first argument, and any | ||
* number of additional objects as subsequent arguments. It copies all properties | ||
* from each source object to the target object, and returns the modified target object. | ||
* | ||
* Only copies properties that are directly on the source object (not inherited). | ||
* | ||
* @param {Object} target - The target object to copy properties to. | ||
* @param {...Object} sources - One or more source objects to copy properties from. | ||
* @returns {Object} The modified target object. | ||
*/ | ||
function extend(target) { | ||
@@ -8,0 +22,0 @@ for (var i = 1; i < arguments.length; i++) { |
var createFunction = require('./createFunction'); | ||
var isString = function(v){return typeof v === 'string';}; | ||
//create a contructor function dynamically. | ||
module.exports = function(name, args, body) { | ||
/** | ||
* Creates a constructor function dynamically with the given name, arguments, and body. | ||
* If the arguments are a string, it is assumed to be the body and the arguments are set to an empty array. | ||
* If the body is null or undefined, a default body is created that calls the parent constructor. | ||
* | ||
* @param {string} name - The name of the constructor function. | ||
* @param {Array|string} args - The arguments of the constructor function. | ||
* @param {string|null|undefined} body - The body of the constructor function. | ||
* @returns {Function} - The constructor function. | ||
*/ | ||
function createCtor(name, args, body) { | ||
if (isString(args)) { | ||
@@ -10,4 +19,7 @@ body = args; | ||
} | ||
if (body == null) body = 'return ' + name + '.__super__.constructor.apply(this, arguments);' | ||
var parentPrototype = '(' + name + '.__super__||Object.getPrototypeOf(' + name + ').prototype)'; | ||
if (body == null) body = 'var p=' + parentPrototype + ';return p?p.constructor.apply(this, arguments):undefined;' | ||
return createFunction(name, args, body); | ||
}; | ||
module.exports = createCtor |
@@ -18,3 +18,16 @@ //Write by http://stackoverflow.com/users/1048572/bergi | ||
module.exports = function(name, args, body, scope, values) { | ||
/** | ||
* Creates a new function with the given name, arguments, body, scope, and values. | ||
* | ||
* @param {string} name - The name of the function. | ||
* @param {string|string[]} args - The argument names of the function if it's `string[]`, else it's the function body without arguments. | ||
* @param {string} body - The body of the function. | ||
* @param {string[]|Object=} scope - The scope of the function. | ||
* @param {Array=} values - The values of the `scope` if the `scope` is `string[]``. | ||
* @returns {Function} - The created function. | ||
* | ||
* @example | ||
* var fn = createFunction('yourFuncName', ['arg1', 'arg2'], 'return log(arg1+arg2);', {log:console.log.bind(console)}); | ||
*/ | ||
function createFunction(name, args, body, scope, values) { | ||
if (arguments.length === 1) return Function('function ' + name + '(){}\nreturn ' + name + ';')(); | ||
@@ -39,4 +52,7 @@ if (isString(args)) { | ||
} | ||
if (typeof body !== 'string') body = '' | ||
return Function(scope, | ||
'function ' + name + '(' + args.join(', ') + ') {\n' + body + '\n}\nreturn ' + name + ';').apply(null, values); | ||
}; | ||
module.exports = createFunction |
@@ -7,3 +7,20 @@ var setPrototypeOf = require('./setPrototypeOf'); | ||
module.exports = function(aClass) { | ||
/** | ||
* Creates a new instance of the given class using the specified arguments. | ||
* @param {Function} aClass - The class to instantiate. | ||
* @param {...*} args - The arguments to pass to the constructor of the class. | ||
* @returns {*} - A new instance of the class. | ||
* @example | ||
* // Define a class | ||
* class Person { | ||
* constructor(name, age) { | ||
* this.name = name; | ||
* this.age = age; | ||
* } | ||
* } | ||
* // Create a new instance of the Person class | ||
* const john = createObject(Person, 'John', 30); | ||
* console.log(john); // Output: Person { name: 'John', age: 30 } | ||
*/ | ||
function createObject(aClass) { | ||
var result = new (Function.prototype.bind.apply(aClass, arguments)); | ||
@@ -40,1 +57,2 @@ if (aClass !== Object && aClass !== Array && aClass !== RegExp) { | ||
module.exports = createObject |
@@ -6,3 +6,23 @@ var hasNativeReflect = require('./isNativeReflectConstruct').hasNativeReflect | ||
module.exports = function(aClass, aArguments) { | ||
/** | ||
* Creates a new instance of the given class using the specified arguments. | ||
* | ||
* @param {function} aClass - The class to create an instance of. | ||
* @param {Array} aArguments - Arguments to pass to the class constructor. | ||
* @returns {object} A new instance of the class. | ||
* | ||
* @example | ||
* // Define a class | ||
* class Person { | ||
* constructor(name, age) { | ||
* this.name = name; | ||
* this.age = age; | ||
* } | ||
* } | ||
* | ||
* // Create a new instance of the Person class | ||
* const john = createObjectWith(Person, ['John', 30]); | ||
* console.log(john); // Output: Person { name: 'John', age: 30 } | ||
*/ | ||
function createObjectWith(aClass, aArguments) { | ||
var args = [aClass]; | ||
@@ -40,1 +60,3 @@ if (aArguments) | ||
}; | ||
module.exports = createObjectWith |
@@ -1,6 +0,15 @@ | ||
var extend = require('./_extend'); | ||
var _extend = require('./_extend'); | ||
module.exports = function(ctor, superCtors) { | ||
extend(ctor.prototype, superCtors.prototype); | ||
/** | ||
* Extends the prototype of the given constructor with the prototypes of one or more super constructors. | ||
* | ||
* @param {function} ctor - The constructor to extend the prototype of. | ||
* @param {...function} superCtors - The super constructors whose prototypes should be copied onto the extended prototype. | ||
* @returns {function} The extended constructor `ctor`. | ||
*/ | ||
function extend(ctor, superCtors) { | ||
_extend(ctor.prototype, superCtors.prototype); | ||
return ctor; | ||
}; | ||
module.exports = extend |
@@ -6,7 +6,13 @@ var isEmptyFunction = require('./isEmptyFunction') | ||
//get latest non-empty constructor function through inherits link: | ||
module.exports = function (ctor) { | ||
//get latest non-empty constructor function through inherits link | ||
/** | ||
* Returns the first(latest) non-empty constructor in the inheritance chain of the given constructor that has own properties. | ||
* | ||
* @param {function} ctor - The constructor to get the first non-empty constructor of. | ||
* @returns {function} The first(latest) non-empty constructor in the inheritance chain of the given constructor. | ||
*/ | ||
function getConstructor(ctor) { | ||
var result = ctor; | ||
var isEmpty = isEmptyFunction(result); | ||
// console.log('getConstructor', result.toString(), isEmpty) | ||
var v = result.super_ || getPrototypeOf(result); | ||
@@ -18,6 +24,5 @@ while (isEmpty && v && v !== objectSuperCtor) { | ||
} | ||
// console.log('getConstructor', result.toString()) | ||
//if (isEmpty) result = null; | ||
return result; | ||
} | ||
module.exports = getConstructor |
@@ -6,25 +6,20 @@ var isArray = Array.isArray; | ||
var defineProperty = require('./defineProperty'); | ||
var getParentCtor = require('./getParentClass'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
* Inherit the prototype methods from one constructor into another. | ||
* Inherit the prototype properties and methods from one constructor into another. | ||
* | ||
* | ||
* The Function.prototype.inherits from lang.js rewritten as a standalone | ||
* function (not on Function.prototype). NOTE: If this file is to be loaded | ||
* during bootstrapping this function needs to be rewritten using some native | ||
* functions as prototype setup using normal JavaScript does not work as | ||
* expected during bootstrapping (see mirror.js in r114903). | ||
* | ||
* @param {function} ctor Constructor function which needs to inherit the | ||
* prototype. | ||
* @param {function} superCtor Constructor function to inherit prototype from. | ||
* @param {boolean} staticInherit whether allow static members inheritance,defaults to true. | ||
* @param {function} ctor the class which needs to inherit the prototype. | ||
* @param {function} superCtor the parent class to inherit prototype from. | ||
* @param {boolean=true} staticInherit whether allow static members inheritance, defaults to true. | ||
* @returns The function returns true if inheritance was successful. | ||
*/ | ||
function inherits(ctor, superCtor, staticInherit) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
function _inherits(ctor, superCtor, staticInherit) { | ||
var v = getParentCtor(ctor); | ||
var mixinCtor = ctor.mixinCtor_; | ||
if (mixinCtor && v === mixinCtor) { | ||
ctor = mixinCtor; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
v = getParentCtor(ctor); | ||
} | ||
@@ -40,3 +35,3 @@ var result = false; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
v = getParentCtor(ctor); | ||
} | ||
@@ -57,8 +52,81 @@ result = true; | ||
module.exports = function(ctor, superCtors, staticInherit) { | ||
if (!isArray(superCtors)) return inherits(ctor, superCtors, staticInherit); | ||
/** | ||
* A powerful tool for implementing class inheritance that supports dynamic inheritance and multiple inheritance. | ||
* | ||
* **Features**: | ||
* | ||
* * Supports dynamic inheritance. | ||
* * Preserves existing methods and properties in the child class's prototype instead of overwriting them. | ||
* * Avoids circular dependencies by checking if the parent class has already inherited from the child class. | ||
* * Avoids duplicate inheritance by checking if the child class has already inherited from the parent class. | ||
* * Supports multiple inheritance by allowing an array of parent classes to be passed in. | ||
* * Optional static members inheritance. | ||
* | ||
* The function is compatible with both ES5 and ES6, as well as older browsers that do not support these | ||
* versions of JavaScript. The function also supports CoffeeScript-generated classes. | ||
* | ||
* **Note**: | ||
* | ||
* * When using the `inherits` function, these two properties are added to the constructor function(`ctor`). | ||
* * The `super_` property refers to the parent constructor. | ||
* * The `__super__` property refers to the parent's prototype object, | ||
* which can be used for the `super` keyword in CoffeeScript. | ||
* * In addition, the `Class` property is added to the prototype object of the constructor function (`ctor`). | ||
* * This property points to the current class(`ctor`). | ||
* * This property can also be accessed by instances of the class. | ||
* * It is important to note that for the empty constructor, the instance of `ctor` may not be the current class, | ||
* but the `Class` property is always set to the current class for instance. | ||
* | ||
* | ||
* @param {Function} ctor the child class that needs to inherit from the parent class. | ||
* @param {Function|Function[]} superCtors the parent class that the child class needs to inherit from. | ||
* The first class is the parent of child class ctor, the left classes will be chained(inherits) one by one, | ||
* if `superCtors` is an array of classes. | ||
* @param {boolean=true} staticInherit optional indicating whether or not the static properties of the parent class should be inherited as well. | ||
* @returns {boolean} returns true if inheritance was successful. | ||
* | ||
* @example | ||
* | ||
* class Animal { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* | ||
* speak() { | ||
* console.log(this.name + ' makes a noise.'); | ||
* } | ||
* } | ||
* | ||
* class Dog extends Animal { | ||
* constructor(name, breed) { | ||
* super(name); | ||
* this.breed = breed; | ||
* } | ||
* | ||
* speak() { | ||
* console.log(this.name + ' barks.'); | ||
* } | ||
* } | ||
* | ||
* function Cat(name, breed) { | ||
* this.name = name; | ||
* this.breed = breed; | ||
* } | ||
* | ||
* Cat.prototype.meow = function() { | ||
* console.log(this.name + ' meows.'); | ||
* }; | ||
* | ||
* inherits(Cat, [Animal]); | ||
* | ||
* const fluffy = new Cat('Fluffy', 'Siamese'); | ||
* fluffy.speak(); // Output: Fluffy makes a noise. | ||
* fluffy.meow(); // Output: Fluffy meows. | ||
*/ | ||
module.exports = function inherits(ctor, superCtors, staticInherit) { | ||
if (!isArray(superCtors)) return _inherits(ctor, superCtors, staticInherit); | ||
for (var i = superCtors.length - 1; i >= 0; i--) { | ||
if (!inherits(ctor, superCtors[i], staticInherit)) return false; | ||
if (!_inherits(ctor, superCtors[i], staticInherit)) return false; | ||
} | ||
return true; | ||
} |
@@ -6,3 +6,15 @@ var newPrototype = require('./newPrototype'); | ||
//just replace the ctor.super to superCtor, | ||
module.exports = function(ctor, superCtor, staticInherit) { | ||
/** | ||
* Enables dynamic prototypal inheritance between classes, allowing for flexible and reusable code. | ||
* | ||
* The `inheritsDirectly` function is compatible with both ES5 and ES6, as well as older browsers that do not support these versions of JavaScript. | ||
* The function also supports CoffeeScript-generated classes | ||
* | ||
* **Note**: If a parent class already exists on the class, it will be replaced by the new parent class. | ||
* | ||
* @param {Function} ctor The child class that will inherit from the parent class. | ||
* @param {Function} superCtor The parent class from which the child class will inherit. | ||
* @param {boolean=} staticInherit Optional A boolean flag indicating whether the child class should also inherit static properties and methods from the parent class. The default value is `true`. | ||
*/ | ||
module.exports = function inheritsDirectly(ctor, superCtor, staticInherit) { | ||
defineProperty(ctor, 'super_', superCtor); | ||
@@ -9,0 +21,0 @@ defineProperty(ctor, '__super__', superCtor.prototype);//for coffeeScript super keyword. |
@@ -5,6 +5,34 @@ var inherits = require('./inherits'); | ||
//make sure the aClass.prototype hook to the aObject instance. | ||
module.exports = function(aObject, aClass, staticInherit) { | ||
// ES6: Object.getPrototypeOf / Object.setPrototypeOf | ||
/** | ||
* Sets the prototype of an object to a new prototype, and inherits from a given class. | ||
* | ||
* make sure the aClass.prototype hook to the aObject instance. | ||
* | ||
* @param {Object} aObject - The object whose prototype needs to be set. | ||
* @param {Function} aClass - The class to inherit from. | ||
* @param {boolean} staticInherit - Whether to inherit static properties or not. | ||
* @returns {boolean} - Whether the prototype was successfully set or not. | ||
* @example | ||
* ```js | ||
* class Person { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* | ||
* sayHello() { | ||
* console.log(`Hello, my name is ${this.name}`); | ||
* } | ||
* } | ||
* | ||
* const john = new Person('John'); | ||
* const jane = {name: 'Jane'}; | ||
* | ||
* // make object Inherit from Person | ||
* inheritsObject(jane, Person); | ||
* | ||
* // Now jane's prototype is Person, and she can call sayHello | ||
* jane.sayHello(); // logs "Hello, my name is Jane" | ||
* ``` | ||
*/ | ||
function inheritsObject(aObject, aClass, staticInherit) { | ||
var vOldProto = getPrototypeOf(aObject); | ||
@@ -19,1 +47,3 @@ var result = false; | ||
}; | ||
module.exports = inheritsObject |
@@ -1,2 +0,8 @@ | ||
module.exports = function(vStr) { | ||
/** | ||
* Determines whether the given string represents an empty constructor. | ||
* | ||
* @param {string} vStr - The string to check. | ||
* @returns {boolean} - Returns true if the string represents an empty constructor, otherwise false | ||
*/ | ||
function isEmptyCtor(vStr) { | ||
var isClass = /^class\s+/.test(vStr); | ||
@@ -12,1 +18,3 @@ var result | ||
}; | ||
module.exports = isEmptyCtor |
@@ -0,3 +1,9 @@ | ||
/** | ||
* Determines whether the given string represents an empty constructor. | ||
* | ||
* @param {string} vStr - The string to check. | ||
* @returns {boolean} - Returns true if the string represents an empty constructor, otherwise false | ||
*/ | ||
module.exports = function(aFunc) { | ||
return /^function\s*\S*\s*\((.|[\n\r\u2028\u2029])*\)\s*{[\s;]*}$/g.test(aFunc.toString()); | ||
}; |
var isEmptyCtor = require('./isEmptyCtor'); | ||
module.exports = function(aFunc, istanbul) { | ||
/** | ||
* Checks whether a given function is empty or not. | ||
* @param {Function} aFunc - The function to be checked. | ||
* @param {boolean} istanbul - whether has istanbul TODO: remove this! | ||
* @returns {boolean} - True if the function is empty, false otherwise. | ||
*/ | ||
module.exports = function isEmptyFunction(aFunc, istanbul) { | ||
var vStr = aFunc.toString(); | ||
@@ -5,0 +11,0 @@ var result = /^function\s*\S*\s*\((.|[\n\r\u2028\u2029])*\)\s*{[\s;]*}$/g.test(vStr); |
@@ -6,3 +6,11 @@ var isInheritedFromStr = require('./isInheritedFromStr'); | ||
module.exports = function(ctor, superCtor, throwError) { | ||
/** | ||
* Determines if a constructor(class) is inherited from a given super constructor(class). | ||
* @param {Function} ctor - The constructor function to check. | ||
* @param {Function|string} superCtor - The super constructor to check for inheritance. Can be the name of the super constructor. | ||
* @param {boolean=false} throwError - If true, an error will be thrown if a circular inheritance is found. | ||
* @returns {boolean|Function} - If the constructor is inherited from the super constructor, returns the constructor. | ||
* Otherwise, returns false. | ||
*/ | ||
module.exports = function isInheritedFrom(ctor, superCtor, throwError) { | ||
if (typeof superCtor === 'string') return isInheritedFromStr(ctor, superCtor, throwError); | ||
@@ -9,0 +17,0 @@ if (ctor === superCtor) { |
var getPrototypeOf = require('./getPrototypeOf'); | ||
module.exports = function(ctor, superStr, throwError) { | ||
/** | ||
* Determines if a constructor(class) is inherited from a given the name of super constructor(class). | ||
* @param {Function} ctor - The constructor function to check. | ||
* @param {string} superStr - The super constructor's name to check for inheritance. | ||
* @param {boolean=false} throwError - If true, an error will be thrown if a circular inheritance is found. | ||
* @returns {boolean|Function} - If the constructor is inherited from the super constructor, returns the constructor. | ||
* Otherwise, returns false. | ||
*/ | ||
module.exports = function isInheritedFromStr(ctor, superStr, throwError) { | ||
if (ctor.name === superStr) { | ||
@@ -5,0 +13,0 @@ if (throwError) |
var isMixinedFromStr = require('./isMixinedFromStr'); | ||
module.exports = function(ctor, superCtor) { | ||
/** | ||
* Check if a constructor is mixed from a specific constructor. | ||
* @param {function} ctor - The constructor to check. | ||
* @param {function|string} superCtor - The constructor to check if the `ctor` is mixed from. Can be the name of the constructor. | ||
* @returns {boolean} - True if `ctor` is mixed from `superCtor`, otherwise false. | ||
*/ | ||
module.exports = function isMixinedFrom(ctor, superCtor) { | ||
if (typeof superCtor === 'string') return isMixinedFromStr(ctor, superCtor); | ||
@@ -5,0 +11,0 @@ var mixinCtors = ctor.mixinCtors_; |
@@ -1,2 +0,8 @@ | ||
module.exports = function(ctor, superStr) { | ||
/** | ||
* Check if a constructor is mixed from a specific constructor. | ||
* @param {function} ctor - The constructor to check. | ||
* @param {string} superStr - The name of constructor to check if the `ctor` is mixed from. | ||
* @returns {boolean} - True if `ctor` is mixed from `superCtor`, otherwise false. | ||
*/ | ||
module.exports = function isMixinedFromStr(ctor, superStr) { | ||
var result = false; | ||
@@ -3,0 +9,0 @@ var mixinCtors = ctor.mixinCtors_; |
@@ -0,1 +1,5 @@ | ||
/** | ||
* Checks if the current environment supports native Reflect.construct method. | ||
* @returns {boolean} True if the current environment supports native Reflect.construct method, false otherwise. | ||
*/ | ||
function isNativeReflectConstruct() { | ||
@@ -2,0 +6,0 @@ if (typeof Reflect === "undefined" || !Reflect.construct) return false; |
194
src/mixin.js
@@ -9,7 +9,22 @@ var inheritsDirectly = require('./inheritsDirectly'); | ||
var extendPrototype = require('./extend'); | ||
var getParentCtor = require('./getParentClass'); | ||
var getOwnPropertyNames = Object.getOwnPropertyNames; | ||
/** | ||
* Enum for filter type | ||
* @readonly | ||
* @enum {number} | ||
*/ | ||
var filterOpts = { | ||
/** | ||
* Include all members from the superCtor | ||
*/ | ||
'all': 0, | ||
/** | ||
* Throw error if the method of superCtor using the `super()` | ||
*/ | ||
'errSuper': 1, | ||
/** | ||
* Skip the method if the method of superCtor using the `super()` | ||
*/ | ||
'skipSuper': 2 | ||
@@ -30,3 +45,3 @@ }; | ||
/** | ||
/* | ||
* Mixin multi classes to ctor. | ||
@@ -57,39 +72,45 @@ * mixin(Class, ParentClass1, ParentClass2, ...) | ||
```coffee | ||
class Root | ||
m: -> | ||
@example | ||
```js | ||
class Root { | ||
m() { | ||
console.log 'root' | ||
console.log '----' | ||
class C | ||
inherits C, Root | ||
m: -> | ||
console.log "c" | ||
super | ||
class B | ||
inherits B, Root | ||
m: -> | ||
console.log "b" | ||
super | ||
class B11 | ||
inherits B11, B | ||
m: -> | ||
console.log 'b11' | ||
super | ||
} | ||
} | ||
class C extends Root { | ||
m() { | ||
console.log("c") | ||
super.m() | ||
} | ||
} | ||
class B extends Root { | ||
m() { | ||
console.log("b") | ||
super.m() | ||
} | ||
} | ||
b = new B11 | ||
class B11 extends B { | ||
m() { | ||
console.log('b11') | ||
super.m() | ||
} | ||
} | ||
let b = new B11 | ||
b.m() | ||
mixin B11, C | ||
mixin(B11, C) | ||
b = new B11 | ||
b.m() | ||
# The console results: | ||
# b11 | ||
# b | ||
# root | ||
# ---- | ||
# b11 | ||
# c | ||
# root | ||
# ---- | ||
// The console results: | ||
// b11 | ||
// b | ||
// root | ||
// ---- | ||
// b11 | ||
// c | ||
// root | ||
// ---- | ||
``` | ||
@@ -107,3 +128,3 @@ | ||
var vStr = aMethod.toString(); | ||
return vStr.indexOf('__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
return vStr.indexOf('.__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
} | ||
@@ -120,3 +141,3 @@ // function isSuperInFunction(aMethod) { | ||
function _mixinGenMethod(aMixinSuper, aMethod, src) { | ||
var oldSuper = src.__super__; | ||
// var oldSuper = src.__super__; | ||
return function() { | ||
@@ -182,3 +203,3 @@ // src.__super__ = aMixinSuper; | ||
var value = filter(k, src[k]); | ||
if (value !== void 0) dest[k] = value; | ||
if (value !== undefined) dest[k] = value; | ||
} | ||
@@ -191,6 +212,6 @@ } | ||
if (n === name) { | ||
value = void 0; | ||
value = undefined; | ||
break; | ||
} | ||
if (value !== void 0) value = filter(name, value); | ||
if (value !== undefined) value = filter(name, value); | ||
} | ||
@@ -208,6 +229,6 @@ return value; | ||
if (n === name) { | ||
value = void 0; | ||
value = undefined; | ||
break; | ||
} | ||
if (value !== void 0) value = filter(name, value); | ||
if (value !== undefined) value = filter(name, value); | ||
} | ||
@@ -228,3 +249,3 @@ return value; | ||
// console.log(k, value) | ||
if (value !== void 0) dp[k] = value; | ||
if (value !== undefined) dp[k] = value; | ||
// continue; | ||
@@ -237,3 +258,3 @@ | ||
// just override the property simply. | ||
// if (mixinedMethod !== void 0 && typeof mixinedMethod !== 'function') { | ||
// if (mixinedMethod !== undefined && typeof mixinedMethod !== 'function') { | ||
// // Already be defined as property in the mixin ctor | ||
@@ -297,6 +318,32 @@ // continue; | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
* @callback FilterFn | ||
* @param {string} name | ||
* @param {any} value | ||
* @returns {any} include it return value directly or return undefined | ||
*/ | ||
/** | ||
* | ||
* @param {Function} ctor the class that needs to mixin from the `superCtor` class. | ||
* @param {Function} superCtor The super class that the `ctor` needs to inherit from. | ||
* @param {FilterFn|string[]|filterOpts=} options.filter (optional) A filter that specifies which members to include | ||
* from the superCtor. | ||
* | ||
* * This can be a function that takes a `name` and `value` parameter and returns a value to include or `undefined` | ||
* * an array of strings that represent member names to include | ||
* * or the filter options (`filterOpts`) available (`all`, `errSuper`, or `skipSuper`) | ||
* * `all`: include all members from the superCtor without check whether the method used the `super()`. | ||
* * `errSuper`: Throw error if the method of superCtor using the `super()` | ||
* * `skipSuper`: skip the method if the method of superCtor using the `super()` | ||
* | ||
* @returns return true if successful | ||
*/ | ||
function mixin(ctor, superCtor, options) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); // original superCtor | ||
var v = getParentCtor(ctor); // original superCtor | ||
var result = false; | ||
// Check if the two classes are already related in some way to avoid circular or duplicate inheritance | ||
if (!isMixinedFrom(ctor, superCtor) && !isInheritedFrom(ctor, superCtor) && !isInheritedFrom(superCtor, ctor)) { | ||
// Create a mixin constructor function for the child class if one doesn't already exist | ||
var mixinCtor = ctor.mixinCtor_; | ||
@@ -328,3 +375,62 @@ var mixinCtors = ctor.mixinCtors_; | ||
var mixins = module.exports = function(ctor, superCtors, options) { | ||
/** | ||
* Mixes the methods and properties from one or more classes to the target class. | ||
* | ||
* By default, all properties and methods from the `superCtors` will be cloned into the internal `mixinCtor_` | ||
* constructor of the target class(`ctor`). This can be customized by providing the `options.filter` parameter. | ||
* | ||
* If the target class does not already have a `mixinCtor_` constructor it'll create the new constructor | ||
* `mixinCtor_` which is then inherited by the `ctor`(target class). The `mixinCtor_` is also set as a property of the | ||
* `ctor`. | ||
* | ||
* **Note**: | ||
* | ||
* 1. If a property or method exists with the same name in both `superCtors` and `ctor`'s `mixinCtor_`, the property | ||
* or method in the `superCtor` takes precedence. The last one will overwrite the previous one. | ||
* 2. the `mixin` does not create a prototype chain between "`superCtors`"(just copy the members from `superCtors`), so | ||
* you cannot clone these methods of `superCtor` which use the `super()`. If you need to use `super()` in these | ||
* methods, you should use `inherits` instead of `mixin`. | ||
* | ||
* @param {Function} ctor the target class that needs to mixin from the `superCtors` class. | ||
* @param {Function|Function[]} superCtors The class(es) to be used as sources of properties and methods. | ||
* @param {FilterFn|string[]|filterOpts=} options.filter (optional) A filter that specifies which members to include | ||
* from the `superCtor`. If no filter is specified, all properties and methods from `superCtor` will be mixed in. | ||
* | ||
* * It could be a function that takes a `name` and `value` parameter and returns a value to include or `undefined` | ||
* * Or an array of strings that represent member names to include | ||
* * Or the filter options (`filterOpts`) available (`all`, `errSuper`, or `skipSuper`) | ||
* * `all`: include all members from the superCtor without check whether the method used the `super()`. | ||
* * `errSuper`: Throw error if the method of superCtor using the `super()` | ||
* * `skipSuper`: skip the method if the method of superCtor using the `super()` | ||
* | ||
* @returns return true if successful | ||
* | ||
* @example | ||
* | ||
* class MixinA { | ||
* methodA() { | ||
* console.log('Method A called'); | ||
* } | ||
* } | ||
* | ||
* class MixinB { | ||
* methodB() { | ||
* console.log('Method B called'); | ||
* } | ||
* } | ||
* | ||
* class MyClass { | ||
* constructor() { | ||
* } | ||
* } | ||
* | ||
* // mixin both MixinA and MixinB | ||
* mixins(MyClass, [MixinA, MixinB]); // == mixins(MyClass, MixinA); mixins(MyClass, MixinB); | ||
* | ||
* const myObj = new MyClass(); | ||
* | ||
* myObj.methodA(); // logs 'Method A called' | ||
* myObj.methodB(); // logs 'Method B called' | ||
*/ | ||
function mixins(ctor, superCtors, options) { | ||
if (typeof superCtors === 'function') return mixin(ctor, superCtors, options); | ||
@@ -339,1 +445,3 @@ for (var i = 0; i < superCtors.length; i++) { | ||
mixins.filterOpts = filterOpts; | ||
module.exports = mixins |
@@ -5,3 +5,9 @@ var getConstructor = require('./getConstructor'); | ||
module.exports = function (aClass, aConstructor) { | ||
/** | ||
* Creates a new object with a prototype chain from a given class and constructor function. | ||
* @param {Function} aClass - The class to use as prototype chain. | ||
* @param {Function} [aConstructor] - The constructor function for the new object. | ||
* @returns {Object} - The newly created prototype object. | ||
*/ | ||
module.exports = function newPrototype(aClass, aConstructor) { | ||
//Object.create(prototype) only for ES5 | ||
@@ -37,4 +43,3 @@ //Object.create(prototype, initProps) only for ES6 | ||
extend(result, aConstructor.prototype); | ||
// console.log('TCL:: ~ file: newPrototype.js ~ line 36 ~ result', result, aConstructor); | ||
return result; | ||
}; |
@@ -6,3 +6,35 @@ var getPrototypeOf = require('./getPrototypeOf'); | ||
//just replace the object's constructor | ||
module.exports = function(aObject, aClass) { | ||
/** | ||
* Replace the prototype of an object with the prototype of a given class | ||
* @param {Object} aObject - The object whose prototype needs to be replaced | ||
* @param {Function} aClass - The class whose prototype should be used to replace the object's prototype | ||
* @returns {boolean} - Returns true if the object's prototype was successfully replaced, otherwise returns false | ||
* | ||
* @example | ||
* | ||
* class Person { | ||
* constructor(name) { | ||
* this.name = name; | ||
* } | ||
* greet() { | ||
* console.log('Hello, my name is '+ this.name); | ||
* } | ||
* } | ||
* | ||
* class Student { | ||
* constructor(name, major) { | ||
* super(name); | ||
* this.major = major; | ||
* } | ||
* greet() { | ||
* console.log("Hello, I'm student. My name is " + this.name); | ||
* } | ||
* } | ||
* const mary = new Person('Mary'); | ||
* mary.greet(); // logs "Hello, my name is Mary" | ||
* replaceCtor(mary, Student); // returns true | ||
* mary.greet(); // logs "Hello, I'm student. My name is Mary" | ||
*/ | ||
module.exports = function replaceCtor(aObject, aClass) { | ||
var vOldProto = getPrototypeOf(aObject); | ||
@@ -9,0 +41,0 @@ var result = false; |
@@ -287,2 +287,33 @@ var chai = require('chai') | ||
}) | ||
it('should ES6 class and function ctor mixed', () => { | ||
class Animal { | ||
constructor(name) { | ||
this.name = name; | ||
} | ||
speak(sound) { | ||
return this.name + ' ' + sound; | ||
} | ||
} | ||
class Dog extends Animal { | ||
constructor(name, breed) { | ||
super(name); | ||
this.breed = breed; | ||
} | ||
speak(sound) { | ||
if (!sound) sound = 'barks'; | ||
return super.speak(sound); | ||
} | ||
} | ||
function Cat(name, breed) { | ||
this.name = name; | ||
this.breed = breed; | ||
} | ||
Cat.prototype.meow = function() { | ||
return this.Class.__super__.speak.call(this, 'meows'); | ||
}; | ||
assert.equal(inherits(Cat, Animal), true); | ||
const fluffy = new Cat('Fluffy', 'Siamese'); | ||
assert.equal(fluffy.speak('meows.'), 'Fluffy meows.'); | ||
assert.equal(fluffy.meow('meows'), 'Fluffy meows'); | ||
}); | ||
@@ -412,3 +443,3 @@ | ||
} | ||
inherits(A2, R).should.be.ok() | ||
inherits(A2, R).should.be.ok | ||
a = createObject(A2) | ||
@@ -415,0 +446,0 @@ assert.instanceOf(a, A2) |
@@ -62,9 +62,9 @@ var chai = require('chai') | ||
o.m("a", 12) // call chain: B1::m -> A1::m -> A::m | ||
mCallOrder.should.be.deep.equal ['B1', 'A1', 'A'] | ||
mCallOrder.should.be.deep.equal(['B1', 'A1', 'A']) | ||
mCallOrder = [] | ||
o.mo() | ||
mCallOrder.should.be.deep.equal ['A1mo'] | ||
mCallOrder.should.be.deep.equal(['A1mo']) | ||
mCallOrder = [] | ||
o.m1() | ||
mCallOrder.should.be.deep.equal ['A1sm', 'Asm'] | ||
mCallOrder.should.be.deep.equal(['A1m1', 'A']) | ||
mCallOrder = [] | ||
@@ -90,4 +90,4 @@ }) | ||
B1.sm() | ||
mCallOrder.should.be.deep.equal ['A1sm', 'A'] | ||
mCallOrder.should.be.deep.equal(['A1sm', 'Asm']) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
196769
7
116
4525
457
5