@@ -55,7 +55,9 @@ var array_splice = ArrayPrototype.splice;
5555var array_push = ArrayPrototype . push ;
5656var array_unshift = ArrayPrototype . unshift ;
5757var array_concat = ArrayPrototype . concat ;
58+ var str_split = StringPrototype . split ;
5859var call = FunctionPrototype . call ;
60+ var apply = FunctionPrototype . apply ;
5961var max = Math . max ;
6062var min = Math . min ;
6163
@@ -163,7 +165,6 @@ var ES = {
163165 // http://es5.github.com/#x9.9
164166 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */
165167 ToObject : function ( o ) {
166- /* jshint eqnull: true */
167168 if ( o == null ) { // this matches both null and undefined
168169 throw new TypeError ( "can't convert " + o + ' to object' ) ;
169170 }
@@ -176,11 +177,160 @@ var ES = {
176177 }
177178} ;
178179
180+ // Check failure of by-index access of string characters (IE < 9)
181+ // and failure of `0 in boxedString` (Rhino)
182+ var boxedString = $Object ( 'a' ) ;
183+ var splitString = boxedString [ 0 ] !== 'a' || ! ( 0 in boxedString ) ;
184+
179185//
180186// Function
181187// ========
182188//
183189
190+ // Tests for inconsistent or buggy `[[Class]]` strings.
191+ /* eslint-disable no-useless-call */
192+ var hasToStringTagBasicBug = to_string . call ( ) !== '[object Undefined]' || to_string . call ( null ) !== '[object Null]' ;
193+ /* eslint-enable no-useless-call */
194+ var hasToStringTagLegacyArguments = to_string . call ( arguments ) !== '[object Arguments]' ;
195+ var hasToStringTagInconsistency = hasToStringTagBasicBug || hasToStringTagLegacyArguments ;
196+ // Others that could be fixed:
197+ // Older ES3 native functions like `alert` return `[object Object]`.
198+ // Inconsistent `[[Class]]` strings for `window` or `global`.
199+
200+ var hasApplyArrayLikeDeficiency = ( function ( ) {
201+ var arrayLike = { length : 4 , 0 : 1 , 2 : 4 , 3 : true } ;
202+ var expectedArray = [ 1 , undefined , 4 , true ] ;
203+ var actualArray ;
204+ try {
205+ actualArray = ( function ( ) {
206+ // `array_slice` is safe to use here, no known issue at present.
207+ return array_slice . apply ( arguments ) ;
208+ } . apply ( null , arrayLike ) ) ;
209+ } catch ( e ) {
210+ if ( to_string . call ( actualArray ) !== '[object Array]' || actualArray . length !== arrayLike . length ) {
211+ return true ;
212+ }
213+ while ( expectedArray . length ) {
214+ if ( actualArray . pop ( ) !== expectedArray . pop ( ) ) {
215+ return true ;
216+ }
217+ }
218+ }
219+ return false ;
220+ } ( ) ) ;
221+
222+ var shouldPatchCallApply = hasToStringTagInconsistency || hasApplyArrayLikeDeficiency ;
223+
224+ if ( shouldPatchCallApply ) {
225+ // Constant. ES3 maximum array length.
226+ var MAX_ARRAY_LENGTH = 4294967295 ;
227+ // To prevent recursion when `call` and `apply` are patched. Robustness.
228+ call . call = call ;
229+ call . apply = apply ;
230+ apply . call = call ;
231+ apply . apply = apply ;
232+ }
233+
234+ if ( hasToStringTagLegacyArguments ) {
235+ // This function is for use within `call` and `apply` only.
236+ // To avoid any possibility of `call` recursion we use original `hasOwnProperty`.
237+ var isDuckTypeArguments = ( function ( hasOwnProperty ) {
238+ return function ( value ) {
239+ if ( value != null ) { // Checks `null` or `undefined`.
240+ if ( typeof value === 'object' && call . call ( hasOwnProperty , value , 'length' ) ) {
241+ var length = value . length ;
242+ if ( length > - 1 && length % 1 === 0 && length <= MAX_ARRAY_LENGTH ) {
243+ return ! call . call ( hasOwnProperty , value , 'arguments' ) && call . call ( hasOwnProperty , value , 'callee' ) ;
244+ }
245+ }
246+ }
247+ return false ;
248+ } ;
249+ } ( ObjectPrototype . hasOwnProperty ) ) ;
250+ }
251+
252+ if ( shouldPatchCallApply ) {
253+ // For use with `call` and `apply` fixes.
254+ var toStringTag = function ( value ) {
255+ // Add whatever fixes for getting `[[Class]]` strings here.
256+ if ( value === null ) {
257+ return '[object Null]' ;
258+ }
259+ if ( typeof value === 'undefined' ) {
260+ return '[object Undefined]' ;
261+ }
262+ if ( hasToStringTagLegacyArguments && isDuckTypeArguments ( value ) ) {
263+ return '[object Arguments]' ;
264+ }
265+ // `to_string` is safe to use here, no known issue at present.
266+ return call . call ( to_string , value ) ;
267+ } ;
268+ // For use with `apply` fix.
269+ var isArrayLikeObject = function ( value ) {
270+ if ( value != null ) { // Checks `null` or `undefined`.
271+ var type = typeof value ;
272+ // `to_string` is safe to use here, no known issue at present.
273+ if ( type === 'object' && type !== 'function' && call . call ( to_string , value ) !== '[object Function]' ) {
274+ var length = value . length ;
275+ if ( typeof length === 'number' ) {
276+ return length > - 1 && length % 1 === 0 && length <= MAX_ARRAY_LENGTH ;
277+ }
278+ }
279+ }
280+ return false ;
281+ } ;
282+ }
283+
284+ defineProperties ( FunctionPrototype , {
285+ // ES-5 15.3.4.3
286+ // http://es5.github.io/#x15.3.4.3
287+ // The apply() method calls a function with a given this value and arguments
288+ // provided as an array (or an array-like object).
289+ apply : function ( thisArg ) {
290+ var argsArray = arguments [ 1 ] ;
291+ if ( arguments . length > 1 ) {
292+ // IE9 (though fix not needed) has a problem here for some reason!!!
293+ // Pretty much any function here causes error `SCRIPT5007: Object expected`.
294+ if ( ! isArrayLikeObject ( argsArray ) ) {
295+ throw new TypeError ( 'Function.prototype.apply: Arguments list has wrong type' ) ;
296+ }
297+ }
298+ // If `this` is `Object#toString`, captured or modified.
299+ if ( this === to_string || this === Object . prototype . toString ) {
300+ return toStringTag ( thisArg ) ;
301+ }
302+ // All other applys.
303+ if ( arguments . length > 1 ) {
304+ // Boxed string access bug fix.
305+ if ( splitString && to_string . call ( thisArg ) === '[object String]' ) {
306+ // `str_split` is safe to use here, no known issue at present.
307+ argsArray = call . call ( str_split , argsArray , '' ) ;
308+ }
309+ // `array_slice` is safe to use here, no known issue at present.
310+ argsArray = call . call ( array_slice , argsArray ) ;
311+ } else {
312+ // `argsArray` was `undefined` (not present).
313+ argsArray = [ ] ;
314+ }
315+
316+ return apply . call ( this , thisArg , argsArray ) ;
317+ } ,
318+
319+ // ES-5 15.3.4.4
320+ // http://es5.github.io/#x15.3.4.4
321+ // The call() method calls a function with a given this value and arguments
322+ // provided individually.
323+ call : function ( thisArg ) {
324+ // If `this` is `Object#toString`, captured or modified.
325+ if ( this === to_string || this === Object . prototype . toString ) {
326+ return toStringTag ( thisArg ) ;
327+ }
328+ // All other calls.
329+ // `array_slice` is safe to use here, no known issue at present.
330+ return apply . call ( this , thisArg , call . call ( array_slice , arguments , 1 ) ) ;
331+ }
332+ } , shouldPatchCallApply ) ;
333+
184334// ES-5 15.3.4.5
185335// http://es5.github.com/#x15.3.4.5
186336
@@ -321,7 +471,7 @@ defineProperties(FunctionPrototype, {
321471} ) ;
322472
323473// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
324- // us it in defining shortcuts.
474+ // use it in defining shortcuts.
325475var owns = call . bind ( ObjectPrototype . hasOwnProperty ) ;
326476var toStr = call . bind ( ObjectPrototype . toString ) ;
327477var strSlice = call . bind ( StringPrototype . slice ) ;
@@ -372,11 +522,6 @@ defineProperties($Array, { isArray: isArray });
372522// http://es5.github.com/#x15.4.4.18
373523// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
374524
375- // Check failure of by-index access of string characters (IE < 9)
376- // and failure of `0 in boxedString` (Rhino)
377- var boxedString = $Object ( 'a' ) ;
378- var splitString = boxedString [ 0 ] !== 'a' || ! ( 0 in boxedString ) ;
379-
380525var properlyBoxesContext = function properlyBoxed ( method ) {
381526 // Check node 0.6.21 bug where third parameter is not boxed
382527 var properlyBoxesNonStrict = true ;
0 commit comments