17
love.apply(i,[you]); undefined Say it with JavaScript! Topics: Objects & C. Functions & C. Closure Inheritance Namespaces & Temp Scope Module Pattern Dispatching Putting it all together Unit Testing

Say It With Javascript

Embed Size (px)

Citation preview

Page 1: Say It With Javascript

love.apply(i,[you]);

undefined

SayitwithJavaScript!

Topics:

� Objects & C.

� Functions & C.

� Closure

� Inheritance

� Namespaces & Temp Scope

� Module Pattern

� Dispatching

� Putting it all together

� Unit Testing

Page 2: Say It With Javascript

Objects & C.

//Creating objects var myObj1 = {}; var myObj2 = new Object(); //Creating arrays

var myArr1 = []; var myArr2 = new Array(); var myArr3 = [1, "a"]; myArr3.length == 2 //true //Exploiting objects typeof myObj1 //"object" myObj1 instanceof Object //true myObj1.constructor //function Object() { [native code] } //Exploiting arrays typeof myArr1 //"object" myArr1 instanceof Array //true (within same frame) myArr1 instanceof Object //true myArr1.constructor //function Array() { [native code] }

//Adding properties myObj1.x = 5; myObj2["x"] = 5; myObj2.double = function(x) { return x*2; } myObj1["x"] == myObj2.x //true myObj2.x //5 myArr1.x = "test"; myArr1["y"] = "test"; myArr1.y == myArr1["x"] //true

//Test var testArr = []; testArr["x"] = "element x"; testArr["y"] = "element 0"; testArr.length //??? //Literals var person = { name: "giovanni", age: 41, rejuvenate: function() { this.age--; } } //The proto chain var developer = { salary: 999999 } //Using Object.create var developer = Object.create(person); developer.salary = 999999; developer.name //"giovanni" developer.__proto__ == person; //true

//Test person.age = 10; developer.age //???

Page 3: Say It With Javascript

Functions&C.

//Defining functions

function sayHello1() { console.log("Hi there!"); } var sayHello2 = function() { console.log("Hi there!"); } //Test

sayHello1.name //?? sayHello2.name //?? typeof sayHello1 //function sayHello1 instanceof Object //true sayHello1.constructor //function Function() {…} var fn = new Function("","console.log('Hi there!')"); //Calling function

var sayHelloTo = function sayHelloTo(name) { return this.greeting + " " + name; } sayHelloTo("Giovanni"); //"undefined Giovanni" window.greeting = "Good morning" sayHelloTo("Giovanni"); //"Good morning Giovanni"

//Calling functions within a context var evening = { greeting: "Good evening"}; //"Good evening Giovanni" sayHelloTo.apply(evening, ["Giovanni"]); sayHelloTo.call(evening, "Giovanni"); var urbanGreeter = { greeting: "Sup", greet: sayHelloTo } urbanGreeter.greet("Giovanni") //"Sup Giovanni" //Test

//What is this function doing? function bind(fnContext, fn) { return function() { return fn.apply(fnContext, arguments); } } //Test

function reverseName() { return this.name.split("").reverse().join(""); } var r = bind({name: "giovanni"}, reverseName); r(); //??

Page 4: Say It With Javascript

Closures

//Defining closures

function counter(startAt){ var count = startAt; return function(){ console.log(++count) }; } var next = counter(0); next(); //1 next(); //2 next(); //3 //Closures with input parameters

var quo = function (status) { return { get_status: function ( ) { return status; } };

}; var myQuo = quo("active"); myQuo.get_status(); //"active" //Test var handlers = []; for (var i = 0; i < 10; i += 1) { handlers.push( function() { return i; } ); }; handlers[2](); //??? handlers[6](); //???

//Test var handlers = []; for (var i = 0; i < 10; i += 1) { handlers.push( function(i) { return function() { return i;}; }(i) ); };

var index = handlers.length; while(index) console.log(handlers[--index]()); //???

//Using closures for encapsulation

function buildProduct() { var productID = 999; return { getID: function () { return productID; }, setID: function (theNewID) { productID = theNewID; } } } var product = buildProduct(); product.getID(); // 999 product.setID(478); product.getID(); // 478

//Test var shortCut = product.getID; shortCut(); //???

Page 5: Say It With Javascript

Inheritance

//Inheritance with the ‘new’ operator

//constructor function Person(name, age){ this.name = name; this.age = age; } Person.prototype.getName = function(){ return this.name; }; Person.prototype.getAge = function(){ return this.age; }; Person.prototype.title = "Mr."; var badPerson = Person("Max",30); badPerson == undefined; //true window.name == "Max"; //true var goodPerson1 = new Person("Giovanni",41); var goodPerson2 = new Person("John",30); goodPerson1.getName() == "Giovanni"; //true goodPerson2.getAge() == "30"; //true goodPerson2.title = "Mr."; //true //Test goodPerson2.age = 31; goodPerson2.title = "Dr."; console.log(goodPerson1.age); //?? console.log(goodPerson1.title); //??

