|
1 |
| -/* |
2 |
| - * Copyright 2013 The Polymer Authors. All rights reserved. |
3 |
| - * Use of this source code is governed by a BSD-style |
4 |
| - * license that can be found in the LICENSE file. |
5 |
| - */ |
6 |
| - (function(scope) { |
7 |
| - // super |
8 |
| - |
9 |
| - // `arrayOfArgs` is an optional array of args like one might pass |
10 |
| - // to `Function.apply` |
11 |
| - |
12 |
| - // TODO(sjmiles): |
13 |
| - // $super must be installed on an instance or prototype chain |
14 |
| - // as `super`, and invoked via `this`, e.g. |
15 |
| - // `this.super();` |
16 |
| - |
17 |
| - // will not work if function objects are not unique, for example, |
18 |
| - // when using mixins. |
19 |
| - // The memoization strategy assumes each function exists on only one |
20 |
| - // prototype chain i.e. we use the function object for memoizing) |
21 |
| - // perhaps we can bookkeep on the prototype itself instead |
22 |
| - function $super(arrayOfArgs) { |
23 |
| - // since we are thunking a method call, performance is important here: |
24 |
| - // memoize all lookups, once memoized the fast path calls no other |
25 |
| - // functions |
26 |
| - // |
27 |
| - // find the caller (cannot be `strict` because of 'caller') |
28 |
| - var caller = $super.caller; |
29 |
| - // memoized 'name of method' |
30 |
| - var nom = caller.nom; |
31 |
| - // memoized next implementation prototype |
32 |
| - var _super = caller._super; |
33 |
| - if (!_super) { |
34 |
| - if (!nom) { |
35 |
| - nom = caller.nom = nameInThis.call(this, caller); |
36 |
| - } |
37 |
| - if (!nom) { |
38 |
| - console.warn('called super() on a method not installed declaratively (has no .nom property)'); |
39 |
| - } |
40 |
| - // super prototype is either cached or we have to find it |
41 |
| - // by searching __proto__ (at the 'top') |
42 |
| - _super = memoizeSuper(caller, nom, getPrototypeOf(this)); |
43 |
| - } |
44 |
| - if (!_super) { |
45 |
| - // if _super is falsey, there is no super implementation |
46 |
| - //console.warn('called $super(' + nom + ') where there is no super implementation'); |
47 |
| - } else { |
48 |
| - // our super function |
49 |
| - var fn = _super[nom]; |
50 |
| - // memoize information so 'fn' can call 'super' |
51 |
| - if (!fn._super) { |
52 |
| - memoizeSuper(fn, nom, _super); |
53 |
| - } |
54 |
| - // invoke the inherited method |
55 |
| - // if 'fn' is not function valued, this will throw |
56 |
| - return fn.apply(this, arrayOfArgs || []); |
57 |
| - } |
58 |
| - } |
59 |
| - |
60 |
| - function nextSuper(proto, name, caller) { |
61 |
| - // look for an inherited prototype that implements name |
62 |
| - while (proto) { |
63 |
| - if ((proto[name] !== caller) && proto[name]) { |
64 |
| - return proto; |
65 |
| - } |
66 |
| - proto = getPrototypeOf(proto); |
67 |
| - } |
68 |
| - } |
69 |
| - |
70 |
| - function memoizeSuper(method, name, proto) { |
71 |
| - // find and cache next prototype containing `name` |
72 |
| - // we need the prototype so we can do another lookup |
73 |
| - // from here |
74 |
| - method._super = nextSuper(proto, name, method); |
75 |
| - if (method._super) { |
76 |
| - // _super is a prototype, the actual method is _super[name] |
77 |
| - // tag super method with it's name for further lookups |
78 |
| - method._super[name].nom = name; |
79 |
| - } |
80 |
| - return method._super; |
81 |
| - } |
82 |
| - |
83 |
| - function nameInThis(value) { |
84 |
| - var p = this.__proto__; |
85 |
| - while (p && p !== HTMLElement.prototype) { |
86 |
| - // TODO(sjmiles): getOwnPropertyNames is absurdly expensive |
87 |
| - var n$ = Object.getOwnPropertyNames(p); |
88 |
| - for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) { |
89 |
| - var d = Object.getOwnPropertyDescriptor(p, n); |
90 |
| - if (typeof d.value === 'function' && d.value === value) { |
91 |
| - return n; |
92 |
| - } |
93 |
| - } |
94 |
| - p = p.__proto__; |
95 |
| - } |
96 |
| - } |
97 |
| - |
98 |
| - // NOTE: In some platforms (IE10) the prototype chain is faked via |
99 |
| - // __proto__. Therefore, always get prototype via __proto__ instead of |
100 |
| - // the more standard Object.getPrototypeOf. |
101 |
| - function getPrototypeOf(prototype) { |
102 |
| - return prototype.__proto__; |
103 |
| - } |
104 |
| - |
105 |
| - // utility function to precompute name tags for functions |
106 |
| - // in a (unchained) prototype |
107 |
| - function hintSuper(prototype) { |
108 |
| - // tag functions with their prototype name to optimize |
109 |
| - // super call invocations |
110 |
| - for (var n in prototype) { |
111 |
| - var pd = Object.getOwnPropertyDescriptor(prototype, n); |
112 |
| - if (pd && typeof pd.value === 'function') { |
113 |
| - pd.value.nom = n; |
114 |
| - } |
115 |
| - } |
116 |
| - } |
117 |
| - |
118 |
| - // exports |
119 |
| - |
120 |
| - scope.super = $super; |
121 |
| - |
122 |
| -})(Polymer); |
| 1 | +/* |
| 2 | + * Copyright 2013 The Polymer Authors. All rights reserved. |
| 3 | + * Use of this source code is governed by a BSD-style |
| 4 | + * license that can be found in the LICENSE file. |
| 5 | + */ |
| 6 | + (function(scope) { |
| 7 | + // super |
| 8 | + |
| 9 | + // `arrayOfArgs` is an optional array of args like one might pass |
| 10 | + // to `Function.apply` |
| 11 | + |
| 12 | + // TODO(sjmiles): |
| 13 | + // $super must be installed on an instance or prototype chain |
| 14 | + // as `super`, and invoked via `this`, e.g. |
| 15 | + // `this.super();` |
| 16 | + |
| 17 | + // will not work if function objects are not unique, for example, |
| 18 | + // when using mixins. |
| 19 | + // The memoization strategy assumes each function exists on only one |
| 20 | + // prototype chain i.e. we use the function object for memoizing) |
| 21 | + // perhaps we can bookkeep on the prototype itself instead |
| 22 | + function $super(arrayOfArgs) { |
| 23 | + // since we are thunking a method call, performance is important here: |
| 24 | + // memoize all lookups, once memoized the fast path calls no other |
| 25 | + // functions |
| 26 | + // |
| 27 | + // find the caller (cannot be `strict` because of 'caller') |
| 28 | + var caller = $super.caller; |
| 29 | + // memoized 'name of method' |
| 30 | + var nom = caller.nom; |
| 31 | + // memoized next implementation prototype |
| 32 | + var _super = caller._super; |
| 33 | + if (!_super) { |
| 34 | + if (!nom) { |
| 35 | + nom = caller.nom = nameInThis.call(this, caller); |
| 36 | + } |
| 37 | + if (!nom) { |
| 38 | + console.warn('called super() on a method not installed declaratively (has no .nom property)'); |
| 39 | + } |
| 40 | + // super prototype is either cached or we have to find it |
| 41 | + // by searching __proto__ (at the 'top') |
| 42 | + // invariant: because we cache _super on fn below, we never reach |
| 43 | + // here from inside a series of calls to super(), so it's ok to |
| 44 | + // start searching from the prototype of 'this' (at the 'top') |
| 45 | + // we must never memoize a null super for this reason |
| 46 | + _super = memoizeSuper(caller, nom, getPrototypeOf(this)); |
| 47 | + } |
| 48 | + // our super function |
| 49 | + var fn = _super[nom]; |
| 50 | + if (fn) { |
| 51 | + // memoize information so 'fn' can call 'super' |
| 52 | + if (!fn._super) { |
| 53 | + // must not memoize null, or we lose our invariant above |
| 54 | + memoizeSuper(fn, nom, _super); |
| 55 | + } |
| 56 | + // invoke the inherited method |
| 57 | + // if 'fn' is not function valued, this will throw |
| 58 | + return fn.apply(this, arrayOfArgs || []); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + function nameInThis(value) { |
| 63 | + var p = this.__proto__; |
| 64 | + while (p && p !== HTMLElement.prototype) { |
| 65 | + // TODO(sjmiles): getOwnPropertyNames is absurdly expensive |
| 66 | + var n$ = Object.getOwnPropertyNames(p); |
| 67 | + for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) { |
| 68 | + var d = Object.getOwnPropertyDescriptor(p, n); |
| 69 | + if (typeof d.value === 'function' && d.value === value) { |
| 70 | + return n; |
| 71 | + } |
| 72 | + } |
| 73 | + p = p.__proto__; |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + function memoizeSuper(method, name, proto) { |
| 78 | + // find and cache next prototype containing `name` |
| 79 | + // we need the prototype so we can do another lookup |
| 80 | + // from here |
| 81 | + var s = nextSuper(proto, name, method); |
| 82 | + if (s[name]) { |
| 83 | + // `s` is a prototype, the actual method is `s[name]` |
| 84 | + // tag super method with it's name for quicker lookups |
| 85 | + s[name].nom = name; |
| 86 | + } |
| 87 | + return method._super = s; |
| 88 | + } |
| 89 | + |
| 90 | + function nextSuper(proto, name, caller) { |
| 91 | + // look for an inherited prototype that implements name |
| 92 | + while (proto) { |
| 93 | + if ((proto[name] !== caller) && proto[name]) { |
| 94 | + return proto; |
| 95 | + } |
| 96 | + proto = getPrototypeOf(proto); |
| 97 | + } |
| 98 | + // must not return null, or we lose our invariant above |
| 99 | + // in this case, a super() call was invoked where no superclass |
| 100 | + // method exists |
| 101 | + // TODO(sjmiles): thow an exception? |
| 102 | + return Object; |
| 103 | + } |
| 104 | + |
| 105 | + // NOTE: In some platforms (IE10) the prototype chain is faked via |
| 106 | + // __proto__. Therefore, always get prototype via __proto__ instead of |
| 107 | + // the more standard Object.getPrototypeOf. |
| 108 | + function getPrototypeOf(prototype) { |
| 109 | + return prototype.__proto__; |
| 110 | + } |
| 111 | + |
| 112 | + // utility function to precompute name tags for functions |
| 113 | + // in a (unchained) prototype |
| 114 | + function hintSuper(prototype) { |
| 115 | + // tag functions with their prototype name to optimize |
| 116 | + // super call invocations |
| 117 | + for (var n in prototype) { |
| 118 | + var pd = Object.getOwnPropertyDescriptor(prototype, n); |
| 119 | + if (pd && typeof pd.value === 'function') { |
| 120 | + pd.value.nom = n; |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + // exports |
| 126 | + |
| 127 | + scope.super = $super; |
| 128 | + |
| 129 | +})(Polymer); |
0 commit comments