AngularJS - 最佳实践:视图或函数调用的模型属性?

Nun*_*noM 7 javascript model-view-controller angularjs angularjs-directive

很长一段时间我一直想知道这个问题:在使用AngularJS时,我应该直接在视图上使用模型对象属性,还是可以使用函数来获取该属性值?

我一直在做一些小的家居项目的角度,和(特别是与只读指令或控制器上工作),我倾向于创建范围的功能来访问并在视图中显示的范围对象及其属性值,但性能明智的,是这是一个好方法吗?

这种方式似乎维护视图代码,因为如果由于某种原因,对象改变时(由于服务器实现或任何其他特定原因),我只需要改变指令的JS代码,而不是HTML更容易.这是一个例子:

//this goes inside directive's link function
scope.getPropertyX = function() {
    return scope.object.subobject.propX;
}
Run Code Online (Sandbox Code Playgroud)

在视图中我可以简单地做

<span>{{ getPropertyX() }}</span>
Run Code Online (Sandbox Code Playgroud)

代替

<span>{{ object.subobject.propX }}</span>
Run Code Online (Sandbox Code Playgroud)

在有时它涉及的HTML混乱中,它更难维护.另一种情况是使用范围函数来测试ng-if上的评估的属性值,而不是直接使用该测试表达式:

scope.testCondition = function() {
    return scope.obj.subobj.propX === 1 && scope.obj.subobj.propY === 2 && ...;
}
Run Code Online (Sandbox Code Playgroud)

那么,这种方法有利有弊吗?你能否就这个问题向我提供一些见解?它一直困扰着我最近,在一个沉重的应用可能会如何表现,例如当一个指令可以得到非常复杂的,而且最重要的是可以一个NG重复可能产生的情况下,几百或几千个内部使用.

谢谢

Jas*_*aat 8

我不认为为所有属性创建函数是个好主意.不仅会在每个摘要周期中进行更多的函数调用,以查看函数返回值是否已更改,但它对我来说实际上似乎不太可读和可维护.它可能会为您的控制器添加许多不必要的代码,并使您的控制器成为一个视图模型.你的第二个案例似乎非常好,复杂的操作似乎正是你希望你的控制器处理的.

至于性能,它根据我写的测试确实有所不同(小提琴,试图使用jsperf,但每次测试无法获得不同的设置).结果几乎快两倍,即使用属性为223,000个摘要/秒,而使用getter函数为120,000个摘要/秒.为使用角度的绑定创建手表$parse.

要考虑的一件事是继承.如果您取消注释ng-repeat小提琴中的列表并检查其中一个元素的范围,您可以看到我在说什么.创建的每个子作用域都继承父作用域的属性.对于对象,它继承了一个引用,因此如果对象上有50个属性,它只会将对象引用值复制到子作用域.如果您有50个手动创建的函数,它会将每个函数复制到它继承的每个子作用域.两种方法的时间都较慢,属性为126,000个摘要/秒,具有吸气功能的时间为80,000个摘要/秒.

我真的不明白如何更容易维护你的代码,这对我来说似乎更难.如果您不想在服务器对象发生更改时触摸HTML,那么在javascript对象中执行此操作可能会更好,而不是将getter函数直接放在您的范围上,即:

$scope.obj = new MyObject(obj); // MyObject class
Run Code Online (Sandbox Code Playgroud)

此外,Angular 2.0将使用Object.observe(),它可以进一步提高性能,但不会使用示波器上的getter函数来提高性能.

看起来这个代码都是为每个函数调用执行的.它为范围本身和返回值调用contextGetter(),fnGetter()ensureSafeFn(),以及ensureSafeObject()每个参数.

return function $parseFunctionCall(scope, locals) {
  var context = contextGetter ? contextGetter(scope, locals) : scope;
  var fn = fnGetter(scope, locals, context) || noop;

  if (args) {
    var i = argsFn.length;
    while (i--) {
      args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
    }
  }

  ensureSafeObject(context, expressionText);
  ensureSafeFunction(fn, expressionText);

  // IE stupidity! (IE doesn't have apply for some native functions)
  var v = fn.apply
        ? fn.apply(context, args)
        : fn(args[0], args[1], args[2], args[3], args[4]);

  return ensureSafeObject(v, expressionText);
};
Run Code Online (Sandbox Code Playgroud)

},

相比之下,简单的属性被编译成如下所示:

(function(s,l /**/) {
    if(s == null) return undefined;
    s=((l&&l.hasOwnProperty("obj"))?l:s).obj;
    if(s == null) return undefined;
    s=s.subobj;
    if(s == null) return undefined;
    s=s.A;
    return s;
})
Run Code Online (Sandbox Code Playgroud)