//inheritance chains

function Worker(name, age, profession, salary) { Person.call(this,name,age); this.profession = profession; this.salary = salary; } Worker.prototype = new Person(); //Added for legacy code compatibility Worker.prototype.constructor = Worker; Worker.prototype.fire = function() { this.profession = "unemployed"; } Worker.prototype.giveBigRaise = function() { this.salary += 10000; } var w1 = new Worker("Giovanni", 41, "developer", 0); var w2 = new Worker("John", 43, "developer", 0); //Test w1.giveBigRaise(); w1.salary; //?? w2.salary; //?? w1.getAge(); //?? w1.title == "Mr."; //?? w1 instance of Worker; //?? W2 instance of Worker; //?? w1 instance of Person; //?? w1 instance of Object; //??

Page 6: Say It With Javascript

//Extending native types – forEach polyfill

if (!Array.prototype.forEach) { Array.prototype.forEach = function (fn, scope) { for (var i = 0, l = this.length; i < l; ++i) { if (i in this) { fn.call(scope, this[i], i, this); } } }; } ['a','b','c'].forEach( function(elm, index, ctx) { console.log(index +'. ' + elm); }, window );

//Inheritance with Object.create

var myMammal = { name : 'Herb the Mammal', get_name : function ( ) { return this.name; }, says : function ( ) { return this.saying || ''; }

}; var myCat1 = createCat('Henrietta'); var myCat2 = createCat('Rocky'); function createCat(name) { var obj = Object.create(myMammal);

obj.name = name; obj.saying = 'meow'; obj.purr = function (n) { return 'r-r-r-r-r'; }; obj.get_name = function ( ) { return this.says( ) + ' ' + this.name + ' '; }; return obj;

} myCat2.get_name(); //?? myMammal.bloodTemperature = 'warm’; myCat1.bloodTemperature; //??

Page 7: Say It With Javascript

//Functional Inheritance

