Download presentation
Presentation is loading. Please wait.
1
JavaScript Internals and OOP Concepts
Martin Kruliš by Martin Kruliš (v1.4)
2
Revision Values Any expression or literal produces a value
There are following value types: number, string, boolean, object, function, and undefined Operator typeof returns the type of an expression Values are automatically garbage-collected when no longer needed Some type conversions are performed automatically "5" + 4 // is "54" "5" * 4 // is 20 console.log(myObject) // converted to string Another good example: 0 == “0” … true 0 == [] … true “0” == [] … false by Martin Kruliš (v1.4)
3
Revision Variables Mnemonic holders for values Declared by var keyword
Rather “attachments” to values than “memory boxes” Declared by var keyword var x; var y = 1; var a, b, c; The declaration is made in the current scope In global scope, the variables are assigned to the script environment (e.g., object window in the browser) var x = 1; and window.x = 1; are equivalent In a function, the variable belongs to the local scope (more details later) by Martin Kruliš (v1.4)
4
Members may be added dynamically.
Revision - Objects Objects Objects are unordered name-value collections All members are public var myObject = { foo: 10, bar: function() { ... } }; myObject.bar(); myObject.anotherFoo = 100; Creates simple object with two members (foo and bar), where foo is a Number and bar is Function (i.e., in some sense a method). Note, that arrays are also regular objects (just with a clever prototype and some additional sugar syntax like [] constructor). Members may be added dynamically. by Martin Kruliš (v1.4)
5
Creates new member of myObject
Objects Prototypes Every object may have a prototype object Prototypes substitute classes in a specific way [[Prototype]] foo bar name printName() Object.prototype AnotherObject myObject Searches up the prototype chain, looks for the first printName property myObject.printName(); myObject.name = …; Creates new member of myObject by Martin Kruliš (v1.4)
6
Objects Prototyping instead of Classes var CircleProto = { radius: 0,
circumference: function() { return 2 * Math.PI * this.radius; } var circle = Object.create(CircleProto); circle.radius = 42; console.log(circle.circumference()); Prototype takes the role of a class Creates new empty object which has CircleProto as prototype Logs by Martin Kruliš (v1.4)
7
Objects Classes vs Prototypes Class-based Language JavaScript
foo Object.prototype myObj MySubclass MyClass Class-based Language foo() bar() JavaScript var MyClass foo() [[Prototype]] bar var MySubclass bar() [[Prototype]] obj properties var myObj by Martin Kruliš (v1.4)
8
Objects - Technical Details
Object Properties obj.name = value or obj['name'] = value Object.defineProperty(obj, name, desc) Sets or modifies object property Descriptor object may contain: configurable – whether the descriptor can be changed enumerable – whether property is visible in keys and for data properties writeable – whether the value can be changed value – initial value of the property and for accessor properties get, set – getter/setter function Note that Object.getOwnPropertyNames(obj) returns all properties (enumerable and non-enumerable alike) of object obj. by Martin Kruliš (v1.4)
9
Objects - Technical Details
Object Properties Prevent adding new properties Object.preventExtensions(obj) Object.isExtensible(obj) Preventing adding or removing properties Object.seal(obj) Object.isSealed(obj) Preventing any property modifications Object.freeze(obj) Object.isFrozen(obj) by Martin Kruliš (v1.4)
10
Functions Revision Functions
Special “callable” values (first-class functions) Various ways to create them function foo(args) { body } var foo = function(args) { body } var foo = new Function(args, "body"); Function declaration = object creation Variadic – implicitly variable arity No difference between functions and methods Slight difference: declarations (1) are processed at parsing time, expressions (2) are processed at runtime The process of populating scope at compile time is informally called “hoisting”. Here is a good and short glossary about hoisting: Hoisting does not affect only functions, but variables as well. For example: x = 42; var x; Is OK, since x is “created” at compile time, so var x has no meaning at runtime (unless its var x = something, in which case x is being assigned to). by Martin Kruliš (v1.4)
11
Functions Revision Hoisting Example foo(); bar(); function foo() {
// do something foo-ish } var bar = () => { // pull up the bar }; OK, foo is already known Error, bar is undefined This declaration is hoisted (processed at parsing time) No hoisting, processed at runtime by Martin Kruliš (v1.4)
12
Functions Revision Function Scope of Variables
var a1; // global scope (obj. window in browser) function foo() { var a2; // local scope of foo() function innerFoo() { var a3; // local scope of innerFoo() function innerInnerFoo() { // I can see a1, a2, and a3 from here … a2 = 1; } We follow the scope chain upwards and find the first variable of the name 'a2'. by Martin Kruliš (v1.4)
13
Execution Context Execution Context
All JS code is executed in execution context Abstraction ~ object that holds variables Global context is represented by the global object E.g., window object in the browser New context is created when function is called Function calls shape the scope chain of exec. context An activation object is created Calling arguments are set in the activation object Scope chain is selected from the [[Scope]] property of the function object (and becomes execution context) Activation object is pushed at the front of scope chain ECMA specification does not say, how the execution context should be implemented. by Martin Kruliš (v1.4)
14
Functions Scope Chain Similar to prototype chain, but…
Both reads and writes follow the chain New (local) variables are created by var keyword var a = 1; function foo(x) { a = 2; var b = 3; c = 3; } foo(3); a foo() c foo [[Scope]] (global context) x b activation object by Martin Kruliš (v1.4)
15
Functions Closure Created functions capture current execution context
Into internal [[Scope]] property Some parts of the scope chain may become inaccessible directly from the other execution contexts (e.g., global context) By defining nested functions and returning them out of their creation scope The hidden part of the scope chain is still accessible from the created (nested) function The isolated scope chain is usually called closure by Martin Kruliš (v1.4)
16
Functions Closure make() f1() f2() function make() { var x = 1;
global context make [[Scope]] Closure function make() { var x = 1; return function(dx) { x += dx; alert(x); } var f1 = make(); var f2 = make(); f1(3); f2(7); x = 1 make() act. obj x = 1 make() act. obj f1 [[Scope]] f2 [[Scope]] 4 8 dx = 3 f1() act. obj dx = 7 f2() act. obj call stack by Martin Kruliš (v1.4)
17
Closure Applications Parametrized Functions function createAdder(x) {
return function(y) { return x + y; } var add3 = createAdder(3); var add7 = createAdder(7); add3(10); // is 13 add7(10); // is 17 The Inner function can see variable x due to scoping rules When the inner function is created, the closure captures value of x == 3 New function have a new closure where x == 7 by Martin Kruliš (v1.4)
18
Closure automatically snapshots arguments
Closure Applications Binding Callback Parameters function myCallback(data) { ... handle callback with data ... } function bindArg(fnc, data) { return function() { fnc(data); myAjax.oncomplete = bindArg(myCallback, reqData); Closure automatically snapshots arguments Note that argument binding can be done using Function.bind() as will be covered later. by Martin Kruliš (v1.4)
19
Closure Applications Hiding Encapsulated Functionality
Private functions, related data structures, … var searcher = (function(){ var lookupTable = [ ... ]; function findPattern(needle) { ... } return function(needle, haystack) { var ptrn = findPattern(needle); ... } })(); Hidden data structure and function This technique is often employed by library modules that expose only a specified interface. The outer function is immediately invoked and then forgotten by Martin Kruliš (v1.4)
20
Closure Pitfalls Shared Context function createLinks() {
All the links are created in one scope, thus sharing one closure. Shared Context function createLinks() { for (var i = 1; i <= 5; ++i) { var link = document.createElement('a'); link.onclick = function(){ alert(i); }; link.textContent = "Link " + i; document.body.appendChild(link); } document.onload = createLinks; Always prints “5”. The value of i is 5, when the scope is closed. by Martin Kruliš (v1.4)
21
Closure Pitfalls Accidental Closures
Unnecessary closures increases memory footprint function addLinkHandler(link) { if (!link) return; link.onclick = function() { this.href += "?marked=1"; return true; } addLinkHandler(document.getElementById("link1")); Event handler accidentally get hold of parent’s activation object which is not required by the handler by Martin Kruliš (v1.4)
22
Empty operation (does not modify param)
Closure Pitfalls Naming Collisions in Scope Chain var module = (function(){ var param = 1; function updateParam(param) { param += 1; } return { func: function() { updateParam(param); }; })(); Function argument hides param variable, which was privatized by the scope chain Empty operation (does not modify param) by Martin Kruliš (v1.4)
23
Augmenting Scope Chain
Pushing Object in Scope Chain with (obj) statement Given object is pushed at the top of the chain var o = { x: 1 }; var foo; with (o) { foo = function() { alert(x++); } Members of object o become part of the variable scope. Using with is not recommended since it may cause a lot of confusion. See x is accessible here by Martin Kruliš (v1.4)
24
Methods Methods (Functions in Object Properties) this keyword
var obj = { x: 1; next: function() { this.x += 1; } }; obj.next(); Default value is the global context (e.g., window) Using/binding different this (and arguments) fnc.apply(this, [args]), fnc.call(this, ...) var fnc2 = fnc.bind(this, ...); Note that Function.bind() create a new function, but the new function inherits the [[Scope]] property from the original (binded) function. by Martin Kruliš (v1.4)
25
Objects – Old School Constructors var Circle = function(r) {
Constructor looks like an ordinary function Constructors var Circle = function(r) { this.radius = r; }; Circle.prototype.foo = function() { … } var myCircle = new Circle(42); this refers to the newly created object (so it can be initialized) The prototype attribute is set to an empty object … so it can be easily augmented Creates new object and copies Circle.prototype to internal [[Prototype]] of the new object by Martin Kruliš (v1.4)
26
Objects – Old School Constructors Example Class-based Language
MyClass .prototype MySubclass myObj [[Prototype]] empty object MyClass obj new Object.prototype myObj MySubclass MyClass Class-based Language JavaScript Inheritance Instatiation Indirect prototyping by Martin Kruliš (v1.4)
27
Objects – Old School Simulating Classes (Naïve Approach)
function MyClass(init) { var privateMember; var privateMethod = function() { ... } this.member = init; this.method = function() { ... }; } var myObject = new MyClass(42); Privacy achieved by closure Methods are created over and over with every instance by Martin Kruliš (v1.4)
28
Better, since the method is created only once and shared
Objects – Old School Simulating Classes (Naïve Approach) function MyClass(init) { var privateMember; function privateMethod() { ... } this.member = init; } MyClass.prototype.method = function() { ... } var myObject = new MyClass(42); Better, since the method is created only once and shared by Martin Kruliš (v1.4)
29
Privileged method is public, but it can access private members
Objects – Old School Simulating Classes (Naïve Approach) function MyClass(init) { var privateMember; function privateMethod() { ... } this.privilegedMethod = function() {}; } MyClass.prototype.publicMethod = function() { … } var myObject = new MyClass(42); Privileged method is public, but it can access private members Even though the approach is called naïve, it may be used in many simple situations where complex class modeling is not required. by Martin Kruliš (v1.4)
30
Objects – Old School Simple Inheritance Using the prototype chain
function Person() { ... } Person.prototype.registerHobby = function(h) ... function Student() { Student.prototype = new Person(); Student.prototype.visitCourse = function(c) ... Base “class” The prototype object can be augmented Makes Student inherit from Person by Martin Kruliš (v1.4)
31
Objects – Old School Operator instanceof Multiple Inheritance
Whether an object was created by given constructor obj instanceof constructor Follows the prototype chain (respects inheritance) Actual instance (without inheritance) can be tested as Object.getPrototypeOf(o) === constr.prototype Multiple Inheritance Not directly supported Can be replaced by Swiss inheritance, traits, mixins, class augmentation, … Constructor function by Martin Kruliš (v1.4)
32
Objects – Old School Parasitic Inheritance Using the prototype chain
function Person() { ... } Person.prototype.registerHobby = function(h) ... function Student() { var that = new Person(); that.visitCourse = function(c) ... ... return that; } Base “class” Parasitic inheritance is not common and could be quite tedious. Note that: The instanceof operator no longer works correctly on derived classes (e.g., Student object is not an instance of Student constructor, but only a Person). Student constructor may be called with both new operator and without (a little confusing). Constructor of a parasitic class takes more significant role. Make sure you correctly consider the memory footprint. On the other hand, modifying existing object is basis for mixings and other types of horizontal inheritance. this is thrown away and replaced by augmented object of a different class by Martin Kruliš (v1.4)
33
Objects – Old School Efficiency Considerations
Problem with simple inheritance SubClass.prototype = new ParentClass(); The parent class may have heavy constructor New parent object is required for each derived class Possible solution function ParentClass() { ... } function SubClass() { ... } var tmp = function() {}; tmp.prototype = ParentClass.prototype; SubClass.prototype = new tmp(); New lightweight constructor, which uses the same prototype as parent class by Martin Kruliš (v1.4)
34
Objects – Old School Prototypal Inheritance
Complicated due to constructor indirection We can create a direct way to link prototypes function createPrototypeOf(o) { function F() {} F.prototype = o; return new F(); } Modern way since ECMAScript 5 Object.create(proto, params) So this is how it evolved from old Constructors and indirect prototyping Note that some browsers already implement proprietary API for object prototype modifications (e.g., see Mozilla Object.setPrototypeOf(obj, prototype)). by Martin Kruliš (v1.4)
35
Object Cloning Making an Object Copy function clone(obj, deep) {
if (typeof(obj) !== 'object' || obj === null) return obj; // obj is simple value var res = new obj.constructor(); for (var attr in obj) if (obj.hasOwnProperty(attr)) { res[attr] = (deep === true) ? clone(obj[attr], deep) : obj[attr]; } return res; This way only the simple properties of the object are cloned. A more elaborate solution would be required if non-enumerable properties or property descriptors need to be cloned as well. by Martin Kruliš (v1.4)
36
ECMA Script Evolution Recent Rapid Development Browser Compatibility
Finalized in June 2015 Many significant changes But backwards compatible with ES 5 ECMAScript 7 Finalized in June 2016 ECMAScript 8 (ECMAScript 2017) Browser Compatibility Nearly 100% support of ES 6 in newest browsers Careful with older browsers (LTS systems, IE 11, …) by Martin Kruliš (v1.4)
37
Discussion by Martin Kruliš (v1.4)
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.