docs: function createAbstractClass(params, constructor) {
          if (!isObject(params)) {
              throw new Error('Expected abstract class definition to be an object with the abstract class members.');
          }
          // Validate class name
          if (hasOwn(params, '$name')) {
              if (!isString(params.$name)) {
                  throw new Error('Abstract class name must be a string.');
              } else if (/\s+/.test(params.$name)) {
                  throw new Error('Abstract class name cannot have spaces.');
              }
          } else {
              params.$name = 'Unnamed';
          }
  
          var def,
              abstractObj = { methods: {}, staticMethods: {}, unimplemented: 0 },
              saved = {},
              key;
  
          // If we are extending an abstract class also, inherit the abstract methods
          if (isFunction(params.$extends)) {
              if (params.$extends[$abstract]) {
                  mixIn(abstractObj.methods, params.$extends[$abstract].methods);
                  mixIn(abstractObj.staticMethods, params.$extends[$abstract].staticMethods);
              }
          }
  
          // Handle abstract methods
          if (hasOwn(params, '$abstracts')) {
              saved.$abstracts = params.$abstracts;     // Save them for later use
          }
  
          // Handle interfaces
          if (hasOwn(params, '$implements')) {
              saved.$interfaces = params.$implements;   // Save them for later use
          }
  
          // Create the class definition
          def = Class.$create(params, constructor, { isAbstract: true });
  
          abstractObj.check = bind(checkClass, def);
  
          if (hasDefineProperty) {
              Object.defineProperty(def, $abstract, {
                  value: abstractObj,
                  writable: false
              });
          } else {
              def[$abstract] = abstractObj;
          }
  
          // Parse the saved interfaces
          if (hasOwn(saved, '$interfaces')) {
              parseInterfaces(saved.$interfaces, def);
          }
  
          // Parse the abstract methods
          if (hasOwn(saved, '$abstracts')) {
              parseAbstracts(saved.$abstracts, def);
          }
  
          // Finally update the unimplemented count
          for (key in def[$abstract].methods) {
              if (!def[$class].methods[key]) {
                  abstractObj.unimplemented += 1;
              }
          }
          for (key in def[$abstract].staticMethods) {
              if (!def[$class].staticMethods[key]) {
                  abstractObj.unimplemented += 1;
              }
          }
  
          return def;
      }