Knockout. js study Note 2

Source: Internet
Author: User

This section is another way to interpret it. It may be easier for everyone to understand the things I have digested. Knockout. js uses a lot of closures, which is very difficult to read.

We can see from viewmodel:

          function MyViewModel() {                this.firstName = $.observable('Planet');                this.lastName = $.observable('Earth');                this.fullName = $.computed({                    getter: function () {                        return this.firstName() + " " + this.lastName();                    },                    setter: function (value) {                        var lastSpacePos = value.lastIndexOf(" ");                        if (lastSpacePos > 0) { // Ignore values with no space character                            this.firstName(value.substring(0, lastSpacePos)); // Update "firstName"                            this.lastName(value.substring(lastSpacePos + 1)); // Update "lastName"                        }                    },                    scope: this                });            }            var a = new MyViewModel();            a.fullName("xxx yyy")

There are two types of observable, which are independent from each other. Computed is called computed!

However, they all return a function. We can simulate them using the following code:

// Note: here we will use the mass framework seed module of the API https://github.com/RubyLouvre/mass-Framework/blob/master/src/mass.js // observable parameter passing must be the basic type var validvaluetype =$. oneobject ("null, Nan, undefined, Boolean, number, string"); $. observable = function (value) {var v = value; // save the last pass to the value of V. RET and it form the closure function RET (NEO) {If (arguments. length) {// setter if (! Validvaluetype [$. Type (NEO)]) {$. Error ("arguments must be primitive type! ") Return ret} If (V! = Neo) {v = NEO;} return ret;} else {// getter return V;} value = validvaluetype [$. Type (value)]? Value: void 0; RET (arguments [0]); // you must first run return ret} $. computed = function (OBJ, scope) {// is an inert function and will overwrite itself. // computed is composed of multiple $. the observable component is Var getter, and setter if (typeof OBJ = "function") {getter = OBJ} else if (OBJ & typeof OBJ = "object") {getter = obj. getter; setter = obj. setter; Scope = obj. scope;} var v var ret = function (NEO) {If (arguments. length) {If (typeof setter = "function") {// The setter is not necessarily stored. If (! Validvaluetype [$. Type (NEO)]) {$. Error ("arguments must be primitive type! ") Return ret} If (V! = Neo) {setter. call (scope, Neo); V = NEO;} return ret;} else {v = getter. call (scope); Return v ;}} RET (); // you must first execute return ret ;}

Therefore, when we execute new myviewmodel (), we will execute $. observable, $. observable, $. computed, $. Computed's parameter getter, and getter will call two more observable.

The problem arises. When computed is called, the dependency (firstname, lastname) is always notified for update, but the fullname is not notified for update when the firstname changes. Ko writes the logic in the dependencydetection module. I simplified it as follows:

            $.dependencyDetection = (function () {                var _frames = [];                return {                    begin: function (ret) {                        _frames.push(ret);                    },                    end: function () {                        _frames.pop();                    },                    collect: function (self) {                        if (_frames.length > 0) {                            if(!self.list)                                self.list = [];                            var fn = _frames[_frames.length - 1];                            if ( self.list.indexOf( fn ) >= 0)                                return;                            self.list.push(fn);                        }                    }                };            })();

Add it to $. computed and $. observable, and then add a publishing update function valuewillmutate.

VaR validvaluetype =$. oneobject ("null, Nan, undefined, Boolean, number, string") $. dependencydetection = (function () {VaR _ frames = []; return {begin: function (RET) {_ frames. push (RET) ;}, end: function () {_ frames. pop () ;}, collect: function (Self) {If (_ frames. length> 0) {If (! Self. list) self. list = []; var fn = _ frames [_ frames. length-1]; If (self. list. indexof (FN)> = 0) return; self. list. push (FN) ;}};}) (); $. valuewillmutate = function (observable) {var list = observable. list if ($. type (list, "array") {for (VAR I = 0, El; El = list [I ++];) {El () ;}}$. observable = function (value) {var v = value; // save the last pass to the value of V. RET and it form the closure function RET (NEO) {If (arguments. length) {// se Tter if (! Validvaluetype [$. Type (NEO)]) {$. Error ("arguments must be primitive type! ") Return ret} If (V! = Neo) {v = NEO; $. valuewillmutate (RET); // send a notification to the dependent party} return ret;} else {// getter $. dependencydetection. collect (RET); // collect return V;} value = validvaluetype [$. type (value)]? Value: void 0; RET (arguments [0]); // you must first run return ret} $. computed = function (OBJ, scope) {// is an inert function and will overwrite itself. // computed is composed of multiple $. the observable component is Var getter, and setter if (typeof OBJ = "function") {getter = OBJ} else if (OBJ & typeof OBJ = "object") {getter = obj. getter; setter = obj. setter; Scope = obj. scope;} var v var ret = function (NEO) {If (arguments. length) {If (typeof setter = "function") {// The setter is not necessarily stored. If (! Validvaluetype [$. Type (NEO)]) {$. Error ("arguments must be primitive type! ") Return ret} If (V! = Neo) {setter. call (scope, Neo); V = NEO;} return ret;} else {$. dependencydetection. begin (RET); // Let the dependency know its existence v = getter. call (scope); $. dependencydetection. end (); Return v ;}} RET (); // you must first execute return ret;} function myviewmodel () {This. firstname = $. observable ('Planet '); this. lastname = $. observable ('global'); this. fullname = $. computed ({getter: function () {return this. firstname () + "" + this. lastname () ;}, setter: function (value) {var lastspacepos = value. lastindexof (""); If (lastspacepos> 0) {// ignore values with no space character this. firstname (value. substring (0, lastspacepos); // Update "firstname" this. lastname (value. substring (lastspacepos + 1); // Update "lastname" }}, scope: This}); this. card = $. computed (function () {return this. fullname () + ""}, this)} var A = new myviewmodel (); // =============== test code ===============$. log (. firstname () // planet $. log (. lastname () // Earth $. log (. fullname () // planet Earth is calculated using the above two methods. fullname ("xxx yyy"); // The firstname and lastname will be automatically updated when fullname is updated. log (. firstname () // XXX $. log (. lastname () // yyy. firstname ("ooo"); // when firstname is updated, fullname $ is automatically updated. log (. fullname () // ooo yyy $. log (. card () // ooo yyy silk

Every field (firstname, lastname, fullname) in viewmodel can be notified to each other as long as there is dependency.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.