function base(spec) { var that = {}; that.name = spec.name; return that; // Return the object } function child(spec) { var that = base(spec); that.sayHello = function() { return 'Hello, I\'m ' + that.name; }; return that; // Return it } // Usage var object = child({ name: 'a functional object' }); console.log(object.sayHello());

//Mixins

var asButton = function() { this.hover = function() { console.log('hover handler'); }; this.press = function() { console.log('press handler'); }; this.fire = function() { return this.action(); }; return this;

}; var asCircle = function() {

this.area = function() { return Math.PI * this.radius * this.radius; }; this.grow = function() { this.radius++; }; this.shrink = function() { this.radius--; }; return this;

}; var RoundButton = function(radius, label, action) { this.radius = radius; this.label = label; this.action = action; }; asButton.call(RoundButton.prototype); asCircle.call(RoundButton.prototype); var button1 = new RoundButton(4, 'yes!', function() {return 'you said yes!';} ); button1.fire(); //'you said yes!'

Page 8: Say It With Javascript

Namespaces&Temp.Scope

//Creating namespaces manually

var afsi = afsi || {}; afsi.utilities = myApp.utilities || {}; afsi.utilities.sayHello = function(name) { return "Hi " + name; } //A namespace utility

var afsi = afsi || {}; afsi.namespace = function namespace(namespaceString) { var parts = namespaceString.split('.'), parent = window, currentPart = ''; for(var i = 0, length = parts.length; i < length; i++) { currentPart = parts[i]; parent[currentPart] = parent[currentPart] || {}; parent = parent[currentPart]; } } //Defining and using a namespace

afsi.namespace("afsi.utilities"); var afsi.utilities.sayHello = function(name) { return "Hi " + name; }

//‘Wrapping’ techniques

(function(){ var myLib = window.myLib = function(){ // Initialize }; // ... })(); --------------------------------------------- var myLib = (function(){ function myLib(){ // Initialize } // ... return myLib; })(); --------------------------------------------- (function( window, document, NS, undefined ){ NS.variableName = "string value"; NS.methodName = function() {}; // ... }(window, window.document, (window.NS = window.NS || {}) ) ); --------------------------------------------- function MyScript(){} (function() { var THIS = this; function defined(x) { alert(THIS); //points to MyScript() } // ... }).apply(MyScript);

Page 9: Say It With Javascript

ModulePattern–(singleton,revealing)

var afsi = afsi || {}; var afsi.calculator = (function () { var _m = 0; function _add(n1,n2) { return n1+n2; } function _substract(n1,n2) { return n1-n2; } function _setM(m) { return _m = m; } function _getM() { return _m; } return { add: _add, substract: _substract, setM: _setM, getM: _getM }; }());

Page 10: Say It With Javascript

ModulePattern–constructor(OOP)

var afsi = afsi || {}; afsi.MyClass = (function(){ var _privateStaticVar = "I am a static private variable"; var _privateFunction = function() { return "I am a private function"; }; var Constructor = function(options) { this.instanceVar = "I am an public instance variable"; this.setPrivateStaticVar = function(x) { _privateStaticVar = x; }; this.getPrivateStaticVar = function() { return _privateStaticVar; }; this.exposePrivateFunction = _privateFunction; }; Constructor.prototype = { constructor: afsi.MyClass, name: "afsi.MyClass", version: "1.0" }; return Constructor; }()); var v1 = new afsi.MyClass(options); var v2 = new afsi.MyClass(options);

Page 11: Say It With Javascript

ModulePattern–factory(functional,revealing)

var afsi = afsi || {}; afsi.calculator = (function(){ var _add = function (n1, n2) { return n1+n2; }; var _substract = function (n1, n2) { return n1-n2; }; var _calculatorFactory = function () { var _m = 0;

var _setM = function (m) { _m = m; }; var _getM = function () { return _m; };

return {

add: _add, substract: _substract, setM: _setM, getM: _getM

}; }; return _calculatorFactory; }()); var calc = afsi.calculator();

Page 12: Say It With Javascript

Dispatching(Publisher/Subscriber)

var afsi = afsi || {}; afsi.messenger = (function () { var _messengerFactory = function() {

var _messages = []; var _subscribeMessage = function (messageName, callBack) { if (typeof messageName === "string" && typeof callBack === "function") { if (typeof _messages[messageName] === "undefined") { _messages[messageName] = []; } _messages[messageName].push(callBack); } }; var _sendMessage = function (messageName, message) { if (typeof messageName === "string" && typeof _messages[messageName] !== "undefined") { for (var _counter = 0, max = _messages[messageName].length; _counter < max; _counter++) { _messages[messageName][_counter](message); } } }; return { subscribeMessage: _subscribeMessage, sendMessage: _sendMessage };

} return _messengerFactory; } ());

Page 13: Say It With Javascript

Puttingitalltogether

//Controller

afsi.namespace("afsi.myPage.controller"); afsi.myPage.controller = (function () { var _processSearchData (searchData) { //process the search data return searchData; } var _ctrFactory = function (model,view, messenger) { messenger.subscribeMessage( "myPage.search_onkeypress", function (text) { model.searchProducts(text); } ); messenger.subscribeMessage( "myPage.search_result", function (searchData) { searchData = _processSearchData(searchData); view.showSearchResult(searchData); } ); }; return _ctrFactory; } ());

//View

afsi.namespace("afsi.myPage.view"); afsi.myPage.view = (function () { var _showSearchResult = function(searchData){ //bind UI with searchData … } var _viewFactory = function (messenger) { $("#searchInput").on("keypress", {}, function (event) { messenger.sendMessage( "myPage.search_onkeypress", this.value ); } ); return { showSearchResult: _showSearchResult }; } return _viewFactory } ());

Page 14: Say It With Javascript

//Model

afsi.namespace("afsi.myPage.model"); afsi.myPage.model = (function () { var _modelFactory = function (messenger) { var _searchProducts = function(text){ $.ajax({ url: "/api/Products/SearchProducts?q="+text, type: 'GET', cache: false, success: function (result) { messenger.sendMessage( "myPage.search_result", Result ); }, error: function (result) { alert("Some error message") } }); } return { searchProducts: _searchProducts }; } return _modelFactory; } ());

//Page initialization

$(function () { var messenger = afsi.messenger(); afsi.myPage.controller( afsi.myPage.model(messenger), afsi.myPage.view(messenger), messenger ); });

Page 15: Say It With Javascript

UnitTesting(QUnit)

(function() { module('Dispatcher Test'); test( "Subscriber should be called and receceive the message", function() { //expected assertion #

expect(3); //reate instance

var m = afsi.messenger(); //set up m.subscribeMessage("afsi.test", function(message) { //assertions

ok( true, "function called" ); ok( typeof message !== 'undefined', "message is defined" ); ok( message.data === 'something', "data has the correct value" ); }); //stimulus m.sendMessage("afsi.test", { data: 'something' }) }); … }());

Page 16: Say It With Javascript

confirm("Questions?")

Page 17: Say It With Javascript

References

Eloquent JavaScript

http://eloquentjavascript.net/index.html

Learning Advanced Javascript http://ejohn.org/apps/learn/

Google Talks: How JavaScript Works http://www.youtube.com/watch?v=ljNi8nS5TtQ Prototypes and Inheritance in JavaScript http://msdn.microsoft.com/en-us/magazine/ff852808.aspx

Functional inheritance vs. prototypal inheritance

http://www.richard-foy.fr/blog/2011/10/30/functional-inheritance-vs-prototypal-inheritance/

Namespacing in JavaScript http://javascriptweblog.wordpress.com/2010/12/07/namespacing-in-javascript/

JavaScript Module Pattern: In-Depth

http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

ECMAScript 5 Strict Mode, JSON, and More

http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/#!

QUnit: Introduction to Unit Testing

http://qunitjs.com/intro/

alert("Thank You!");