{"id":15416246,"url":"https://github.com/ooade/advanced-javascript","last_synced_at":"2025-04-19T14:33:17.119Z","repository":{"id":49758791,"uuid":"112807514","full_name":"ooade/Advanced-JavaScript","owner":"ooade","description":"Documentation based on John Resig's website on Advanced JavaScript","archived":false,"fork":false,"pushed_at":"2017-12-27T08:19:30.000Z","size":37,"stargazers_count":55,"open_issues_count":0,"forks_count":13,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T08:43:31.087Z","etag":null,"topics":["advanced-javascript","documentation","javascript","markdown"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ooade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-02T02:54:52.000Z","updated_at":"2024-08-31T12:54:02.000Z","dependencies_parsed_at":"2022-09-10T15:01:03.270Z","dependency_job_id":null,"html_url":"https://github.com/ooade/Advanced-JavaScript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ooade%2FAdvanced-JavaScript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ooade%2FAdvanced-JavaScript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ooade%2FAdvanced-JavaScript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ooade%2FAdvanced-JavaScript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ooade","download_url":"https://codeload.github.com/ooade/Advanced-JavaScript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249715182,"owners_count":21314995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["advanced-javascript","documentation","javascript","markdown"],"created_at":"2024-10-01T17:11:17.053Z","updated_at":"2025-04-19T14:33:17.060Z","avatar_url":"https://github.com/ooade.png","language":"JavaScript","readme":"# Advanced-JavaScript\n\nThis documentation is based on John Resig's website on Advanced JavaScript. If these concepts seem complex to you, i recommend [these resources](https://github.com/micromata/awesome-javascript-learning) and also strongly recommend [FreeCodeCamp - Learn to code and help nonprofits](https://www.freecodecamp.org). If you feel you know most of these concepts, you could just try out the [quizzes](#quizzes) and you're good to go.\n\n\n## Contents\n\n- [Goal](#goal)\n- [Helper Methods](#helper-methods)\n- [Running a Quiz](#running-a-quiz)\n- [Lessons](#lessons)\n  - [Defining Functions](#defining-functions)\n    - [Order of function definition](#order-of-function-definition)\n    - [Where can assignment be accessed](#where-can-assignments-be-accessed)\n    - [Can functions be defined below return statements](#can-functions-be-defined-below-return-statements)\n  - [Named Functions](#named-functions)\n    - [What is the name of a function](#what-is-the-name-of-a-function)\n    - [With anonymous function that's an object property](#with-anonymous-function-thats-an-object-property)\n    - [What happens when we remove the original object](#what-happens-when-we-remove-the-original-object)\n    - [Let's give the anonymous function a name](#lets-give-the-anonymous-function-a-name)\n  - [Functions as Objects](#functions-as-objects)\n    - [How similar are functions and objects](#how-similar-are-functions-and-objects)\n    - [Is it possible to cache the return results from a function](#is-it-possible-to-cache-the-return-results-from-a-function)\n    - [One possible way to cache the results](#one-possible-way-to-cache-the-results)\n  - [Context](#context)\n    - [What happens if a function is an object property](#what-happens-if-a-function-is-an-object-property)\n    - [What exactly does context represent](#what-exactly-does-context-represent)\n    - [How can we change the context of a function](#how-can-we-change-the-context-of-a-function)\n    - [Different ways of changing the context](#different-ways-of-changing-the-context)\n    - [How can we implement looping with a callback](#how-can-we-implement-looping-with-a-callback)\n    - [A possible solution for function looping](#a-possible-solution-for-function-looping)\n  - [Instantiation](#instantiation)\n    - [What does the new operator do](#what-does-the-new-operator-do)\n    - [We have a 'this' context that is a Ninja object](#we-have-a-this-context-that-is-a-ninja-object)\n    - [Add a new property and method to the object](#add-a-new-property-and-method-to-the-object)\n    - [What happens when we forget to use the new operator](#what-happens-when-we-forget-to-use-the-new-operator)\n    - [Cont: What happens when we forget to use the new operator](#cont-what-happens-when-we-forget-to-use-the-new-operator)\n    - [We need to make sure that the new operator is always used](#we-need-to-make-sure-that-the-new-operator-is-always-used)\n    - [A solution using arguments.callee](#a-solution-using-arguments-callee)\n  - [Flexible Arguments](#flexible-arguments)\n    - [Using a variable number of arguments to our advantage](#using-a-variable-number-of-arguments-to-our-advantage)\n    - [How can we find the Min/Max number in an array](#how-can-we-find-the-min-max-number-in-an-array)\n    - [Another possible solution](#another-possible-solution)\n    - [Uh oh, what's going wrong here](#uh-oh-whats-going-wrong-here)\n    - [We can use built-in methods to our advantage](#we-can-use-built-in-methods-to-our-advantage)\n    - [We can use call and apply to build a solution](#we-can-use-call-and-apply-to-build-a-solution)\n  - [Closures](#closures)\n    - [But why doesn't this work](#but-why-doesnt-this-work)\n    - [Closures are frequently used for callbacks](#closures-are-frequently-used-for-callbacks)\n    - [They're also useful for timers](#theyre-also-useful-for-timers)\n    - [And they're also frequently used when attaching event listeners](#and-theyre-also-frequently-used-when-attaching-event-listeners)\n    - [Private properties, using closures](#private-properties-using-closures)\n    - [The last one is quite tricky, we'll revisit it](#the-last-one-is-quite-tricky-well-revisit-it)\n  - [Temporary Scope](#temporary-scope)\n    - [Self-executing, temporary, function](#self-executing-temporary-function)\n    - [Now we can handle closures and looping](#now-we-can-handle-closures-and-looping)\n    - [The anonymous wrapper functions are also useful for wrapping libraries](#the-anonymous-wrapper-functions-are-also-useful-for-wrapping-libraries)\n    - [Another way to wrap a library](#another-way-to-wrap-a-library)\n    - [A quick wrapper function will do the trick](#a-quick-wrapper-function-will-do-the-trick)\n  - [Function Prototypes](#function-prototypes)\n    - [Adding a prototyped method to a function](#adding-a-prototyped-method-to-a-function)\n    - [Properties added in the constructor (or later) override prototyped properties](#properties-added-in-the-constructor-or-later-override-prototyped-properties)\n    - [Prototyped properties affect all objects of the same constructor, simultaneously, even if they already exist](#prototyped-properties-affect-all-objects-of-the-same-constructor-simultaneously-even-if-they-already-exist)\n    - [The chainable method must return this](#the-chainable-method-must-return-this)\n  - [Instance Type](#instance-type)\n    - [Examining the basics of an object](#examining-the-basics-of-an-object)\n    - [We can still use the constructor to build other instances](#we-can-still-use-the-constructor-to-build-other-instances)\n    - [Use the .constructor property to dig in](#use-the-constructor-property-to-dig-in)\n  - [Inheritance](#inheritance)\n    - [The basics of how prototypal inheritance works](#the-basics-of-how-prototypal-inheritance-works)\n    - [The result is rather straight-forward](#the-result-is-rather-straight-forward)\n  - [Built-in Prototypes](#built-in-prototypes)\n    - [We can also modify built-in object prototypes](#we-can-also-modify-built-in-object-prototypes)\n    - [Beware: Extending prototypes can be dangerous](#beware-extending-prototypes-can-be-dangerous)\n  - [Enforcing Function Context](#enforcing-function-context)\n    - [What happens when we try to bind an object's method to a click handler](#what-happens-when-we-try-to-bind-an-objects-method-to-a-click-handler)\n    - [We need to keep its context as the original object](#we-need-to-keep-its-context-as-the-original-object)\n    - [Add a method to all functions to allow context enforcement](#add-a-method-to-all-functions-to-allow-context-enforcement)\n    - [Our final target (the .bind method from Prototype.js)](#our-final-target-the-bind-method-from-prototype-js)\n  - [Bonus: Function Length](#bonus-function-length)\n    - [How does a function's length property work](#how-does-a-functions-length-property-work)\n    - [We can use it to implement method overloading](#we-can-use-it-to-implement-method-overloading)\n    - [How method overloading might work, using the function length property](#how-method-overloading-might-work-using-the-function-length-property)\n- [Quizzes](#quizzes)\n  - [QUIZ: Can you cache the results of this function](#quiz-can-you-cache-the-results-of-this-function)\n  - [QUIZ: Add a method that gives a name to the ninja](#quiz-add-a-method-that-gives-a-name-to-the-ninja)\n  - [QUIZ: Is there another, more generic, way of doing this](#quiz-is-there-another-more-generic-way-of-doing-this)\n  - [QUIZ: We must convert array-like objects into actual arrays. Can any built-in methods help](#quiz-we-must-convert-array-like-objects-into-actual-arrays-can-any-built-in-methods-help)\n  - [QUIZ: Implement a multiplication function (first argument by largest number)](#quiz-implement-a-multiplication-function-first-argument-by-largest-number-)\n  - [QUIZ: What are the values of the variables](#quiz-what-are-the-values-of-the-variables)\n  - [QUIZ: Fix the broken closures in this loop](#quiz-fix-the-broken-closures-in-this-loop)\n  - [QUIZ: Make a chainable Ninja method](#quiz-make-a-chainable-ninja-method)\n  - [QUIZ: Make another instance of a Ninja](#quiz-make-another-instance-of-a-ninja)\n  - [QUIZ: Let's try our hand at inheritance](#quiz-lets-try-our-hand-at-inheritance)\n- [Credits](#credits)\n- [Change Logs](#change-logs)\n\n### Goal\n\nTo be able to understand this function:\n\n```js\n// The .bind method from Prototype.js\nFunction.prototype.bind = function(){\n  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();\n  return function(){\n    return fn.apply(object,\n      args.concat(Array.prototype.slice.call(arguments)));\n  };\n};\n```\n\n### Helper Methods\n\n```js\nassert( true, \"I'll pass.\" ); //passes\nassert( \"truey\", \"So will I.\" ); //passes\nassert( false, \"I'll fail.\" ); //fails\nassert( null, \"So will I.\" ); //fails\nlog( \"Just a simple log\", \"of\", \"values.\", true );\nerror( \"I'm an error!\" );\n```\n\n### Running a Quiz\n\nIt's not quite hard.\n\n1. Fork the Repo.\n2. Clone the Repo to your machine.\n3. `npm install`.\n4. `node start.js`\n\n## Lessons\n\n### Defining Functions\n\nFunctions can be defined like these:\n\n```js\nfunction isNimble(){ return true; }\nvar canFly = function(){ return true; };\nwindow.isDeadly = function(){ return true; };\nlog(isNimble, canFly, isDeadly);\n```\n\n#### Order of function definition\n\nOrder doesn't matter for [functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) like `isNimble`.\n\n```js\nvar canFly = function(){ return true; };\nwindow.isDeadly = function(){ return true; };\nassert( isNimble() \u0026\u0026 canFly() \u0026\u0026 isDeadly(), \"Still works, even though isNimble is moved.\" );\nfunction isNimble(){ return true; }\n```\n\n#### Where can assignments be accessed\n\nThe Order does matter for `canFly` and `isDeadly`.\n\n```js\nassert( typeof canFly == \"undefined\", \"canFly doesn't get that benefit.\" );\nassert( typeof isDeadly == \"undefined\", \"Nor does isDeadly.\" );\nvar canFly = function(){ return true; };\nwindow.isDeadly = function(){ return true; };\n```\n\n#### Can functions be defined below return statements\n\nYes, can be defined but can be called below return statements.\n\n```js\nfunction stealthCheck(){\n  assert( stealth(), \"We'll never get below the return, but that's OK!\" );\n\n  return stealth();\n\n  function stealth(){ return true; }\n}\n\nstealthCheck();\n```\n\n### Named Functions\n\nWe can refer to a function, within itself, by its name.\n\n```js\nfunction yell(n){\n  return n \u003e 0 ? yell(n-1) + \"a\" : \"hiy\";\n}\nassert( yell(4) == \"hiyaaaa\", \"Calling the function by itself comes naturally.\" );\n```\n\n#### What is the name of a function\n\n```js\nvar ninja = function myNinja(){\n  assert( ninja == myNinja, \"This function is named two things - at once!\" );\n};\nninja();\nassert( typeof myNinja == \"undefined\", \"But myNinja isn't defined outside of the function.\" ); // myNinja exist only within the function scope\nlog( ninja );\n```\n\n#### With anonymous function that's an object property\n\nYeah, we could also have \"hiyaaaa\" displayed, with an anonymous function that's an Object Property.\n\n```js\nvar ninja = {\n  yell: function(n){\n    return n \u003e 0 ? ninja.yell(n-1) + \"a\" : \"hiy\";\n  }\n};\nassert( ninja.yell(4) == \"hiyaaaa\", \"A single object isn't too bad, either.\" );\n```\n\n#### What happens when we remove the original object\n\n```js\nvar ninja = {\n  yell: function(n){\n    return n \u003e 0 ? ninja.yell(n-1) + \"a\" : \"hiy\";\n  }\n};\nassert( ninja.yell(4) == \"hiyaaaa\", \"A single object isn't too bad, either.\" );\n\nvar samurai = { yell: ninja.yell };\nvar ninja = null;\n\ntry {\n  samurai.yell(4);\n} catch(e){\n  assert( false, \"Uh, this isn't good! Where'd ninja.yell go\" );\n}\n```\n\n#### Let's give the anonymous function a name\n\n```js\nvar ninja = {\n  yell: function yell(n){\n    return n \u003e 0 ? yell(n-1) + \"a\" : \"hiy\";\n  }\n};\nassert( ninja.yell(4) == \"hiyaaaa\", \"Works as we would expect it to!\" );\n\nvar samurai = { yell: ninja.yell };\nvar ninja = null;\nassert( samurai.yell(4) == \"hiyaaaa\", \"The method correctly calls itself.\" );\n```\n\n#### What if we don't want to give the function a name\n\n`arguments.callee` does the trick here :)\n\n```js\nvar ninja = {\n  yell: function(n){\n    return n \u003e 0 ? arguments.callee(n-1) + \"a\" : \"hiy\";\n  }\n};\nassert( ninja.yell(4) == \"hiyaaaa\", \"arguments.callee is the function itself.\" );\n```\n\n### Functions as Objects\n\n#### How similar are functions and objects\n\n```js\nvar obj = {};\nvar fn = function(){};\nassert( obj \u0026\u0026 fn, \"Both the object and function exist.\" );\n```\n\nMore similarity:\n\n```js\nvar obj = {};\nvar fn = function(){};\nobj.prop = \"some value\";\nfn.prop = \"some value\";\nassert( obj.prop == fn.prop, \"Both are objects, both have the property.\" );\n```\n\n#### Is it possible to cache the return results from a function\n\nYes! It is.\n\n```js\nfunction getElements( name ) {\n  var results;\n\n  if ( getElements.cache[name] ) {\n    results = getElements.cache[name];\n  } else {\n    results = document.getElementsByTagName(name);\n    getElements.cache[name] = results;\n  }\n\n  return results;\n}\ngetElements.cache = {};\n\nlog( \"Elements found: \", getElements(\"pre\").length );\nlog( \"Cache found: \", getElements.cache.pre.length );\n```\n\n#### QUIZ: Can you cache the results of this function\n\n```js\nfunction isPrime( num ) {\n  var prime = num != 1; // Everything but 1 can be prime\n  for ( var i = 2; i \u003c num; i++ ) {\n    if ( num % i == 0 ) {\n      prime = false;\n      break;\n    }\n  }\n  return prime;\n}\n\nassert( isPrime(5), \"Make sure the function works, 5 is prime.\" );\nassert( isPrime.cache[5], \"Is the answer cached\" );\n```\n\n#### One possible way to cache the results\n\n```js\nfunction isPrime( num ) {\n  if ( isPrime.cache[ num ] != null )\n    return isPrime.cache[ num ];\n\n  var prime = num != 1; // Everything but 1 can be prime\n  for ( var i = 2; i \u003c num; i++ ) {\n    if ( num % i == 0 ) {\n      prime = false;\n      break;\n    }\n  }\n\n  isPrime.cache[ num ] = prime\n\n  return prime;\n}\n\nisPrime.cache = {};\n\nassert( isPrime(5), \"Make sure the function works, 5 is prime.\" );\nassert( isPrime.cache[5], \"Make sure the answer is cached.\" );\n```\n\n### Context\n\n#### What happens if a function is an object property\n\n```js\nvar katana = {\n  isSharp: true,\n  use: function(){\n    this.isSharp = !this.isSharp;\n  }\n};\nkatana.use();\nassert( !katana.isSharp, \"Verify the value of isSharp has been changed.\" );\n```\n\n#### What exactly does context represent\n\n```js\nfunction katana(){\n  this.isSharp = true;\n}\nkatana();\nassert( isSharp === true, \"A global object now exists with that name and value.\" );\n\nvar shuriken = {\n  toss: function(){\n    this.isSharp = true;\n  }\n};\nshuriken.toss();\nassert( shuriken.isSharp === true, \"When it's an object property, the value is set within the object.\" );\n```\n\n#### How can we change the context of a function\n\n```js\nvar object = {};\nfunction fn(){\n  return this;\n}\nassert( fn() == this, \"The context is the global object.\" );\nassert( fn.call(object) == object, \"The context is changed to a specific object.\" );\n```\n\n#### Different ways of changing the context\n\n```js\nfunction add(a, b){\n  return a + b;\n}\nassert( add.call(this, 1, 2) == 3, \".call() takes individual arguments\" );\nassert( add.apply(this, [1, 2]) == 3, \".apply() takes an array of arguments\" );\n```\n\n#### QUIZ: How can we implement looping with a callback\n\n```js\nfunction loop(array, fn){\n  for ( var i = 0; i \u003c array.length; i++ ) {\n    // Implement me!\n  }\n}\nvar num = 0;\nloop([0, 1, 2], function(value){\n  assert(value == num++, \"Make sure the contents are as we expect it.\");\n  assert(this instanceof Array, \"The context should be the full array.\");\n});\n```\n\n\u003c!---\n  TODO: This needs improvements tho because if we forget to pass the the necessary args, it will still pass. i.e: fn.call(array, i); // oops!\n--\u003e\n\n#### A possible solution for function looping\n\n```js\nfunction loop(array, fn){\n  for ( var i = 0; i \u003c array.length; i++ )\n    fn.call( array, array[i], i );\n}\nvar num = 0;\nloop([0, 1, 2], function(value, i){\n  assert(value == num++, \"Make sure the contents are as we expect it.\");\n  assert(this instanceof Array, \"The context should be the full array.\");\n});\n```\n\n### Instantiation\n\n#### What does the new operator do\n\n```js\nfunction Ninja(){\n  this.name = \"Ninja\";\n}\n\nvar ninjaA = Ninja();\nassert( !ninjaA, \"Is undefined, not an instance of Ninja.\" );\n\nvar ninjaB = new Ninja();\nassert( ninjaB.name == \"Ninja\", \"Property exists on the ninja instance.\" );\n```\n\n#### We have a 'this' context that is a Ninja object\n\n```js\nfunction Ninja(){\n  this.swung = false;\n\n  // Should return true\n  this.swingSword = function(){\n    this.swung = !this.swung;\n    return this.swung;\n  };\n}\n\nvar ninja = new Ninja();\nassert( ninja.swingSword(), \"Calling the instance method.\" );\nassert( ninja.swung, \"The ninja has swung the sword.\" );\n\nvar ninjaB = new Ninja();\nassert( !ninjaB.swung, \"Make sure that the ninja has not swung his sword.\" );\n```\n\n#### QUIZ: Add a method that gives a name to the ninja\n\n```js\nfunction Ninja(name){\n  // Implement!\n}\n\nvar ninja = new Ninja(\"John\");\nassert( ninja.name == \"John\", \"The name has been set on initialization\" );\n\nninja.changeName(\"Bob\");\nassert( ninja.name == \"Bob\", \"The name was successfully changed.\" );\n```\n\n#### Add a new property and method to the object\n\n```js\nfunction Ninja(name){\n  this.changeName = function(name){\n    this.name = name;\n  };\n\n  this.changeName( name );\n}\n\nvar ninja = new Ninja(\"John\");\nassert( ninja.name == \"John\", \"The name has been set on initialization\" );\n\nninja.changeName(\"Bob\");\nassert( ninja.name == \"Bob\", \"The name was successfully changed.\" );\n```\n\n#### What happens when we forget to use the new operator\n\n```js\nfunction User(first, last){\n  this.name = first + \" \" + last;\n}\n\nvar user = User(\"John\", \"Resig\");\nassert( typeof user == \"undefined\", \"Since new wasn't used, the instance is undefined.\" );\n```\n\n#### Cont: What happens when we forget to use the new operator\n\n```js\nfunction User(first, last){\n  this.name = first + \" \" + last;\n}\n\nwindow.name = \"Resig\";\nvar user = User(\"John\", name);\n\nassert( name == \"John Resig\", \"The name variable is accidentally overridden.\" );\n```\n\n#### We need to make sure that the new operator is always used\n\n```js\nfunction User(first, last){\n  if ( !(this instanceof User) )\n    return new User(first, last);\n\n  this.name = first + \" \" + last;\n}\n\nvar name = \"Resig\";\nvar user = User(\"John\", name);\n\nassert( user, \"This was defined correctly, even if it was by mistake.\" );\nassert( name == \"Resig\", \"The right name was maintained.\" );\n```\n\n#### QUIZ: Is there another, more generic, way of doing this\n\n```js\nfunction User(first, last){\n  // Replace ___ with a value\n  if ( !(this instanceof ___) )\n    return new User(first, last);\n\n  this.name = first + \" \" + last;\n}\n\nvar name = \"Resig\";\nvar user = User(\"John\", name);\n\nassert( user, \"This was defined correctly, even if it was by mistake.\" );\nassert( name == \"Resig\", \"The right name was maintained.\" );\n```\n\n#### A solution using arguments.callee\n\n```js\nfunction User(first, last){\n  if ( !(this instanceof arguments.callee) )\n    return new User(first, last);\n\n  this.name = first + \" \" + last;\n}\n\nvar name = \"Resig\";\nvar user = User(\"John\", name);\n\nassert( user, \"This was defined correctly, even if it was by mistake.\" );\nassert( name == \"Resig\", \"The right name was maintained.\" );\n```\n\n### Flexible Arguments\n\n#### Using a variable number of arguments to our advantage\n\n```js\nfunction merge(root){\n  for ( var i = 1; i \u003c arguments.length; i++ )\n    for ( var key in arguments[i] )\n      root[key] = arguments[i][key];\n  return root;\n}\n\nvar merged = merge({name: \"John\"}, {city: \"Boston\"});\nassert( merged.name == \"John\", \"The original name is intact.\" );\nassert( merged.city == \"Boston\", \"And the city has been copied over.\" );\n```\n\n#### How can we find the Min/Max number in an array\n\n```js\nfunction smallest(array){\n  return Math.min.apply( Math, array );\n}\nfunction largest(array){\n  return Math.max.apply( Math, array );\n}\nassert(smallest([0, 1, 2, 3]) == 0, \"Locate the smallest value.\");\nassert(largest([0, 1, 2, 3]) == 3, \"Locate the largest value.\");\n```\n\n#### Another possible solution\n\n```js\nfunction smallest(){\n  return Math.min.apply( Math, arguments );\n}\nfunction largest(){\n  return Math.max.apply( Math, arguments );\n}\nassert(smallest(0, 1, 2, 3) == 0, \"Locate the smallest value.\");\nassert(largest(0, 1, 2, 3) == 3, \"Locate the largest value.\");\n```\n\n#### Uh oh, what's going wrong here\n\n```js\nfunction highest(){\n  return arguments.sort(function(a,b){\n    return b - a;\n  });\n}\nassert(highest(1, 1, 2, 3)[0] == 3, \"Get the highest value.\");\nassert(highest(3, 1, 2, 3, 4, 5)[1] == 4, \"Verify the results.\");\n```\n\n#### QUIZ: We must convert array-like objects into actual arrays. Can any built-in methods help\n\n\u003c!-- TODO: Remove the slice method on makeArray; Misguided as the first num will chopped off --\u003e\n\n```js\n// Hint: Arrays have .slice and .splice methods which return new arrays.\nfunction highest(){\n  return makeArray(arguments).slice(1).sort(function(a,b){\n    return b - a;\n  });\n}\n\nfunction makeArray(array){\n  // Implement me!\n}\n\n// Expecting: [3,2,1]\nassert(highest(1, 1, 2, 3)[0] == 3, \"Get the highest value.\");\n// Expecting: [5,4,3,2,1]\nassert(highest(3, 1, 2, 3, 4, 5)[1] == 4, \"Verify the results.\");\n```\n\n#### We can use built-in methods to our advantage\n\n```js\nfunction highest(){\n  return makeArray(arguments).sort(function(a,b){\n    return b - a;\n  });\n}\n\nfunction makeArray(array){\n  return Array().slice.call( array );\n}\n\nassert(highest(1, 1, 2, 3)[0] == 3, \"Get the highest value.\");\nassert(highest(3, 1, 2, 3, 4, 5)[1] == 4, \"Verify the results.\");\n```\n\n#### QUIZ: Implement a multiplication function (first argument by largest number)\n\n```js\nfunction multiMax(multi){\n  // Make an array of all but the first argument\n  var allButFirst = ___;\n\n  // Find the largest number in that array of arguments\n  var largestAllButFirst = ___;\n\n  // Return the multiplied result\n  return multi * largestAllButFirst;\n}\nassert( multiMax(3, 1, 2, 3) == 9, \"3*3=9 (First arg, by largest.)\" );\n```\n\n#### We can use call and apply to build a solution\n\n```js\nfunction multiMax(multi){\n  // Make an array of all but the first argument\n  var allButFirst = Array().slice.call( arguments, 1 );\n\n  // Find the largest number in that array of arguments\n  var largestAllButFirst = Math.max.apply( Math, allButFirst );\n\n  // Return the multiplied result\n  return multi * largestAllButFirst;\n}\nassert( multiMax(3, 1, 2, 3) == 9, \"3*3=9 (First arg, by largest.)\" );\n```\n\n### Closures\n\nA basic closure:\n\n```js\nvar num = 10;\n\nfunction addNum(myNum){\n  return num + myNum;\n}\n\nassert( addNum(5) == 15, \"Add two numbers together, one from a closure.\" );\n```\n\n#### But why doesn't this work\n\n```js\nvar num = 10;\n\nfunction addNum(myNum){\n  return num + myNum;\n}\n\nnum = 15;\n\nassert( addNum(5) == 15, \"Add two numbers together, one from a closure.\" );\n```\n\n#### Closures are frequently used for callbacks\n\n```js\nvar results = jQuery(\"#results\").html(\"\u003cli\u003eLoading...\u003c/li\u003e\");\n\njQuery.get(\"test.html\", function(html){\n  results.html( html );\n  assert( results, \"The element to append to, via a closure.\" );\n});\n```\n\n#### They're also useful for timers\n\n```js\nvar count = 0;\n\nvar timer = setInterval(function(){\n  if ( count \u003c 5 ) {\n    log( \"Timer call: \", count );\n    count++;\n  } else {\n    assert( count == 5, \"Count came via a closure, accessed each step.\" );\n    assert( timer, \"The timer reference is also via a closure.\" );\n    clearInterval( timer );\n  }\n}, 100);\n```\n\n#### And they're also frequently used when attaching event listeners\n\n```js\nvar count = 1;\nvar elem = document.createElement(\"li\");\nelem.innerHTML = \"Click me!\";\nelem.onclick = function(){\n  log( \"Click #\", count++ );\n};\ndocument.getElementById(\"results\").appendChild( elem );\nassert( elem.parentNode, \"Clickable element appended.\" );\n```\n\n#### Private properties, using closures\n\n```js\nfunction Ninja(){\n  var slices = 0;\n\n  this.getSlices = function(){\n    return slices;\n  };\n  this.slice = function(){\n    slices++;\n  };\n}\n\nvar ninja = new Ninja();\nninja.slice();\nassert( ninja.getSlices() == 1, \"We're able to access the internal slice data.\" );\nassert( ninja.slices === undefined, \"And the private data is inaccessible to us.\" );\n```\n\n#### QUIZ: What are the values of the variables\n\n```js\nvar a = 5;\nfunction runMe(a){\n assert( a == ___, \"Check the value of a.\" );\n\n function innerRun(){\n   assert( b == ___, \"Check the value of b.\" );\n   assert( c == ___, \"Check the value of c.\" );\n }\n\n var b = 7;\n innerRun();\n var c = 8;\n}\nrunMe(6);\n\nfor ( var d = 0; d \u003c 3; d++ ) {\n setTimeout(function(){\n   assert( d == ___, \"Check the value of d.\" );\n }, 100);\n}\n```\n\n#### The last one is quite tricky, we'll revisit it\n\n```js\nvar a = 5;\nfunction runMe(a){\n assert( a == 6, \"Check the value of a.\" );\n\n function innerRun(){\n   assert( b == 7, \"Check the value of b.\" );\n   assert( c == undefined, \"Check the value of c.\" );\n }\n\n var b = 7;\n innerRun();\n var c = 8;\n}\nrunMe(6);\n\nfor ( var d = 0; d \u003c 3; d++ ) {\n setTimeout(function(){\n   assert( d == 3, \"Check the value of d.\" );\n }, 100);\n}\n```\n\n### Temporary Scope\n\n#### Self-executing, temporary, function\n\n```js\n(function(){\n  var count = 0;\n\n  var timer = setInterval(function(){\n    if ( count \u003c 5 ) {\n      log( \"Timer call: \", count );\n      count++;\n    } else {\n      assert( count == 5, \"Count came via a closure, accessed each step.\" );\n      assert( timer, \"The timer reference is also via a closure.\" );\n      clearInterval( timer );\n    }\n  }, 100);\n})();\n\nassert( typeof count == \"undefined\", \"count doesn't exist outside the wrapper\" );\nassert( typeof timer == \"undefined\", \"neither does timer\" );\n```\n\n#### Now we can handle closures and looping\n\n```js\nfor ( var d = 0; d \u003c 3; d++ ) (function(d){\n setTimeout(function(){\n   log( \"Value of d: \", d );\n   assert( d == d, \"Check the value of d.\" );\n }, d * 200);\n})(d);\n```\n\n#### The anonymous wrapper functions are also useful for wrapping libraries\n\n```js\n(function(){\n  var myLib = window.myLib = function(){\n    // Initialize\n  };\n\n  // ...\n})();\n```\n\n#### Another way to wrap a library\n\n```js\nvar myLib = (function(){\n  function myLib(){\n    // Initialize\n  }\n\n  // ...\n\n  return myLib;\n})();\n```\n\n#### QUIZ: Fix the broken closures in this loop\n\n```js\nvar count = 0;\nfor ( var i = 0; i \u003c 4; i++ ) {\n  setTimeout(function(){\n    assert( i == count++, \"Check the value of i.\" );\n  }, i * 200);\n}\n```\n\n#### A quick wrapper function will do the trick\n\n```js\nvar count = 0;\nfor ( var i = 0; i \u003c 4; i++ ) (function(i){\n  setTimeout(function(){\n    assert( i == count++, \"Check the value of i.\" );\n  }, i * 200);\n})(i);\n```\n\n### Function Prototypes\n\n#### Adding a prototyped method to a function\n\n```js\nfunction Ninja(){}\n\nNinja.prototype.swingSword = function(){\n  return true;\n};\n\nvar ninjaA = Ninja();\nassert( !ninjaA, \"Is undefined, not an instance of Ninja.\" );\n\nvar ninjaB = new Ninja();\nassert( ninjaB.swingSword(), \"Method exists and is callable.\" );\n```\n\n#### Properties added in the constructor (or later) override prototyped properties\n\n```js\nfunction Ninja(){\n  this.swingSword = function(){\n    return true;\n  };\n}\n\n// Should return false, but will be overridden\nNinja.prototype.swingSword = function(){\n  return false;\n};\n\nvar ninja = new Ninja();\nassert( ninja.swingSword(), \"Calling the instance method, not the prototype method.\" );\n```\n\n#### Prototyped properties affect all objects of the same constructor, simultaneously, even if they already exist\n\n```js\nfunction Ninja(){\n  this.swung = true;\n}\n\nvar ninjaA = new Ninja();\nvar ninjaB = new Ninja();\n\nNinja.prototype.swingSword = function(){\n  return this.swung;\n};\n\nassert( ninjaA.swingSword(), \"Method exists, even out of order.\" );\nassert( ninjaB.swingSword(), \"and on all instantiated objects.\" );\n```\n\n#### QUIZ: Make a chainable Ninja method\n\n```js\nfunction Ninja(){\n  this.swung = true;\n}\n\nvar ninjaA = new Ninja();\nvar ninjaB = new Ninja();\n\n// Add a method to the Ninja prototype which\n// returns itself and modifies swung\n\nassert( !ninjaA.swing().swung, \"Verify that the swing method exists and returns an instance.\" );\nassert( !ninjaB.swing().swung, \"and that it works on all Ninja instances.\" );\n```\n\n#### The chainable method must return this\n\n```js\nfunction Ninja(){\n  this.swung = true;\n}\n\nvar ninjaA = new Ninja();\nvar ninjaB = new Ninja();\n\nNinja.prototype.swing = function(){\n  this.swung = false;\n  return this;\n};\n\nassert( !ninjaA.swing().swung, \"Verify that the swing method exists and returns an instance.\" );\nassert( !ninjaB.swing().swung, \"and that it works on all Ninja instances.\" );\n```\n\n### Instance Type\n\n#### Examining the basics of an object\n\n```js\nfunction Ninja(){}\n\nvar ninja = new Ninja();\n\nassert( typeof ninja == \"object\", \"However the type of the instance is still an object.\" );\nassert( ninja instanceof Ninja, \"The object was instantiated properly.\" );\nassert( ninja.constructor == Ninja, \"The ninja object was created by the Ninja function.\" );\n```\n\n#### We can still use the constructor to build other instances\n\n```js\nfunction Ninja(){}\nvar ninja = new Ninja();\nvar ninjaB = new ninja.constructor();\n\nassert( ninjaB instanceof Ninja, \"Still a ninja object.\" );\n```\n\n#### QUIZ: Make another instance of a Ninja\n\n```js\nvar ninja = (function(){\n function Ninja(){}\n return new Ninja();\n})();\n\n// Make another instance of Ninja\nvar ninjaB = ___;\n\nassert( ninja.constructor == ninjaB.constructor, \"The ninjas come from the same source.\" );\n```\n\n#### Use the .constructor property to dig in\n\n```js\nvar ninja = (function(){\n function Ninja(){}\n return new Ninja();\n})();\n\n// Make another instance of Ninja\nvar ninjaB = new ninja.constructor();\n\nassert( ninja.constructor == ninjaB.constructor, \"The ninjas come from the same source.\" );\n```\n\n### Inheritance\n\n#### The basics of how prototypal inheritance works\n\n```js\nfunction Person(){}\nPerson.prototype.dance = function(){};\n\nfunction Ninja(){}\n\n// Achieve similar, but non-inheritable, results\nNinja.prototype = Person.prototype;\nNinja.prototype = { dance: Person.prototype.dance };\n\nassert( (new Ninja()) instanceof Person, \"Will fail with bad prototype chain.\" );\n\n// Only this maintains the prototype chain\nNinja.prototype = new Person();\n\nvar ninja = new Ninja();\nassert( ninja instanceof Ninja, \"ninja receives functionality from the Ninja prototype\" );\nassert( ninja instanceof Person, \"... and the Person prototype\" );\nassert( ninja instanceof Object, \"... and the Object prototype\" );\n```\n\n#### QUIZ: Let's try our hand at inheritance\n\n```js\nfunction Person(){}\nPerson.prototype.getName = function(){\n  return this.name;\n};\n\n// Implement a function that inherits from Person\n// and sets a name in the constructor\n\nvar me = new Me();\nassert( me.getName(), \"A name was set.\" );\n```\n\n#### The result is rather straight-forward\n\n```js\nfunction Person(){}\nPerson.prototype.getName = function(){\n  return this.name;\n};\n\nfunction Me(){\n  this.name = \"John Resig\";\n}\nMe.prototype = new Person();\n\nvar me = new Me();\nassert( me.getName(), \"A name was set.\" );\n```\n\n### Built-in Prototypes\n\n#### We can also modify built-in object prototypes\n\n```js\nif (!Array.prototype.forEach) {\n  Array.prototype.forEach = function(fn){\n    for ( var i = 0; i \u003c this.length; i++ ) {\n      fn( this[i], i, this );\n    }\n  };\n}\n\n[\"a\", \"b\", \"c\"].forEach(function(value, index, array){\n  assert( value, \"Is in position \" + index + \" out of \" + (array.length - 1) );\n});\n```\n\n#### Beware: Extending prototypes can be dangerous\n\n```js\nObject.prototype.keys = function(){\n  var keys = [];\n  for ( var i in this )\n    keys.push( i );\n  return keys;\n};\n\nvar obj = { a: 1, b: 2, c: 3 };\n\nassert( obj.keys().length == 3, \"We should only have 3 properties.\" );\n\ndelete Object.prototype.keys;\n```\n\n### Enforcing Function Context\n\n#### What happens when we try to bind an object's method to a click handler\n\n```js\nvar Button = {\n  click: function(){\n    this.clicked = true;\n  }\n};\n\nvar elem = document.createElement(\"li\");\nelem.innerHTML = \"Click me!\";\nelem.onclick = Button.click;\ndocument.getElementById(\"results\").appendChild(elem);\n\nelem.onclick();\nassert( elem.clicked, \"The clicked property was accidentally set on the element\" );\n```\n\n#### We need to keep its context as the original object\n\n```js\nfunction bind(context, name){\n  return function(){\n    return context[name].apply(context, arguments);\n  };\n}\n\nvar Button = {\n  click: function(){\n    this.clicked = true;\n  }\n};\n\nvar elem = document.createElement(\"li\");\nelem.innerHTML = \"Click me!\";\nelem.onclick = bind(Button, \"click\");\ndocument.getElementById(\"results\").appendChild(elem);\n\nelem.onclick();\nassert( Button.clicked, \"The clicked property was correctly set on the object\" );\n```\n\n#### Add a method to all functions to allow context enforcement\n\n```js\nFunction.prototype.bind = function(object){\n  var fn = this;\n  return function(){\n    return fn.apply(object, arguments);\n  };\n};\n\nvar Button = {\n  click: function(){\n    this.clicked = true;\n  }\n};\n\nvar elem = document.createElement(\"li\");\nelem.innerHTML = \"Click me!\";\nelem.onclick = Button.click.bind(Button);\ndocument.getElementById(\"results\").appendChild(elem);\n\nelem.onclick();\nassert( Button.clicked, \"The clicked property was correctly set on the object\" );\n```\n\n#### Our final target (the .bind method from Prototype.js)\n\n\u003c!-- Let John Resig check this out --\u003e\n\n```js\nFunction.prototype.bind = function(){\n  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();\n  return function(){\n    return fn.apply(object,\n      args.concat(Array.prototype.slice.call(arguments)));\n  };\n};\n\nvar Button = {\n  click: function(value){\n    this.clicked = value;\n  }\n};\n\nvar elem = document.createElement(\"li\");\nelem.innerHTML = \"Click me!\";\nelem.onclick = Button.click.bind(Button, false);\ndocument.getElementById(\"results\").appendChild(elem);\n\nelem.onclick();\nassert( Button.clicked === false, \"The clicked property was correctly set on the object\" );\n```\n\n### Bonus: Function Length\n\n#### How does a function's length property work\n\n```js\nfunction makeNinja(name){}\nfunction makeSamurai(name, rank){}\nassert( makeNinja.length == 1, \"Only expecting a single argument\" );\nassert( makeSamurai.length == 2, \"Multiple arguments expected\" );\n```\n\n#### We can use it to implement method overloading\n\n```js\nfunction addMethod(object, name, fn){\n  // Save a reference to the old method\n  var old = object[ name ];\n\n  // Overwrite the method with our new one\n  object[ name ] = function(){\n    // Check the number of incoming arguments,\n    // compared to our overloaded function\n    if ( fn.length == arguments.length )\n      // If there was a match, run the function\n      return fn.apply( this, arguments );\n\n    // Otherwise, fallback to the old method\n    else if ( typeof old === \"function\" )\n      return old.apply( this, arguments );\n  };\n}\n```\n\n#### How method overloading might work, using the function length property\n\n```js\nfunction addMethod(object, name, fn){\n  // Save a reference to the old method\n  var old = object[ name ];\n\n  // Overwrite the method with our new one\n  object[ name ] = function(){\n    // Check the number of incoming arguments,\n    // compared to our overloaded function\n    if ( fn.length == arguments.length )\n      // If there was a match, run the function\n      return fn.apply( this, arguments );\n\n    // Otherwise, fallback to the old method\n    else if ( typeof old === \"function\" )\n      return old.apply( this, arguments );\n  };\n}\n\nfunction Ninjas(){\n  var ninjas = [ \"Dean Edwards\", \"Sam Stephenson\", \"Alex Russell\" ];\n  addMethod(this, \"find\", function(){\n    return ninjas;\n  });\n  addMethod(this, \"find\", function(name){\n    var ret = [];\n    for ( var i = 0; i \u003c ninjas.length; i++ )\n      if ( ninjas[i].indexOf(name) == 0 )\n        ret.push( ninjas[i] );\n    return ret;\n  });\n  addMethod(this, \"find\", function(first, last){\n    var ret = [];\n    for ( var i = 0; i \u003c ninjas.length; i++ )\n      if ( ninjas[i] == (first + \" \" + last) )\n        ret.push( ninjas[i] );\n    return ret;\n  });\n}\n\nvar ninjas = new Ninjas();\nassert( ninjas.find().length == 3, \"Finds all ninjas\" );\nassert( ninjas.find(\"Sam\").length == 1, \"Finds ninjas by first name\" );\nassert( ninjas.find(\"Dean\", \"Edwards\").length == 1, \"Finds ninjas by first and last name\" );\nassert( ninjas.find(\"Alex\", \"X\", \"Russell\") == null, \"Does nothing\" );\n```\n\n## Credits\n\n[John Resig](https://github.com/jeresig) - He made the whole thing.\n\n## Change Logs\n\u003c!-- Any Changes in John's code will be placed here --\u003e\n\n## Contribution\n\nContributions are highly welcome\n\n## License\n\nISC\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fooade%2Fadvanced-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fooade%2Fadvanced-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fooade%2Fadvanced-javascript/lists"}