# Overview of the Differences

TKO is a fundamental change in the foundation of the code behind Knockout, representing the reverse engineering, compartmentalization, and reintegration of the original code that dates back to 2010.

With this reengineering of Knockout into discrete pieces, it will be easier to update, build, and test the features of Knockout, as well as put the individual packages that make up Knockout to use in situations outside Knockout itself.

To see the differences, have a look at the [CHANGELOG.md](https://github.com/knockout/tko/blob/master/CHANGELOG.md).


# Version Comparison

| Version | tko.js  | Knockout 4 | Knockout 3.x |
| --- | --- | --- | --- |
| Browser compatibility |  Modern browsers (i.e. [`Proxy`](https://caniuse.com/#feat=proxy) support) | Internet Explorer 9+ |  Internet Explorer 6+  |
| `ko.BindingHandler`    | Yes  | Yes  | No  |
| `observableArray.length`   | Yes  | Browsers with [Array subclass](https://kangax.github.io/compat-table/es6/#test-Array_is_subclassable_length_property_(accessing)) support [More info](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#wrappers_prototype_chain_injection)  | No  |
| iterable `observableArray`   | Yes  | Browsers with [Symbol support](https://kangax.github.io/compat-table/es6/#test-Symbol)  | No  |
| event `throttle` / `debounce`   | Yes  | Yes  | No  |
| `ko.Component`   | Yes | Yes  | No  |
| `applyBindings` returns `Promise`   | Yes  | Yes  | No  |
| Polyfills included   | None  | Up to ES6  |  `Object.prototype.bind`  |
| `ko.proxy`   |  Yes  |  No  |  No  |
| `ko.onError` | Does not automatically throw (you need to add `throw error` to `ko.options.onError`) | Does not rethrow automatically | Always re-throws error |
| `foreach` binding | FastForEach | Template foreach | Template foreach |
| `each` binding    | FastForEach | FastForEach | Template foreach


# Build System

TKO has a complete build system rewrite and a conversion of the code from a concatenation of source files to discrete ES6 modules with `import` and `export` statements.  This process has been complex and taken years, with the result being a Knockout with a strong foundation of discrete reusable components.

Knockout 4 and TKO will be maintained at the new monorepo [knockout/tko](https://github.com/knockout/tko) on GitHub.  Knockout 3.x will continue to be maintained at [knockout/knockout](https://github.com/knockout/knockout).

TKO now uses standard tools like `lerna` and `yarn`, and employs [StandardJS](https://standardjs.com/) for code style — though all the old code is not yet updated to StandardJS yet.

# Test System

Knockout 3 used Jasmine 1 to perform tests.  Some packages in TKO continue to use Jasmine 1, while others now use Mocha.

## Backwards compatibility and 💥 breaking changes

We've strived to have backwards compatibility, and the numerous test cases we've run it through have been successful.  A key value of Knockout has been and remains the comprehensive test cases that enforce performance to a predictable standard, and TKO meets all the tests that were enforced on Knockout 3.x, notwithstanding a few issues:

- The `function` no longer works in `data-bind`, having been replaced by lambdas, so `data-bind='click: function () { x++ }'` will have to be replaced by e.g. `data-bind='click: => x++'`
- The `data-bind` is now interpreted by a LL compiler (based on [knockout-secure-binding](https://github.com/brianmhunt/knockout-secure-binding)), so some edge case parsing issues may crop up

## Browser support

Knockout 4 and TKO and the underlying packages will start support from IE9 forward.  We aim to test Knockout across all browsers from this point forward.

If you need IE6, 7, and 8 support you may prefer to keep using the Knockout 3.x line, or be prepared for workarounds or missing functionality.

# Options

* (options) Allow importing `ko` in node
* various new [`options`](https://github.com/knockout/tko.utils/blob/master/src/options.js)

# Utilities

* (utils) Several array utilities use native functions now (`arrayPushAll`, `arrayFilter`, `arrayGetDistinctValues`, `arrayFirst`, `arrayIndexOf`)
* The `throttle` and `debounce` utilities now pass arguments to the target functions
* utils
  * utils.domNodeDisposal is now exposed as domNodeDisposal
  * arguments to setHtml that are functions are called (not just observables)
  * cleanExternalData now exposed in domNodeDisposal.otherNodeCleanerFunctions

* error handling
  * onError no longer throws if overloaded; default function is to re-throw.
  * error is thrown when an extender is not found

# Life Cycles

* (internal) Add the ES6 LifeCycle class (see tko.lifecycle)

# Observables

* (observable) When supported, `observable.length` will now be undefined (was `0` before), and `observableArray.length` will now be the length of the wrapped array
* (observableArray) `observableArray` is now iterable (has a `Symbol.iterator` property)
* (subscribable) Add the `once`, `then`, `when`, `yet`, and `next` functions

# Components

* (components) Warn with custom-element names that cannot be used with custom elements re. #43 & knockout/knockout#1603
* (components) Add `ko.Component`, an abstract base class that simplifies the Component creation and registration API (see `tko.utils.component/src/ComponentABC.js`)
* (components) Add `getBindingHandler(key)` to use binding handlers local to a component

Components can control their binding handlers.

## ko.Component example

<p data-height="490" data-theme-id="dark" data-slug-hash="XzNONW" data-default-tab="js,result" data-user="Knockout" data-embed-version="2" data-pen-title="Commented ko.Component" data-editable="true" class="codepen">See the Pen <a href="https://codepen.io/team/Knockout/pen/XzNONW/">Commented ko.Component</a> by Knockout (<a href="https://codepen.io/Knockout">@Knockout</a>) on <a href="https://codepen.io">CodePen</a>.</p>

# Bindings

* (binding) `ko.applyBindings` now returns a Promise that resolves when bindings are completed

* (binding handlers) Add new-style ES6 Binding Handler class (see custom-bindings documentation and tko.bind/src/BindingHandler.js), descended from the LifeCycle class
* (bind) String errors on binding are now propagated

## Binding Handlers and ko.BindingHandler

In TKO, binding handlers can be either an `object`, a `function` or a descendant of `ko.BindingHandler`.  The following are all valid binding handlers:

```javascript
class NewHandler extends ko.BindingHandler {
    constructor ({$element, valueAccessor, allBindings, $context, onError}) {
        /*
          this.value is valueAccessor()
          this.value(x) is valueAccessor(x);
          if valueAccessor() is observable or a property, it will be set properly.
        */
    }

    get controlsDescendants () { return true|false }

    get bindingComplete () {
        /* overload where binding is asynchronous. See e.g. Component binding*/
    }
    static get allowVirtualElements () { return true|false }
}

handler_fn = (element, valueAccessor, allBindings, viewModel, bindingContext) => { /* ... */ }

the_knockout_3_way = {
    init (element, valueAccessor, allBindings, viewModel, bindingContext) {
        /* ... */
    },

    update (element, valueAccessor, allBindings, viewModel, bindingContext) {
        /* ... */
    },

    allowVirtualElements: true|false
}

// Virtual Elements may be permitted for a binding explicitly.
virtualElements.allowedBindings[handler_name] = true|false
```

Binding handlers can be registered in the following ways:

```javascript
// Globally, where NewHandler is a BindingHandler descendant.
NewHandler.registerAs('handler')

// Globally, for any handler type.
ko.bindingHandlers.set(handler_name: handler)

// Knockout 3.x style
ko.bindingHandlers[handler_name] = handler

// For a component
class Component {
    getBindingHandler(bindingKey) {
        if (bindingKey === handler_name) { return handler }
        // Alternatively:
        // return { bindingKey[bindingKey]: handler }[bindingKey]
    }
}
```

## Parsing

* (parser) Fix interpretation of unicode characters as identifiers / variables
* `==` and `===` use `===` for comparison (same for `!=` and `!==`); fuzzy equality ~== / ~!= for the evil twins
* Knockout 4 will work with a Content Security Policy that prohibits unsafe-eval.
  * add "naked" `=>` lambdas (even in legacy browsers e.g. `data-bind='click: => was_clicked(true)'`
  * inline functions are no longer supported (e.g. `data-bind='click: function (){...}'` will fail)
  * No longer uses `with` statements
  * No longer uses `eval`/`new Function`

## Namespacing

  * incorporate punches namespacing i.e. `data-bind='event.click: => thing(true)'` is equivalent to `data-bind='event: {click: => thing(true)}'`

## Attribute Interpolation


## Text Interpolation

* incorporate punches `{{ }}` and `{{{}}}` text and attribute interpolation


## Event
* (`event` binding) Add object-based event handler e.g. `event.click: { handler: fn, once: true, capture: true, bubble: false, passive: false}`.  Also, bubbling can be prevented with `event.click: {bubble: false }` re #32
* (`event` binding) Add `throttle` and `debounce` parameters

## With
* (with binding) Fix dependency count for function-arguments [knockout/knockout#2285]

## Attr
* (attr) Support namespaced attributes with `attr` binding #27

## Foreach

* Use tko.binding.foreach for the `foreach` binding (based on brianmhunt/knockout-fast-foreach)
* Add `each` as an alias of `foreach`
* Rewritten as O(1)
* (foreach binding) When using the `as` parameter, the `$data` remains unchanged (i.e. the context inside a `foreach` is no longer a "child" context, but an extension of the current context); this deprecates the `noContext` parameter
* (foreach binding) Expose the `conditional` on the `domData` for use by the `else` binding (when the array is empty, the `else` binding will be rendered)
* (foreach binding) Expose `$list` inside the foreach
* (foreach binding) Allow `noIndex` as a peer binding parameter (e.g. `foreach: items, noIndex: true`)
* (foreach) Preserve focus when items are deleted and re-added (i.e. moved) in the same animation frame.

## Template

* Make the `template` binding expose a conditional for else-binding
* support template literals (\`\`) in bindings (even in legacy browsers)
* add the `@` prefix operator that calls/unwrap functions (i.e. `obs()()` is the same as `@obs`)

## If / Else

* add `<!-- else -->` inside the `if` binding, and add an `else` binding (following the brianmhunt/knockout-else plugin)
* Add `else` binding
* Add `unless` binding

## Using

## Hidden

  * add `hidden` binding (knockout/knockut#2103)

## HTML

The HTML binding now works in virtual elements. Based on ko.punches.

## Filtering

Filters can be applied to modify values in bindings. Based on ko.punches.


# Deprecated

  - Template binding options are deprecated
  - expressionWriting (twoWayBinding)
  - ‘.’ in binding handler names
  - jsonExpressionRewriting (expressionRewriting)
  - form parsing
  - `bind` shim
  - ko.utils.parseJson
  - getFormFields
  - fieldsIncludedWithJsonPost
  - postJson
