Skip to content

Commit 4456e7e

Browse files
atscottmatsko
authored andcommitted
refactor(core): remove looseIdentical in favor of built-in Object.is (angular#37191)
Remove `looseIdentical` implementation and instead use the ES2015 `Object.is` in its place. They behave exactly the same way except for `+0`/`-0`. `looseIdentical(+0, -0)` => `true` `Object.is(+0, -0)` => `false` Other than the difference noted above, this is not be a breaking change because: 1. `looseIdentical` is a private API 2. ES2015 is listed as a mandatory polyfill in the [browser support guide](https://angular.io/guide/browser-support#mandatory-polyfills) 3. Also note that `Ivy` already uses `Object.is` in `bindingUpdated`. PR Close angular#37191
1 parent 92c436d commit 4456e7e

File tree

12 files changed

+20
-35
lines changed

12 files changed

+20
-35
lines changed

packages/core/src/change_detection/change_detection_util.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {looseIdentical} from '../util/comparison';
109
import {getSymbolIterator} from '../util/symbol';
1110

1211
export function devModeEqual(a: any, b: any): boolean {
@@ -20,7 +19,7 @@ export function devModeEqual(a: any, b: any): boolean {
2019
if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
2120
return true;
2221
} else {
23-
return looseIdentical(a, b);
22+
return Object.is(a, b);
2423
}
2524
}
2625
}

packages/core/src/change_detection/differs/default_iterable_differ.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {looseIdentical} from '../../util/comparison';
109
import {stringify} from '../../util/stringify';
1110
import {isListLikeIterable, iterateListLike} from '../change_detection_util';
1211

@@ -180,15 +179,15 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
180179
for (let index = 0; index < this.length; index++) {
181180
item = collection[index];
182181
itemTrackBy = this._trackByFn(index, item);
183-
if (record === null || !looseIdentical(record.trackById, itemTrackBy)) {
182+
if (record === null || !Object.is(record.trackById, itemTrackBy)) {
184183
record = this._mismatch(record, item, itemTrackBy, index);
185184
mayBeDirty = true;
186185
} else {
187186
if (mayBeDirty) {
188187
// TODO(misko): can we limit this to duplicates only?
189188
record = this._verifyReinsertion(record, item, itemTrackBy, index);
190189
}
191-
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
190+
if (!Object.is(record.item, item)) this._addIdentityChange(record, item);
192191
}
193192

194193
record = record._next;
@@ -197,15 +196,15 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
197196
index = 0;
198197
iterateListLike(collection, (item: V) => {
199198
itemTrackBy = this._trackByFn(index, item);
200-
if (record === null || !looseIdentical(record.trackById, itemTrackBy)) {
199+
if (record === null || !Object.is(record.trackById, itemTrackBy)) {
201200
record = this._mismatch(record, item, itemTrackBy, index);
202201
mayBeDirty = true;
203202
} else {
204203
if (mayBeDirty) {
205204
// TODO(misko): can we limit this to duplicates only?
206205
record = this._verifyReinsertion(record, item, itemTrackBy, index);
207206
}
208-
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
207+
if (!Object.is(record.item, item)) this._addIdentityChange(record, item);
209208
}
210209
record = record._next;
211210
index++;
@@ -289,7 +288,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
289288
if (record !== null) {
290289
// We have seen this before, we need to move it forward in the collection.
291290
// But first we need to check if identity changed, so we can update in view if necessary
292-
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
291+
if (!Object.is(record.item, item)) this._addIdentityChange(record, item);
293292

294293
this._moveAfter(record, previousRecord, index);
295294
} else {
@@ -298,7 +297,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
298297
if (record !== null) {
299298
// It is an item which we have evicted earlier: reinsert it back into the list.
300299
// But first we need to check if identity changed, so we can update in view if necessary
301-
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
300+
if (!Object.is(record.item, item)) this._addIdentityChange(record, item);
302301

303302
this._reinsertAfter(record, previousRecord, index);
304303
} else {
@@ -628,7 +627,7 @@ class _DuplicateItemRecordList<V> {
628627
let record: IterableChangeRecord_<V>|null;
629628
for (record = this._head; record !== null; record = record._nextDup) {
630629
if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex!) &&
631-
looseIdentical(record.trackById, trackById)) {
630+
Object.is(record.trackById, trackById)) {
632631
return record;
633632
}
634633
}

packages/core/src/change_detection/differs/default_keyvalue_differ.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {looseIdentical} from '../../util/comparison';
109
import {stringify} from '../../util/stringify';
1110
import {isJsObject} from '../change_detection_util';
1211
import {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory} from './keyvalue_differs';
@@ -229,7 +228,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
229228

230229
// Add the record or a given key to the list of changes only when the value has actually changed
231230
private _maybeAddToChanges(record: KeyValueChangeRecord_<K, V>, newValue: any): void {
232-
if (!looseIdentical(newValue, record.currentValue)) {
231+
if (!Object.is(newValue, record.currentValue)) {
233232
record.previousValue = record.currentValue;
234233
record.currentValue = newValue;
235234
this._addToChanges(record);

packages/core/src/core_private_export.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn}
2727
export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, BypassType as ɵBypassType, getSanitizationBypassType as ɵgetSanitizationBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass';
2828
export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer';
2929
export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer';
30-
export {looseIdentical as ɵlooseIdentical,} from './util/comparison';
3130
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
3231
export {global as ɵglobal} from './util/global';
3332
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';

packages/core/src/util/comparison.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@
88

99
import {areIterablesEqual, isListLikeIterable} from './iterable';
1010

11-
12-
// JS has NaN !== NaN
13-
export function looseIdentical(a: any, b: any): boolean {
14-
return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b);
15-
}
16-
1711
export function devModeEqual(a: any, b: any): boolean {
1812
const isListLikeIterableA = isListLikeIterable(a);
1913
const isListLikeIterableB = isListLikeIterable(b);
@@ -25,7 +19,7 @@ export function devModeEqual(a: any, b: any): boolean {
2519
if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) {
2620
return true;
2721
} else {
28-
return looseIdentical(a, b);
22+
return Object.is(a, b);
2923
}
3024
}
3125
}

packages/core/src/view/util.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {devModeEqual, WrappedValue} from '../change_detection/change_detection';
1010
import {SOURCE} from '../di/injector_compatibility';
1111
import {ViewEncapsulation} from '../metadata/view';
1212
import {RendererType2} from '../render/api';
13-
import {looseIdentical} from '../util/comparison';
1413
import {stringify} from '../util/stringify';
1514

1615
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
@@ -81,7 +80,7 @@ export function checkBinding(
8180
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
8281
const oldValues = view.oldValues;
8382
if ((view.state & ViewState.FirstCheck) ||
84-
!looseIdentical(oldValues[def.bindingIndex + bindingIdx], value)) {
83+
!Object.is(oldValues[def.bindingIndex + bindingIdx], value)) {
8584
return true;
8685
}
8786
return false;

packages/core/test/bundling/todo/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -941,9 +941,6 @@
941941
{
942942
"name": "locateHostElement"
943943
},
944-
{
945-
"name": "looseIdentical"
946-
},
947944
{
948945
"name": "makeMetadataCtor"
949946
},

packages/core/test/change_detection/util.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import {IterableChangeRecord, IterableChanges} from '@angular/core/src/change_detection/differs/iterable_differs';
1010
import {KeyValueChangeRecord, KeyValueChanges} from '@angular/core/src/change_detection/differs/keyvalue_differs';
1111

12-
import {looseIdentical} from '../../src/util/comparison';
1312
import {stringify} from '../../src/util/stringify';
1413

1514
export function iterableDifferToString<V>(iterableChanges: IterableChanges<V>) {
@@ -64,7 +63,7 @@ export function iterableChangesAsString({
6463
}
6564

6665
function kvcrAsString(kvcr: KeyValueChangeRecord<string, any>) {
67-
return looseIdentical(kvcr.previousValue, kvcr.currentValue) ?
66+
return Object.is(kvcr.previousValue, kvcr.currentValue) ?
6867
stringify(kvcr.key) :
6968
(stringify(kvcr.key) + '[' + stringify(kvcr.previousValue) + '->' +
7069
stringify(kvcr.currentValue) + ']');

packages/forms/src/directives/select_control_value_accessor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core';
9+
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider} from '@angular/core';
1010

1111
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
1212

@@ -121,7 +121,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
121121
this._compareWith = fn;
122122
}
123123

124-
private _compareWith: (o1: any, o2: any) => boolean = looseIdentical;
124+
private _compareWith: (o1: any, o2: any) => boolean = Object.is;
125125

126126
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
127127

packages/forms/src/directives/select_multiple_control_value_accessor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core';
9+
import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider} from '@angular/core';
1010

1111
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
1212

@@ -118,7 +118,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
118118
this._compareWith = fn;
119119
}
120120

121-
private _compareWith: (o1: any, o2: any) => boolean = looseIdentical;
121+
private _compareWith: (o1: any, o2: any) => boolean = Object.is;
122122

123123
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
124124

0 commit comments

Comments
 (0)