From d2f8e472a57da35202a1b0bff142641b2057a32f Mon Sep 17 00:00:00 2001 From: Jacob Wright Date: Thu, 8 Feb 2018 21:04:29 -0700 Subject: [PATCH] Add support to computed and store for immutable structures Adds optional performance support for apps using an immutable data structure such as redux. Adds the `immutable` boolean option for compile and an `immutable` option to store as well. When these options are used, computed will not recompute if the object has not changed. If your data structure is not immutable you should not use this as svelte cannot know if a mutation was made on objects. This PR also adds support for Dates and NaN values so computed properties will not recompute if a date has not changed or a value did not change from NaN. This closes out these issues: * https://github.com/sveltejs/svelte/issues/1146 * https://github.com/sveltejs/svelte/issues/1161 This is my first PR for Svelte. Any feedback would be appreciated! --- src/generators/dom/index.ts | 1 + src/interfaces.ts | 1 + src/shared/index.js | 41 ++++++++++++++++++- store.js | 8 ++-- .../expected-bundle.js | 9 +++- .../component-static/expected-bundle.js | 9 +++- .../computed-collapsed-if/expected-bundle.js | 9 +++- .../css-media-query/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../deconflict-globals/expected-bundle.js | 9 +++- .../samples/do-use-dataset/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../event-handlers-custom/expected-bundle.js | 9 +++- .../head-no-whitespace/expected-bundle.js | 9 +++- .../if-block-no-update/expected-bundle.js | 9 +++- .../if-block-simple/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../inline-style-optimized/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../legacy-input-type/expected-bundle.js | 9 +++- .../legacy-quote-class/expected-bundle.js | 9 +++- .../samples/media-bindings/expected-bundle.js | 9 +++- .../non-imported-component/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../samples/setup-method/expected-bundle.js | 9 +++- test/js/samples/svg-title/expected-bundle.js | 9 +++- test/js/samples/title/expected-bundle.js | 9 +++- .../expected-bundle.js | 9 +++- .../window-binding-scroll/expected-bundle.js | 9 +++- 33 files changed, 279 insertions(+), 33 deletions(-) diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 776cf1ab0bb6..e103f428cf24 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -375,6 +375,7 @@ export default function dom( if (sigil === '@') { if (name in shared) { if (options.dev && `${name}Dev` in shared) name = `${name}Dev`; + else if (options.immutable && `${name}Immutable` in shared) name = `${name}Immutable`; usedHelpers.add(name); } diff --git a/src/interfaces.ts b/src/interfaces.ts index 9773d330d394..82de8cd04737 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -52,6 +52,7 @@ export interface CompileOptions { cssOutputFilename?: string; dev?: boolean; + immutable?: boolean; shared?: boolean | string; cascade?: boolean; hydratable?: boolean; diff --git a/src/shared/index.js b/src/shared/index.js index ef160ebf0779..ec8706be6d1b 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -26,7 +26,25 @@ export function destroyDev(detach) { } export function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; +} + +export function differsImmutable(a, b) { + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b; } export function dispatchObservers(component, group, changed, newState, oldState) { @@ -165,6 +183,27 @@ export function _set(newState) { } } +export function _setImmutable(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (differsImmutable(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign({}, oldState, newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } +} + export function setDev(newState) { if (typeof newState !== 'object') { throw new Error( diff --git a/store.js b/store.js index f31c659080a3..853d36a52a9b 100644 --- a/store.js +++ b/store.js @@ -2,12 +2,13 @@ import { assign, blankObject, differs, + differsImmutable, dispatchObservers, get, observe } from './shared.js'; -function Store(state) { +function Store(state, options) { this._observers = { pre: blankObject(), post: blankObject() }; this._changeHandlers = []; this._dependents = []; @@ -16,6 +17,7 @@ function Store(state) { this._sortedComputedProperties = []; this._state = assign({}, state); + this._differs = options && options.immutable ? differsImmutable : differs; } assign(Store.prototype, { @@ -88,7 +90,7 @@ assign(Store.prototype, { if (dirty) { var newValue = fn.apply(null, values); - if (differs(newValue, value)) { + if (store._differs(newValue, value)) { value = newValue; changed[key] = true; state[key] = value; @@ -124,7 +126,7 @@ assign(Store.prototype, { for (var key in newState) { if (this._computed[key]) throw new Error("'" + key + "' is a read-only property"); - if (differs(newState[key], oldState[key])) changed[key] = dirty = true; + if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true; } if (!dirty) return; diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 59cd2de1256b..ffc75c872ce7 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -52,7 +52,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/component-static/expected-bundle.js b/test/js/samples/component-static/expected-bundle.js index 708ef5be95ac..970b8e139a71 100644 --- a/test/js/samples/component-static/expected-bundle.js +++ b/test/js/samples/component-static/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index b39f95a77b71..e9285f3bc068 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/css-media-query/expected-bundle.js b/test/js/samples/css-media-query/expected-bundle.js index 91662053a4f1..6ccc9200d57c 100644 --- a/test/js/samples/css-media-query/expected-bundle.js +++ b/test/js/samples/css-media-query/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js index 03e5cef1e24b..4948afea4d55 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js @@ -40,7 +40,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/deconflict-globals/expected-bundle.js b/test/js/samples/deconflict-globals/expected-bundle.js index ba22542c4b49..6733b68767f3 100644 --- a/test/js/samples/deconflict-globals/expected-bundle.js +++ b/test/js/samples/deconflict-globals/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/do-use-dataset/expected-bundle.js b/test/js/samples/do-use-dataset/expected-bundle.js index 2079e6607c98..442afd002e47 100644 --- a/test/js/samples/do-use-dataset/expected-bundle.js +++ b/test/js/samples/do-use-dataset/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js index efcfcc8f30c6..3b5681f2ca06 100644 --- a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js index cf43bbd1300d..242ac5182875 100644 --- a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index e35826e354d9..ca09f3774ff3 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -60,7 +60,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 43db3035a350..f9e32a02565a 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -40,7 +40,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/head-no-whitespace/expected-bundle.js b/test/js/samples/head-no-whitespace/expected-bundle.js index 91f894bc301c..62aac217d514 100644 --- a/test/js/samples/head-no-whitespace/expected-bundle.js +++ b/test/js/samples/head-no-whitespace/expected-bundle.js @@ -40,7 +40,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/if-block-no-update/expected-bundle.js b/test/js/samples/if-block-no-update/expected-bundle.js index b309a25e9698..681edc072ec8 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index 5084639f4b9b..9ce6331f4485 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js index 753d61db71c4..9077eea9d795 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/inline-style-optimized-url/expected-bundle.js b/test/js/samples/inline-style-optimized-url/expected-bundle.js index cf360881b1bd..7277ff587a23 100644 --- a/test/js/samples/inline-style-optimized-url/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-url/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/inline-style-optimized/expected-bundle.js b/test/js/samples/inline-style-optimized/expected-bundle.js index 38024df4ff8c..9b3f41768f04 100644 --- a/test/js/samples/inline-style-optimized/expected-bundle.js +++ b/test/js/samples/inline-style-optimized/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/inline-style-unoptimized/expected-bundle.js b/test/js/samples/inline-style-unoptimized/expected-bundle.js index 320c733a43dc..f1a5a53d7f29 100644 --- a/test/js/samples/inline-style-unoptimized/expected-bundle.js +++ b/test/js/samples/inline-style-unoptimized/expected-bundle.js @@ -44,7 +44,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/input-without-blowback-guard/expected-bundle.js b/test/js/samples/input-without-blowback-guard/expected-bundle.js index eacaca85a623..b32377763e01 100644 --- a/test/js/samples/input-without-blowback-guard/expected-bundle.js +++ b/test/js/samples/input-without-blowback-guard/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/legacy-input-type/expected-bundle.js b/test/js/samples/legacy-input-type/expected-bundle.js index 7b730f08d921..1dbd32f6194a 100644 --- a/test/js/samples/legacy-input-type/expected-bundle.js +++ b/test/js/samples/legacy-input-type/expected-bundle.js @@ -46,7 +46,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/legacy-quote-class/expected-bundle.js b/test/js/samples/legacy-quote-class/expected-bundle.js index 499a82c46e4e..0b203fb4b65d 100644 --- a/test/js/samples/legacy-quote-class/expected-bundle.js +++ b/test/js/samples/legacy-quote-class/expected-bundle.js @@ -63,7 +63,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/media-bindings/expected-bundle.js b/test/js/samples/media-bindings/expected-bundle.js index bbd56d81237b..ec971167be53 100644 --- a/test/js/samples/media-bindings/expected-bundle.js +++ b/test/js/samples/media-bindings/expected-bundle.js @@ -56,7 +56,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index f8e0722db702..46de1d757ed6 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -42,7 +42,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index e53dd0de5e91..b65e0bfc2a47 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/setup-method/expected-bundle.js b/test/js/samples/setup-method/expected-bundle.js index 58ee3a67a03c..80bb84769218 100644 --- a/test/js/samples/setup-method/expected-bundle.js +++ b/test/js/samples/setup-method/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/svg-title/expected-bundle.js b/test/js/samples/svg-title/expected-bundle.js index 12f06bcf9226..1ee4d64a4841 100644 --- a/test/js/samples/svg-title/expected-bundle.js +++ b/test/js/samples/svg-title/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/title/expected-bundle.js b/test/js/samples/title/expected-bundle.js index 6eb3471b5b2e..454a1fad0e23 100644 --- a/test/js/samples/title/expected-bundle.js +++ b/test/js/samples/title/expected-bundle.js @@ -28,7 +28,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index e2ee1e61fba2..9ac57fe2156f 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -52,7 +52,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) { diff --git a/test/js/samples/window-binding-scroll/expected-bundle.js b/test/js/samples/window-binding-scroll/expected-bundle.js index a8a932c8b7cf..457f6d55ea37 100644 --- a/test/js/samples/window-binding-scroll/expected-bundle.js +++ b/test/js/samples/window-binding-scroll/expected-bundle.js @@ -48,7 +48,14 @@ function destroy(detach) { } function differs(a, b) { - return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + if (a == null || b == null) return a !== b; + if (a.constructor !== b.constructor) return true; + if (a.valueOf && b.valueOf) { + a = a.valueOf(); + b = b.valueOf(); + } + if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false; + return a !== b || typeof a === 'object' || typeof a === 'function'; } function dispatchObservers(component, group, changed, newState, oldState) {