Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the purpose of the function annotation method in the Facebook JavaScript SDK?

I'm starting using facebook javscript SDK, and I found a interesting thing when I read the source code.

The code example is as belowed:

/**
 * Annotates a function with a meta object
 */
function annotate(fn, meta) {
    meta.superClass = fn.__superConstructor__;
    fn.__TCmeta = meta;
    return fn;
}

// export to global
__w = annotate;

/**
 * when using the annotate function
 */
function sprintf(format) {
   // function body
}
__w(sprintf, {"signature":"function(string)"});   // <-- what is the purpose of doing this?

So, my question is what is that used for? What is the benefit doing this?

FYI, the whole source code is here, where you can see lots of annotate() is being used

http://connect.facebook.net/en_US/all/debug.js

like image 307
user1481096 Avatar asked Oct 03 '13 01:10

user1481096


1 Answers

It appears to be a home-grown strong typing setup:

/**
 * A recursive descent analyzer which takes a value and a typehint, validating
 * whether or not the value matches the typehint.
 * The function will call it self as long as both the value and the typehint
 * yields a nested component. This means that we will never recurse deeper
 * than needed, and also that we automatically get support for
 *   > equals([], 'array<string>') // true
 *   > equals(['string'], 'array') // true
 */
function equals(value, node) {
  var type = typeof value;
  var subType;
  var nextNode;
  var nextValue;

  //: Nullable types are delimited with a leading ?
  //: ?string, ?boolean, etc.
  var nullable = /^\?/.test(node);
  if (nullable) {
    node = node.substring(1);
  }

//: snip ...

switch (type) {
  // start by testing the most common types
  case 'boolean':
  case 'number':
  case 'string':
  case 'undefined':
    break;
  default:
      //: snip ...
      // let functions with signatures also match 'function'
      type = value.__TCmeta && node !== 'function'
        ? value.__TCmeta.signature
        : 'function';
    } else if (type === 'object' || type === 'function') {
      // HTMLObjectElements has a typeof function in FF
      var constructor = value.constructor;
      if (constructor && constructor.__TCmeta) {
        // The value is a custom type
        //: snip ...
          while (constructor && constructor.__TCmeta) {
            if (constructor.__TCmeta.type == node) {
              type = node;
              break;
            }
            constructor = constructor.__TCmeta.superClass;
          }
        //: snip ...
        }
      }
    }
}

if (nullable && /undefined|null/.test(type)) {
  return true;
}

if (type in typeInterfaces) {
  var interfaces = typeInterfaces[type], i = interfaces.length;
  while (i--) {
    if (interfaces[i] === node) {
      type = node;
      break;
    }
  }
}

currentType.push(type);
return nextValue && nextNode
  ? node === type && equals(nextValue, nextNode)
  : subType && nextNode
    ? node === type && subType === nextNode
    : node === type;
}

 

/**
 * Given a value and a typehint (can be a union type), this will return
 * whether or not the passed in value matches the typehint.
 */
function matches(value, node) {
  var nodes = node.split('|'), i = nodes.length;
  while (i--) {
    currentType = [];
    if (equals(value, nodes[i])) {
      return true;
    }
  }
  return false;
}

The reason they use the annotate function is to allow type hinting for custom types and function signatures. Without annotate you could only do matches(someVar, "function"). With annotate you can do matches(someVar, "function(string, ?int)|function(string)") and only accept functions that take a string and a nullable integer or functions that only accept a string.

like image 126
Sean Vieira Avatar answered Nov 20 '22 00:11

Sean Vieira