mirror of
https://github.com/flynx/Course-JavaScript.git
synced 2025-10-29 02:50:09 +00:00
131 lines
4.0 KiB
JavaScript
Executable File
131 lines
4.0 KiB
JavaScript
Executable File
/**********************************************************************
|
|
*
|
|
* The basics of JavaScript OOP
|
|
*
|
|
*
|
|
**********************************************************************/
|
|
//
|
|
// The value of 'this'
|
|
// -------------------
|
|
//
|
|
function f(){
|
|
console.log(this)
|
|
this.a = 1
|
|
}
|
|
var o = { f: f }
|
|
|
|
//
|
|
// 'this' is always the "context" of the function call, in JS a context
|
|
// can be:
|
|
// - implicit
|
|
// - root context
|
|
f() // 'window' or 'module' is implied, this is
|
|
// equivalent to: window.f()
|
|
// - 'new' context
|
|
new f() // here a context will be created and passed to
|
|
// 'f's 'this', for more details on what 'new'
|
|
// does see the next section.
|
|
// - explicit:
|
|
// - the object on the left side of "." or the [ ] attribute access:
|
|
o.f() // o is the context
|
|
o['f']() // the same as the above
|
|
// - the object explicitly passed to .call(..) or .apply(..) methods
|
|
// as first argument:
|
|
f.call(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 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 that
|
|
// is not stored in it, 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__ -> ...
|
|
//
|
|
//
|
|
//
|
|
//
|
|
/**********************************************************************
|
|
* vim:set ts=4 sw=4 : */
|