@@ -297,7 +297,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
297
297
// - scope: bound scope
298
298
// - element: previous element.
299
299
// - index: position
300
- var lastBlockMap = { } ;
300
+ //
301
+ // We are using no-proto object so that we don't need to guard against inherited props via
302
+ // hasOwnProperty.
303
+ var lastBlockMap = createMap ( ) ;
301
304
302
305
//watch props
303
306
$scope . $watchCollection ( rhs , function ngRepeatAction ( collection ) {
@@ -306,7 +309,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
306
309
nextNode ,
307
310
// Same as lastBlockMap but it has the current state. It will become the
308
311
// lastBlockMap on the next iteration.
309
- nextBlockMap = { } ,
312
+ nextBlockMap = createMap ( ) ,
310
313
arrayLength ,
311
314
key , value , // key/value of iteration
312
315
trackById ,
@@ -343,39 +346,35 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
343
346
key = ( collection === collectionKeys ) ? index : collectionKeys [ index ] ;
344
347
value = collection [ key ] ;
345
348
trackById = trackByIdFn ( key , value , index ) ;
346
- assertNotHasOwnProperty ( trackById , '`track by` id' ) ;
347
- if ( lastBlockMap . hasOwnProperty ( trackById ) ) {
349
+ if ( lastBlockMap [ trackById ] ) {
350
+ // found previously seen block
348
351
block = lastBlockMap [ trackById ] ;
349
352
delete lastBlockMap [ trackById ] ;
350
353
nextBlockMap [ trackById ] = block ;
351
354
nextBlockOrder [ index ] = block ;
352
- } else if ( nextBlockMap . hasOwnProperty ( trackById ) ) {
353
- // restore lastBlockMap
355
+ } else if ( nextBlockMap [ trackById ] ) {
356
+ // id collision detected. restore lastBlockMap and throw an error
354
357
forEach ( nextBlockOrder , function ( block ) {
355
358
if ( block && block . scope ) lastBlockMap [ block . id ] = block ;
356
359
} ) ;
357
- // This is a duplicate and we need to throw an error
358
360
throw ngRepeatMinErr ( 'dupes' , "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}" ,
359
361
expression , trackById ) ;
360
362
} else {
361
363
// new never before seen block
362
364
nextBlockOrder [ index ] = { id : trackById , scope : undefined , clone : undefined } ;
363
- nextBlockMap [ trackById ] = false ;
365
+ nextBlockMap [ trackById ] = true ;
364
366
}
365
367
}
366
368
367
369
// remove existing items
368
370
for ( var blockKey in lastBlockMap ) {
369
- // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
370
- if ( lastBlockMap . hasOwnProperty ( blockKey ) ) {
371
- block = lastBlockMap [ blockKey ] ;
372
- elementsToRemove = getBlockNodes ( block . clone ) ;
373
- $animate . leave ( elementsToRemove ) ;
374
- forEach ( elementsToRemove , function ( element ) {
375
- element [ NG_REMOVED ] = true ;
376
- } ) ;
377
- block . scope . $destroy ( ) ;
378
- }
371
+ block = lastBlockMap [ blockKey ] ;
372
+ elementsToRemove = getBlockNodes ( block . clone ) ;
373
+ $animate . leave ( elementsToRemove ) ;
374
+ forEach ( elementsToRemove , function ( element ) {
375
+ element [ NG_REMOVED ] = true ;
376
+ } ) ;
377
+ block . scope . $destroy ( ) ;
379
378
}
380
379
381
380
// we are not using forEach for perf reasons (trying to avoid #call)
0 commit comments