好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

knockout.js的学习笔记2

knockout.js的学习笔记2

本节换一种方式解读,把我消化过的东西反刍出来可能这样大家容易理解些,knockout.js大量使用闭包,非常难读。

我们从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" )

这里包含两种observable,没有依赖的与有依赖的,有依赖的通过没有依赖的计算出来,因此叫做computed!

但不管怎么样,它们都是返回一个函数,我们通过如下代码就可以模拟它们了:

//注:这里会用到mass Framework的种子模块的API https://github.com/RubyLouvre/mass-Framework/blob/master/src/mass.js

  //observable的传参必须是基本类型

  var validValueType = $.oneObject( "Null,NaN,Undefined,Boolean,Number,String" );

$.observable = function (value){

      var v = value; //将上一次的传参保存到v中,ret与它构成闭包

      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]); //必须先执行一次

      return ret

  }

 

  $.computed = function (obj, scope){ //为一个惰性函数,会重写自身

      //computed是由多个$.observable组成

      var getter, 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" ){ //setter不一定存在的

                  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(); //必须先执行一次

      return ret;

  }

因此当我们执行new MyViewModel(),就会依次执行$.observable, $.observable, $.computed, $.computed中的参数的getter, getter再调用两个observable。

问题来了,当我们调用computed时,总会通知其依赖(即firstName ,lastName)进行更新,但firstName 发生改变时没有手段通知fullName 进行更新。ko把这逻辑写在dependencyDetection模块中。我简化如下:

$.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);

             }

         }

     };

})();

我们把它加入到 $.computed 与 $.observable中,再添加一个发布更新函数valueWillMutate

View Code

到这里viewModel中的每个域(firstName, lastName, fullName)只要存在依赖关系都能相互通知了。

 

 

标签:  knockoutjs

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于knockout.js的学习笔记2的详细内容...

  阅读:44次