
Aún Menos
1 // Soy un float.
"nyancat"
["Soy", "Un", "Arreglo"]
{"Soy": "un",
"Objecto": "."}
true, false
(function(num) {
if (num < 0) {
return -num;
} else {
return num;
};
});
(function(num) {
if (num < 0) {
return -num;
} else {
return num;
};
})(-1);
// => 1
var abs = function(num) {
if (num < 0) {
return -num;
} else {
return num;
};
};
abs(-1);
abs(0);
abs(1);
abs(-Infinity);
var r = 5;
function foo(n) {
var r = 2;
r *= n
return r;
}
r // 5
foo(4) // 8
r // 5
¿IteraQué? Higher Order functions.
-
Map
-
Filter
-
Reduce
function square(num) {
return num * num
};
[ -1 , 1, 3, 8].map(square);
// [1, 1, 9, 64]
function isEven(num) {
if (num % 2 === 0) {
return true;
} else {
return false;
};
};
[0, 1, 2, 3, 4, 5].filter(isEven);
// [0, 2, 4]
function returnMax(prev, curr) {
if (curr > prev) {
return curr;
} else {
return prev;
};
};
[-1, -5, 2, 10, 3, 5, 1, -99].reduce(returnMax);
// 10
[-1, -5, 2, -10, 3, 5, 1, -99].reduce(returnMax);
// 5
Interludio
Scope
El 'rango' donde una un nombre se refiere a la misma referencia (variable).
Extent
El tiempo durante el que la variable existe o dura.
Function
+
Environment
===
Closures
function getMaxValueFactory () {
var max = -Infinity;
return function(prev, curr) {
if (curr > max) {
max = curr;
}
return max;
}
};
var mf = getMaxValueFactory();
[-1, -5, 2, -10, 3, 5, 1, -99].reduce(mf);
// 5
[-1, -5, 2, 10, 3, 5, 1, -99].reduce(mf);
// 10
[-1, -5, 2, -10, 3, 5, 1, -99].reduce(mf);
// 10
Closures as Modules
var myModule = (function() {
// código aqui
// API publica aqui
return {
'foo': foo,
'bar': bar
};
})();
Ejemplo
var counter = (function() {
var count = 0;
var inc = function () {
count += 1;
}
var dec = function () {
count -= 1;
}
return {
'inc': inc,
'dec': dec
};
})();
Una variación
var myModule = (function(window, document, undefined) {
// código aqui
// API publica aqui
return {
'foo': foo,
'bar': bar
};
})(window, window.document);
Open Modules
var myModule = (function(m) {
m.foo = function () { /* … */ };
m.bar = function () { /* … */ };
// ...
return m;
})(myModule || {});
Closures as Objects
var pedometer = function (){
var make = function (countedObjectName) {
var counter = 0;
var reset = function () {
counter = 0;
};
var inc = function () {
counter += 1;
}
var print = function () {
console.log("There are", counter, countedObjectName);
}
return {
'reset': reset,
'inc': inc,
'print': print
}
};
return {
'make': make
}
}();
var men = pedometer.make("men");
var women = pedometer.make("women")
men.print() // There are 0 men
women.print() // There are 0 women
women.inc()
women.inc()
console.log("====");
men.print() // There are 0 men
women.print() // There are 2 women
console.log("====");
men.inc()
women.inc()
men.print() // There are 1 men
women.print() // There are 3 women
function fibNth(n) {
if (n === 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
return fibNth(n - 1) + fibNth(n - 2);
}
};
function memoize(f) {
var cache = {};
return function (x) {
if (!cache.hasOwnProperty(x)) {
cache[x] = f(x);
}
return cache[x];
}
};
var mf = memoize(fibNth)
mf(4) // => 3
To @wxo's demo
Constant Folding con Esprima et al.
Que es Esprima?
Un traductor de Javascript a JSON, facilitando la transformacion de código.
Constant Folding
Constant folding
es el proceso de reconocer y evaluar expresiones constantes durante la compilacion en lugar de durante la ejecución.
var x = 2 + 5;
// =>
var x = 7;
First Stab
/// Boilerplate
var esprima = require('esprima');
var parse = esprima.parse;
var escodegen = require('escodegen');
var estraverse = require('estraverse');
var Syntax = estraverse.Syntax;
var generate = escodegen.generate;
var run = function(code, transformation) {
console.log('running', transformation.name);
console.log('Input:', code)
console.log('Output', generate(transformation(parse(code))));
}
First Stab
function most_simple_constant_foldling(stmt) {
estraverse.replace(
stmt,
{
enter: function(node) {
if (node.type === 'BinaryExpression')
{
if (node.operator === "+" &&
node.left.type === "Literal" &&
node.right.type === "Literal") {
var result = node.left.value + node.right.value;
return { type: "Literal",
value: result};
} else {
return node;
}
}
}
})
return stmt;
};
run('var x = 2 + 4', most_simple_constant_foldling);
// running most_simple_constant_foldling
// Input: var x = 2 + 4
// Output var x = 6;
- * /
// running most_simple_constant_foldling
// Input: var x = 2 - 4
// Output var x = 2 - 4;
// Faltan el resto operadores aritméticos
function too_simple_constant_folding(stmt) {
estraverse.replace(
stmt,
{
enter: function(node) {
if (node.type === Syntax.BinaryExpression &&
node.left.type === Syntax.Literal &&
node.right.type === Syntax.Literal) {
if (node.operator === "+") {
return { type: Syntax.Literal,
value: node.left.value + node.right.value };
} else if ( node.operator === "-") {
return { type: Syntax.Literal,
value: node.left.value - node.right.value };
} else if (node.operator === "*") {
return { type: Syntax.Literal,
value: node.left.value * node.right.value }
} else if (node.operator === "/") {
return { type: Syntax.Literal,
value: node.left.value / node.right.value }
}};
}
})
return stmt; };
// Input: var x = 4 - 2
// Output var x = 2;
// Input: var x = 4 / 2
// Output var x = 2;
// Input: var x = 4 / 0
/ Output var x = 1e+400;
function finicky_simple_constant_folding(stmt) {
estraverse.replace(
stmt,
{
enter: function(node) {
if (node.type === Syntax.BinaryExpression &&
node.left.type === Syntax.Literal &&
node.right.type === Syntax.Literal) {
if (node.operator === "+") {
return { type: Syntax.Literal,
value: node.left.value + node.right.value };
} else if ( node.operator === "-") {
return { type: Syntax.Literal,
value: node.left.value - node.right.value };
} else if (node.operator === "*") {
return { type: Syntax.Literal,
value: node.left.value * node.right.value }
} else if (node.operator === "/") {
var result = node.left.value / node.right.value;
if (isFinite(result)) {
return { type: Syntax.Literal,
value: result }
}
}};
}
})
return stmt; };
run('var x = 4 - 8', too_simple_constant_folding);
// Error: Numeric literal whose value is negative
// ¿Cómo se representa -2?
{
"type": "UnaryExpression",
"operator": "-",
"argument": {
"type": "Literal",
"value": 2,
"raw": "2"
},
"prefix": true
}
function wrap_negative_values(node) {
if (node.value < 0) {
return { type: Syntax.UnaryExpression,
operator: "-",
prefix: true,
argument: { type: Syntax.Literal,
value: -node.value}}
} else {
return node;
}
}
/// ...
if ( node.operator === "-") {
return wrap_negative_values({ type: Syntax.Literal,
value: node.left.value - node.right.value });
/// ...
run('var x = 4 + 2 + 8', i_hope_it_does_simple_constant_folding);
// running i_hope_it_does_simple_constant_folding
// Input: var x = 4 + 2 + 8
// Output var x = 6 + 8;
function alas_simple_constant_folding(stmt) {
var modified = true;
while (modified) {
modified = false;
estraverse.replace(
stmt,
{
enter: function(node) {
if (node.type === Syntax.BinaryExpression &&
node.left.type === Syntax.Literal &&
node.right.type === Syntax.Literal) {
if (node.operator === "+") {
modified = true;
return { type: Syntax.Literal,
value: node.left.value + node.right.value };
// ...
} else if (node.operator === "/") {
var result = node.left.value / node.right.value;
if (isFinite(result) || !isNaN(result)) {
modified = true;
return { type: Syntax.Literal,
value: result }
}
}};
}
})
};
return stmt; }
Do you want to know more?
Gracias
¿Preguntas?
next
Javascript 101
By puercopop
Javascript 101
- 685