mark.js
function Mark(typeName, props, contents) {
		// handle special shorthand
		if (arguments.length === 1 && (typeName[0] === '{' || typeName[0] === '[' || ws.indexOf(typeName[0]) >= 0)) { 
			return MARK.parse(typeName); 
		}
		
		// 1. prepare the constructor
		if (typeof typeName !== 'string') {
			if (this instanceof Mark) { // called through new operator
				this[$length] = 0;
				// no need to do further construction
				// props, contents are not supported at the moment
				return;
			}
			throw "Type name should be a string";
		}
		let con = $ctrs[typeName];
		if (!con) {
			con = $ctrs[typeName] = function(){};
			// con.prototype.constructor is set to con by JS
			// sets the type name
			Object.defineProperty(con, 'name', {value:typeName, configurable:true}); // non-writable, as we don't want the name to be changed

			// con.prototype.__proto__ = Array.prototype; // Mark no longer extends Array; Mark is array like, but not array.
			// con is set to extend Mark, instead of copying all the API functions
			// for (let a in api) { Object.defineProperty(con.prototype, a, {value:api[a], writable:true, configurable:true}); } // make API functions non-enumerable
			Object.setPrototypeOf(con.prototype, Mark.prototype);
		}
		
		// 2. create object
		let obj = Object.create(con.prototype);
		
		// 3. copy properties, numeric keys are not allowed
		if (props) { 
			for (let p in props) {
				// accept only non-numeric key; and we do no check key duplication here, last definition wins
				if (isNaN(p*1)) { obj[p] = props[p]; }
			}
		}
		
		// 4. copy contents if any
		obj[$length] = 0;
		if (contents) { push.call(obj, contents); }
		return obj;
	}
function Mark(typeName, props, contents) {
		// handle special shorthand
		if (arguments.length === 1 && (typeName[0] === '{' || typeName[0] === '[' || ws.indexOf(typeName[0]) >= 0)) { 
			return MARK.parse(typeName); 
		}
		
		// 1. prepare the constructor
		if (typeof typeName !== 'string') {
			if (this instanceof Mark) { // called through new operator
				this[$length] = 0;
				// no need to do further construction
				// props, contents are not supported at the moment
				return;
			}
			throw "Type name should be a string";
		}
		let con = $ctrs[typeName];
		if (!con) {
			con = $ctrs[typeName] = function(){};
			// con.prototype.constructor is set to con by JS
			// sets the type name
			Object.defineProperty(con, 'name', {value:typeName, configurable:true}); // non-writable, as we don't want the name to be changed

			// con.prototype.__proto__ = Array.prototype; // Mark no longer extends Array; Mark is array like, but not array.
			// con is set to extend Mark, instead of copying all the API functions
			// for (let a in api) { Object.defineProperty(con.prototype, a, {value:api[a], writable:true, configurable:true}); } // make API functions non-enumerable
			Object.setPrototypeOf(con.prototype, Mark.prototype);
		}
		
		// 2. create object
		let obj = Object.create(con.prototype);
		
		// 3. copy properties, numeric keys are not allowed
		if (props) { 
			for (let p in props) {
				// accept only non-numeric key; and we do no check key duplication here, last definition wins
				if (isNaN(p*1)) { obj[p] = props[p]; }
			}
		}
		
		// 4. copy contents if any
		obj[$length] = 0;
		if (contents) { push.call(obj, contents); }
		return obj;
	}
function Mark ( typeName , props , contents ) { // handle special shorthand if ( arguments . length === 1 && ( typeName [ 0 ] === '{' || typeName [ 0 ] === '[' || ws . indexOf ( typeName [ 0 ] ) >= 0 ) ) { return MARK . parse ( typeName ) ; } // 1. prepare the constructor if ( typeof typeName !== 'string' ) { if ( this instanceof Mark ) { // called through new operator this [ $length ] = 0 ; // no need to do further construction // props, contents are not supported at the moment return ; } throw "Type name should be a string" ; } let con = $ctrs [ typeName ] ; if ( ! con ) { con = $ctrs [ typeName ] = function ( ) { } ; // con.prototype.constructor is set to con by JS // sets the type name Object . defineProperty ( con , 'name' , { value : typeName , configurable : true } ) ; // non-writable, as we don't want the name to be changed // con.prototype.__proto__ = Array.prototype; // Mark no longer extends Array; Mark is array like, but not array. // con is set to extend Mark, instead of copying all the API functions // for (let a in api) { Object.defineProperty(con.prototype, a, {value:api[a], writable:true, configurable:true}); } // make API functions non-enumerable Object . setPrototypeOf ( con . prototype , Mark . prototype ) ; } // 2. create object let obj = Object . create ( con . prototype ) ; // 3. copy properties, numeric keys are not allowed if ( props ) { for ( let p in props ) { // accept only non-numeric key; and we do no check key duplication here, last definition wins if ( isNaN ( p * 1 ) ) { obj [ p ] = props [ p ] ; } } } // 4. copy contents if any obj [ $length ] = 0 ; if ( contents ) { push . call ( obj , contents ) ; } return obj ; }
Mark.prototype and Mark object constructor
Mark . prototype and Mark object constructor