@@ -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
@@ -175,11 +177,147 @@ var ES = {
175177 }
176178} ;
177179
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+
178185//
179186// Function
180187// ========
181188//
182189
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+ }
269+
270+ defineProperties ( FunctionPrototype , {
271+ // ES-5 15.3.4.3
272+ // http://es5.github.io/#x15.3.4.3
273+ // The apply() method calls a function with a given this value and arguments
274+ // provided as an array (or an array-like object).
275+ apply : function ( thisArg ) {
276+ var argsArray = arguments [ 1 ] ;
277+ if ( arguments . length > 1 ) {
278+ // IE9 (though fix not needed) has a problem here for some reason!!!
279+ // Pretty much any function here causes error `SCRIPT5007: Object expected`.
280+ var type = typeof argsArray ;
281+ if ( type !== 'undefined' && type !== 'object' && type !== 'function' ) {
282+ throw new TypeError ( 'Function.prototype.apply: Arguments list has wrong type' ) ;
283+ }
284+ }
285+ // If `this` is `Object#toString`, captured or modified.
286+ if ( this === to_string || this === Object . prototype . toString ) {
287+ return toStringTag ( thisArg ) ;
288+ }
289+ // All other applys.
290+ if ( arguments . length > 1 ) {
291+ // Boxed string access bug fix.
292+ if ( splitString && to_string . call ( thisArg ) === '[object String]' ) {
293+ // `str_split` is safe to use here, no known issue at present.
294+ argsArray = call . call ( str_split , argsArray , '' ) ;
295+ }
296+ // `array_slice` is safe to use here, no known issue at present.
297+ argsArray = call . call ( array_slice , argsArray ) ;
298+ } else {
299+ // `argsArray` was `undefined` (not present).
300+ argsArray = [ ] ;
301+ }
302+
303+ return apply . call ( this , thisArg , argsArray ) ;
304+ } ,
305+
306+ // ES-5 15.3.4.4
307+ // http://es5.github.io/#x15.3.4.4
308+ // The call() method calls a function with a given this value and arguments
309+ // provided individually.
310+ call : function ( thisArg ) {
311+ // If `this` is `Object#toString`, captured or modified.
312+ if ( this === to_string || this === Object . prototype . toString ) {
313+ return toStringTag ( thisArg ) ;
314+ }
315+ // All other calls.
316+ // `array_slice` is safe to use here, no known issue at present.
317+ return apply . call ( this , thisArg , call . call ( array_slice , arguments , 1 ) ) ;
318+ }
319+ } , shouldPatchCallApply ) ;
320+
183321// ES-5 15.3.4.5
184322// http://es5.github.com/#x15.3.4.5
185323
@@ -320,7 +458,7 @@ defineProperties(FunctionPrototype, {
320458} ) ;
321459
322460// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
323- // us it in defining shortcuts.
461+ // use it in defining shortcuts.
324462var owns = call . bind ( ObjectPrototype . hasOwnProperty ) ;
325463var toStr = call . bind ( ObjectPrototype . toString ) ;
326464var strSlice = call . bind ( StringPrototype . slice ) ;
@@ -371,11 +509,6 @@ defineProperties($Array, { isArray: isArray });
371509// http://es5.github.com/#x15.4.4.18
372510// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
373511
374- // Check failure of by-index access of string characters (IE < 9)
375- // and failure of `0 in boxedString` (Rhino)
376- var boxedString = $Object ( 'a' ) ;
377- var splitString = boxedString [ 0 ] !== 'a' || ! ( 0 in boxedString ) ;
378-
379512var properlyBoxesContext = function properlyBoxed ( method ) {
380513 // Check node 0.6.21 bug where third parameter is not boxed
381514 var properlyBoxesNonStrict = true ;
0 commit comments