mirror of
				https://github.com/flynx/Course-JavaScript.git
				synced 2025-10-30 19:40:09 +00:00 
			
		
		
		
	rewritted the OOP intro, still needs some cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									159a80d737
								
							
						
					
					
						commit
						0553ec9845
					
				| @ -128,7 +128,7 @@ var PRE_NAMESPACE = { | |||||||
| 			// XXX should we look ahead and count the explicitly closed
 | 			// XXX should we look ahead and count the explicitly closed
 | ||||||
| 			// 		via ']' and ']]' blocks???
 | 			// 		via ']' and ']]' blocks???
 | ||||||
| 			// 		...at this point this seems a bit complex...
 | 			// 		...at this point this seems a bit complex...
 | ||||||
| 			// 		...of there are more than one ']]' in a structure
 | 			// 		...if there are more than one ']]' in a structure
 | ||||||
| 			//		this might stop being deterministic...
 | 			//		this might stop being deterministic...
 | ||||||
| 			code.splice(0, 0, cur) | 			code.splice(0, 0, cur) | ||||||
| 		} | 		} | ||||||
|  | |||||||
							
								
								
									
										479
									
								
								js-oop.js
									
									
									
									
									
								
							
							
						
						
									
										479
									
								
								js-oop.js
									
									
									
									
									
								
							| @ -5,124 +5,405 @@ | |||||||
| * | * | ||||||
| **********************************************************************/ | **********************************************************************/ | ||||||
| //
 | //
 | ||||||
| // The value of 'this'
 | // The basic prototype inheritance
 | ||||||
|  | // -------------------------------
 | ||||||
|  | //
 | ||||||
|  | // First we'll create a  basic object a
 | ||||||
|  | 
 | ||||||
|  | 	var a = { | ||||||
|  | 		x: 1, | ||||||
|  | 		y: 2, | ||||||
|  | 	}  | ||||||
|  | 
 | ||||||
|  | // Then we will create a new object using a as a "base" 
 | ||||||
|  | 
 | ||||||
|  | 	var b = Object.create(a) | ||||||
|  | 	b.z = 3 | ||||||
|  | 
 | ||||||
|  | // The object b now has both access to it's own attributes ('z') and 
 | ||||||
|  | // attributes of a ('x' and 'y')
 | ||||||
|  | 
 | ||||||
|  | 	b.x					// -> 1
 | ||||||
|  | 	b.z					// -> 3
 | ||||||
|  | 
 | ||||||
|  | // What we see is that if the attribute is not found in the current 
 | ||||||
|  | // object it resolves to the object's "prototype" and so on, these 
 | ||||||
|  | // chians can of any length.
 | ||||||
|  | //
 | ||||||
|  | // NOTE: there is also a second mechanism available but we'll discuss 
 | ||||||
|  | // 		it a bit later in 
 | ||||||
|  | //
 | ||||||
|  | // A couple of easy ways to see these sets of attributes:
 | ||||||
|  | 	 | ||||||
|  | 	Object.keys(b)		// -> z
 | ||||||
|  | 
 | ||||||
|  | 	for(var k in b){ console.log(k) } | ||||||
|  | 						// -> x, y, z
 | ||||||
|  | 
 | ||||||
|  | // Another way to test if the attribute is "local" ("own"):
 | ||||||
|  | 
 | ||||||
|  | 	b.isOwnProperty('z')	// -> true
 | ||||||
|  | 	b.isOwnProperty('x')	// -> false
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // What happens under the hood is very simple:
 | ||||||
|  | 
 | ||||||
|  | 	b.__proto__ === a	// -> true
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Thus, we could define our own create function like this:
 | ||||||
|  | 
 | ||||||
