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