|  | 	function clone(from){ | ||||||
|  | 		var o = {} | ||||||
|  | 		o.__proto__ = from | ||||||
|  | 		return o | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var c = clone(b) | ||||||
|  | 
 | ||||||
|  | // Out of curiosity let's see if .__proto__ is defined on a basic object
 | ||||||
|  | 
 | ||||||
|  | 	var x = {} | ||||||
|  | 
 | ||||||
|  | 	x.__proto__			// -> {}
 | ||||||
|  | 
 | ||||||
|  | // Turns out it is, and it points to Object's prototype
 | ||||||
|  | 
 | ||||||
|  | 	x.__proto__ === Object.prototye | ||||||
|  | 						// -> true
 | ||||||
|  | 
 | ||||||
|  | // We will discuss what this means and how we can use this in the next 
 | ||||||
|  | // sections...
 | ||||||
|  | //
 | ||||||
|  | //
 | ||||||
|  | //
 | ||||||
|  | // The Constructor Mechanism
 | ||||||
|  | // -------------------------
 | ||||||
|  | //
 | ||||||
|  | // JavaScript provides a second, complementary mechanism to inherit 
 | ||||||
|  | // attributes, it resembles the class/object relationship in languages
 | ||||||
|  | // like C++ but this resemblance is on the surface only as it still 
 | ||||||
|  | // uses the same prototype mechanism as the above.  
 | ||||||
|  | //
 | ||||||
|  | // We will start by creating a constructor:
 | ||||||
|  | 	 | ||||||
|  | 	function A(){ | ||||||
|  | 		this.x = 1 | ||||||
|  | 		this.y = 2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | // Technically a constructor is just a function, what makes it a 
 | ||||||
|  | // "constructor" is how we use it...
 | ||||||
|  | 
 | ||||||
|  | 	var a = new A() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // what 'new' does here is:
 | ||||||
|  | // 	1) creates an empty object
 | ||||||
|  | // 	2) sets a bunch of attributes on it
 | ||||||
|  | // 	3) passes it to the constructor via 'this'
 | ||||||
|  | // 	4) after the constructor returns, this object is returned
 | ||||||
|  | //
 | ||||||
|  | // We could write an equivalent (simplified) function:
 | ||||||
|  | 
 | ||||||
|  | 	function construct(func){ | ||||||
|  | 		var obj = {} | ||||||
|  | 
 | ||||||
|  | 		// set some special attributes on obj...
 | ||||||
|  | 
 | ||||||
|  | 		return func.apply(obj) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var b = construct(A) | ||||||
|  | 
 | ||||||
|  | // But what makes this interesting? At this point this all looks like 
 | ||||||
|  | // all we did is moved attribute from a literal object notation to a 
 | ||||||
|  | // constructor function, effectively adding complexity. What are we 
 | ||||||
|  | // getting back from this?
 | ||||||
|  | //
 | ||||||
|  | // Let's look at a number of attributes:
 | ||||||
|  | 
 | ||||||
|  | 	a.__proto__		// -> {} 
 | ||||||
|  | 
 | ||||||
|  | 	a.constructor	// -> [Function A]
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // The answer lies in the attributes that are set on the object, lets 
 | ||||||
|  | // write a more complete reference implementation:
 | ||||||
|  | 	 | ||||||
|  | 	function construct(func, args){ | ||||||
|  | 		var obj = {} | ||||||
|  | 
 | ||||||
|  | 		obj.constructor = func | ||||||
|  | 		obj.__proto__ = func.prototype | ||||||
|  | 
 | ||||||
|  | 		var res = func.apply(obj, args) | ||||||
|  | 		if(res instanceof Object){ | ||||||
|  | 			return res | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return obj | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var b = construct(A) | ||||||
|  | 
 | ||||||
|  | // Notice that we return the resulting object in a more complicated
 | ||||||
|  | // way, this will come in handy later.
 | ||||||
|  | // 
 | ||||||
|  | // Also notice that 'prototype' from the end of the previous section.
 | ||||||
|  | //
 | ||||||
|  | // First let us cover the default. Each time a function is created in
 | ||||||
|  | // JavaScript it will get a new empty object assigned to it's .prototype
 | ||||||
|  | // attribute.
 | ||||||
|  | // On the function level, in general, this is not used, but this is used
 | ||||||
|  | // when we use the function as a constructor.
 | ||||||
|  | //
 | ||||||
|  | // As we can see from the code above, the resulting object's .__proto__
 | ||||||
|  | // points to the constructor's .prototype, from the previous section 
 | ||||||
|  | // this means that attributes accessed via that object are resolved to 
 | ||||||
|  | // the prototype.
 | ||||||
|  | // In the default case this is true.
 | ||||||
|  | //
 | ||||||
|  | // So if we add stuff to the constructor's .prototype they should get 
 | ||||||
|  | // resolved from the object
 | ||||||
|  | 
 | ||||||
|  | 	A.prototype.x = 123 | ||||||
|  | 	a.constructor.prototype.y = 321 | ||||||
|  | 	a.__proto__.z = 333 | ||||||
|  | 
 | ||||||
|  | 	// for illustration, some object own attributes
 | ||||||
|  | 	a.x = 'a!' | ||||||
|  | 	b.x = 'b!' | ||||||
|  | 
 | ||||||
|  | 	a.x				// -> 'a!'
 | ||||||
|  | 	a.y				// -> 321
 | ||||||
|  | 	a.z				// -> 333
 | ||||||
|  | 
 | ||||||
|  | // These values are accessible from all objects constructed by A since
 | ||||||
|  | // all of them point to A with both the .constructor and .__proto__ 
 | ||||||
|  | // attributes
 | ||||||
|  | 
 | ||||||
|  | 	b.x				// -> 'b!'
 | ||||||
|  | 	b.y				// -> 321
 | ||||||
|  | 	b.z				// -> 333
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Double inheritance:
 | ||||||
| // -------------------
 | // -------------------
 | ||||||
| //
 | //
 | ||||||
|  | // NOTE: this might be implementation specific. Tested and works in IE11, V8
 | ||||||
|  | //
 | ||||||
|  | // There are actually three sources where JavaScript looks for attributes:
 | ||||||
|  | // 	1) the actual object
 | ||||||
|  | // 	2) .__proto__ 
 | ||||||
|  | // 		as coverd in the first section
 | ||||||
|  | // 	3) .constructor.prototype 
 | ||||||
|  | // 		as explained in the previous section
 | ||||||
|  | 
 | ||||||
|  | 	var O = {  | ||||||
|  | 		o: 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	function A(){} | ||||||
|  | 	A.prototype.a = 1 | ||||||
|  | 
 | ||||||
|  | 	var a = new A() | ||||||
|  | 	a.__proto__ = o | ||||||
|  | 
 | ||||||
|  | // Now we can access both attributes inherited from 'O' and 'A'...
 | ||||||
|  | 
 | ||||||
|  | 	a.o				// -> 0
 | ||||||
|  | 	a.a				// -> 1
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // The check is done specifically in this order, thus attributes can 
 | ||||||
|  | // "shadow" other attributes defined later in the chain.
 | ||||||
|  | //
 | ||||||
|  | // To show this let us define an attribute with the same name on both 
 | ||||||
|  | // 'O' and 'A':
 | ||||||
|  | 
 | ||||||
|  | 	O.x = 'came from O' | ||||||
|  | 	A.prototype.x = 'came from A' | ||||||
|  | 
 | ||||||
|  | 	a.x				// -> 'came from O'
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // In both inheritance mechanisms, each step is checked via the same 
 | ||||||
|  | // rules recursively, this enables inheritance chains.
 | ||||||
|  | //
 | ||||||
|  | // We will create a cahin:
 | ||||||
|  | //
 | ||||||
|  | // 		c -> b -> a
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | 	var a = {x: 1} | ||||||
|  | 	var b = Object.create(a) | ||||||
|  | 	b.y = 2 | ||||||
|  | 	var c = Object.create(b) | ||||||
|  | 	 | ||||||
|  | 	c.x				// -> 1
 | ||||||
|  | 	c.y				// -> 2
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Creating an inheritance chain via the constructor mechanism is a bit
 | ||||||
|  | // more involved, and there are multiple ways to do this...
 | ||||||
|  | //
 | ||||||
|  | // Here we will create a similar chian:
 | ||||||
|  | //
 | ||||||
|  | // 		C -> B -> A
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | 	function A(){} | ||||||
|  | 	A.prototype.x = 1 | ||||||
|  | 
 | ||||||
|  | 	function B(){} | ||||||
|  | 	// NOTE: if this is done after an instance is created, that instances'
 | ||||||
|  | 	// 		.__proto__ will keep referencing the old prototype object.
 | ||||||
|  | 	// 		see the next constructor for a way around this...
 | ||||||
|  | 	B.prototype = Object.create(A.prototype) | ||||||
|  | 	B.prototype.y = 2 | ||||||
|  | 
 | ||||||
|  | 	function C(){} | ||||||
|  | 	// NOTE: this is safer than Object.create as it does not overwrite
 | ||||||
|  | 	// 		the original object and thus will affect all existing 
 | ||||||
|  | 	// 		instances of C, if any were created before this point...
 | ||||||
|  | 	C.prototype.__proto__ = B.prototype | ||||||
|  | 
 | ||||||
|  | 	var c = new C() | ||||||
|  | 
 | ||||||
|  | 	c.x				// -> 1
 | ||||||
|  | 	c.y				// -> 2
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Checking inheritance (instanceof)
 | ||||||
|  | // ---------------------------------
 | ||||||
|  | //
 | ||||||
|  | // An object is considered an instance of its' constructor and all other 
 | ||||||
|  | // constructors in the inheritance chain.
 | ||||||
|  | 
 | ||||||
|  | 	c instanceof C	// -> true
 | ||||||
|  | 	c instanceof B	// -> true
 | ||||||
|  | 	c instanceof A	// -> true
 | ||||||
|  | 	c instanceof Object | ||||||
|  | 					// -> true
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // This also works for manually created objects
 | ||||||
|  | 
 | ||||||
|  | 	var cc = construct(C) | ||||||
|  | 
 | ||||||
|  | 	cc instanceof C | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // But this will not work outside the constructor model, i.e. if the right 
 | ||||||
|  | // parameter is not a function.
 | ||||||
|  | 
 | ||||||
|  | 	var x = {} | ||||||
|  | 	var y = Object.create(x) | ||||||
|  | 
 | ||||||
|  | 	try{ | ||||||
|  | 		// this will fail as x is not a function...
 | ||||||
|  | 		y instanceof x | ||||||
|  | 	} catch(e){ | ||||||
|  | 		console.log('error') | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Again to make this simpler to understand we will implement our own
 | ||||||
|  | // equivalent to instanceof:
 | ||||||
|  | 	 | ||||||
|  | 	function isInstanceOf(obj, proto){ | ||||||
|  | 		return proto instanceof Function  | ||||||
|  | 			&& (obj.__proto__ === proto.prototype ? true | ||||||
|  | 				// NOTE: the last in this chain is Object.prototype.__proto__ 
 | ||||||
|  | 				// 		and it is null
 | ||||||
|  | 				: obj.__proto__ == null ? false | ||||||
|  | 				// go down the chian...
 | ||||||
|  | 				: isInstanceOf(obj.__proto__, proto)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	isInstanceOf(c, C)	// -> true
 | ||||||
|  | 	isInstanceOf(c, B)	// -> true
 | ||||||
|  | 	isInstanceOf(c, A)	// -> true
 | ||||||
|  | 	isInstanceOf(c, Object) | ||||||
|  | 						// -> true
 | ||||||
|  | 	isInstanceOf(c, function X(){}) | ||||||
|  | 						// -> false
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Checking type (typeof)
 | ||||||
|  | // ----------------------
 | ||||||
|  | //
 | ||||||
|  | // What typeof returns in JavaScript is not too useful and sometimes 
 | ||||||
|  | // even odd...
 | ||||||
|  | 
 | ||||||
|  | 	typeof c			// -> 'object'
 | ||||||
|  | 
 | ||||||
|  | // This might differ from implementation to implementation but 
 | ||||||
|  | // essentially the main thing typeof is useful for is distinguishing
 | ||||||
|  | // between objects and non-objects (numbers, strings, ...etc.)
 | ||||||
|  | 
 | ||||||
|  | 	// non-objects
 | ||||||
|  | 	typeof 1			// -> 'number'
 | ||||||
|  | 	typeof Infinity		// -> 'number'
 | ||||||
|  | 	typeof 'a'			// -> 'string'
 | ||||||
|  | 	typeof undefined	// -> 'undefined'
 | ||||||
|  | 
 | ||||||
|  | 	// objects
 | ||||||
|  | 	typeof {}			// -> 'object'
 | ||||||
|  | 	typeof []			// -> 'object'
 | ||||||
|  | 
 | ||||||
|  | 	// the odd stuff...
 | ||||||
|  | 	typeof NaN			// -> 'number'
 | ||||||
|  | 	typeof null			// -> 'object'
 | ||||||
|  | 	typeof function(){}	// -> 'function'
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Methods and the value of 'this'
 | ||||||
|  | // -------------------------------
 | ||||||
|  | //
 | ||||||
|  | // A method is simply an attribute that references a function.
 | ||||||
|  | 
 | ||||||
|  	function f(){ |  	function f(){ | ||||||
|  		console.log(this) |  		console.log(this) | ||||||
|  		this.a = 1 |  		this.a = 1 | ||||||
|  	} |  	} | ||||||
|  | 
 | ||||||
| 	var o = { f: f } | 	var o = { f: f } | ||||||
| 
 | 
 | ||||||
|  | // Thus we call the attribute .f of object o a method.
 | ||||||
| //
 | //
 | ||||||
| // 'this' is always the "context" of the function call, in JS a context
 | //
 | ||||||
| // can be:
 | // 'this' is a reserved word and is available in the context of a function
 | ||||||
|  | // execution, not just in methods, but what value it references depends
 | ||||||
|  | // on how that function is called...
 | ||||||
|  | // 
 | ||||||
|  | // a simple way to think about is that 'this' always points to the 
 | ||||||
|  | // "context" of the function call.
 | ||||||
|  | //
 | ||||||
|  | // This context can be:
 | ||||||
| // 	- implicit
 | // 	- implicit
 | ||||||
| // 		- root context
 | // 		- root context
 | ||||||
|  			f()			// 'window' or 'module' is implied, this is 
 |  			f() | ||||||
|  						//	equivalent to: window.f()
 | 						// 'window', 'global' or 'module' is implied, 
 | ||||||
|  | 						// in strict mode this is null.
 | ||||||
|  | 						// the same as:
 | ||||||
|  | 						// 		window.f()
 | ||||||
| // 		- 'new' context
 | // 		- 'new' context
 | ||||||
|  			new f()		// here a context will be created and passed to
 |  			new f()		// here a context will be created and passed to
 | ||||||
|  						//	'f's 'this', for more details on what 'new'
 |  						// 'f's 'this', for more details on what 'new'
 | ||||||
|  						//	does see the next section.
 |  						// does see: "The Constructor Mechanism" section.
 | ||||||
| // 	- explicit:
 | // 	- explicit:
 | ||||||
| // 		- the object on the left side of "." or the [ ] attribute access:
 | // 		- the object on the left side of "." or the [ ] operators:
 | ||||||
|  			o.f()		// o is the context
 |  			o.f()		// o is the context
 | ||||||
|  			o['f']()	// the same as the above
 |  			o['f']()	// the same as the above
 | ||||||
| // 		- the object explicitly passed to .call(..) or .apply(..) methods
 | // 		- the object explicitly passed to .call(..) or .apply(..) methods
 | ||||||
| // 		  as first argument:
 | // 		  as first argument:
 | ||||||
|  		  	f.call(o)	// o is the context
 |  		  	f.call(o)	// o is the context
 | ||||||
| //
 |  		  	f.apply(o)	// o is the context
 | ||||||
| //
 |  | ||||||
| //
 |  | ||||||
| // What's 'new'?
 |  | ||||||
| // -------------
 |  | ||||||
| //
 |  | ||||||
|  	function O(){ |  | ||||||
|  		this.attr = 123 |  | ||||||
|  	} |  | ||||||
|  	var o = new O() |  | ||||||
| 
 |  | ||||||
| //
 |  | ||||||
| // 'new' creates a new context object and passes it to the function 
 |  | ||||||
| // being called (the constructor), this new object has several special
 |  | ||||||
| // attributes set:
 |  | ||||||
| // 	o.constructor	-- references the object (constructor) used to 
 |  | ||||||
| // 						construct the object o (instance)
 |  | ||||||
| // 	o.__proto__		-- references the constructor prototype, same as:
 |  | ||||||
|  							o.constructor.prototype === o.__proto__ |  | ||||||
| // 						this is used to identify the object via:
 |  | ||||||
|  							o instanceof O |  | ||||||
| //
 |  | ||||||
| // The 'new' expression returns the context object after it has been
 |  | ||||||
| // populated by the constructor function.
 |  | ||||||
| //
 |  | ||||||
| // NOTE: when using 'new', the function/constructor return value is 
 |  | ||||||
| // 		ignored.
 |  | ||||||
| //
 |  | ||||||
| //
 |  | ||||||
| // The values set on 'this' by the constructor are instance attributes,
 |  | ||||||
| // i.e. they are stored in the specific instance being created.
 |  | ||||||
| //
 |  | ||||||
| // NOTE: calling the constructor is not required, but not calling it
 |  | ||||||
| // 		will not run the initialization code that would otherwise 
 |  | ||||||
| // 		populate the object. i.e. no instance values will be created.
 |  | ||||||
| // 
 |  | ||||||
| //
 |  | ||||||
| // The instance has another type of attribute accessible through it, an 
 |  | ||||||
| // attribute that's not stored in the object, but rather in it's 
 |  | ||||||
| // prototype (o.__proto__), or rather the constructor's prototype 
 |  | ||||||
| // (o.constructor.prototype). For more details see the next section.
 |  | ||||||
| //
 |  | ||||||
| //
 |  | ||||||
| //
 |  | ||||||
| // The object's 'prototype'
 |  | ||||||
| // ------------------------
 |  | ||||||
| //
 |  | ||||||
|  	function f(){} |  | ||||||
|  	console.log(f.prototype)			// f {}
 |  | ||||||
| 
 |  | ||||||
| //
 |  | ||||||
| // The unique prototype object is created on every function definition.
 |  | ||||||
| // The prototype is instance-like of the function to which it is assigned.
 |  | ||||||
| //
 |  | ||||||
| // NOTE: since the prototype has .__proto__ set to Object, technically
 |  | ||||||
| // 		it's not a strict instance of the type it defines, so:
 |  | ||||||
|  			f.prototype instanceof f |  | ||||||
| // 		will return false.
 |  | ||||||
| //
 |  | ||||||
| // Each unresolved attribute access on the "instance" will resolve to its
 |  | ||||||
| // prototype (o.__proto__ or o.constructor.prototype). 
 |  | ||||||
| //
 |  | ||||||
|  	O.prototype.x = 321 |  | ||||||
|  	console.log(o.x)					// 321
 |  | ||||||
| 
 |  | ||||||
| //
 |  | ||||||
| // Since the prototype is a JS object that adheres to the same rules as 
 |  | ||||||
| // any other object, if the attr is not resolved in it directly, it will 
 |  | ||||||
| // be searched in its prototype, and so on.
 |  | ||||||
| // This principle enables us to implement inheritance.
 |  | ||||||
| //
 |  | ||||||
| 	var OO = function(){ |  | ||||||
| 		// call the base constructor...
 |  | ||||||
| 		O.call(this) |  | ||||||
| 	} |  | ||||||
| 	// chain the two prototypes...
 |  | ||||||
| 	OO.prototype = new O() |  | ||||||
| 	// this is to make things coherent for oo below...
 |  | ||||||
| 	OO.prototype.constructor = OO |  | ||||||
| 
 |  | ||||||
| 	var oo = new OO() |  | ||||||
| 
 |  | ||||||
| 	console.log(oo.x)					// 321
 |  | ||||||
| 	console.log(oo.constructor.name)	// 'OO'
 |  | ||||||
| 
 |  | ||||||
| //
 |  | ||||||
| // So in the example above local attributes (in 'oo') will be searched 
 |  | ||||||
| // first, then oo.__proto__ (instance of O), then in O.prototype, and 
 |  | ||||||
| // then in Object.prototype.
 |  | ||||||
| //
 |  | ||||||
| // 	oo -> oo.__proto__ -> (oo.__proto__).__proto__ -> ...
 |  | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user