原文: http://www.cnblogs.com/whitewolf/p/3493362.html

这篇国外的文章也非常好: http://codetunnel.io/angularjs-controller-as-or-scope/

有些人觉得即使这样我们的controller还是不够POJO,以及对于coffescript爱好者不足够友好,所以在angular在1.2给我带来了一个新的语法糖这就是本文将要说的controller as的语法糖,修改上面的demo将会变成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
angular.module("app",[])
 
.controller("demoController",[function(){
 
    this.title = "angualr";
 
}])
 
  
 
<div ng-app="app" ng-controller="demoController as demo">
 
     hello : {{demo.title}} !
 
</div> 

这里我们可以看见现在controller不再有$scope的注入了,感觉controller就是一个很简单的平面的JavaScript对象了,不存在任何的差别了。再则就是view上多增加了个demoController as demo,给controller起了一个别名,在此后的view模板中靠这个别名来访问数据对象。

或许看到这里你会问为什么需要如此啊,不就是个语法糖而已,先别着急,我们会在后边分析$scope和他的差别。在此之前我们先来看看angular源码的实现这样才会有助于我们的分析:

下面是一段来自angular的code:在1499行开始(行数只能保证在写作的时候有效)

1
2
3
4
5
if (directive.controllerAs) {
 
         locals.$scope[directive.controllerAs] = controllerInstance;
 
  }  

如果你希望看更完全的code请猛击这里https://github.com/angular/angular.js/blob/c7a1d1ab0b663edffc1ac7b54deea847e372468d/src/ng/compile.js.

从上面的代码我们能看见的是:angular只是把controller这个对象实例以其as的别名在scope上创建了一个新的对象属性。靠,就这么一行代码搞定!

___________________________________________________________________________________________________________________________

原文: http://pinkyjie.com/2015/02/09/controller-as-vs-scope/

用$scope还是用controller as

发表于 2015-02-09   |   分类于 前端开发   |   暂无评论

AngularJS中在处理controller时提供了两种语法。

  • 第一种是,在DOM中使用ng-controller="TestController",这样在定义controller时需要将model绑定到$scope上。
  • 另一种是,在DOM中使用ng-controller="TestController as test",这样其实是将model直接绑定到controller的实例上。

在AngularJS的官方Get Started以及各种文档中,多推荐第一种方式,导致很多人可能都不知道原来还有第二种方式,我也是最近看一篇文章时才注意到这个。那么这两种方式各有什么优劣势呢?在现实的开发中到底更推荐哪种方式呢?今天就来探究一下!

controller as方式

$scope方式就不详细说了,大家应该最常用这种吧,看下面这段简单的代码。

对应版本的controller as方式如下:

在controller as方式中,可以给controller起别名,上面的例子中别名是ctrl。对比这两个例子,可以明显的看到controller as有两个不同的地方:

  • 在HTML中,所有的绑定都需要写别名,即需要使用点运算符ctrl.
  • 在JS中,controller的定义可以抛开$scope了,也就是说controller可以不依赖$scope了。

下面就从这两个区别出发去谈谈controller as的好处。

所有model都需要绑定在ctrl

首先有必要澄清下,这个别名是怎么实现的呢?使用AngularJS在Chrome上的调试插件AngularJS Batarang可以很清楚的看出来。安装好插件后打开上面的例子,右击页面“审查元素”打开Chrome的DevTools,在Elements标签里选中<div ng-controller="scopeController as ctrl" class="ng-scope">这一行,然后点击右边的$scope标签(就是和Styles,Computed在一行的,看不到的话点击右边的小箭头),结果就是这个DOM元素所对应的$scope,如下图:

原来别名ctrl就是定义在$scope上的一个对象,这就是controller的一个实例,所有在JS中定义controller时绑定到this上的model其实都是绑定到$scope.ctrl上的,看到这里你想到了什么?是不是和上篇文章AngularJS中scope基于原型链的继承里的$scope.data有异曲同工之妙。所以,使用controller as的一大好处就是原型链继承给scope带来的问题都不复存在了,即有效避免了在嵌套scope的情况下子scope的属性隐藏掉父scope属性的情况。

可以发现,无论定义controller时有没有直接依赖$scope,DOM中的scope是始终存在的。即使使用controller as,双向绑定还是通过$scope的watch以及digest来实现的。

另外,使用别名还有一个显而易见的好处:指代清晰。在嵌套scope时,子scope如果想使用父scope的属性,只需简单的使用父scope的别名引用父scope即可。比如下面这个例子,我们将上篇文章的例子用controller as重写。

这里我想让子scope里直接指向父scope的属性,只需在DOM绑定model时写上parent.myName即可,简单明了,看代码的一下就懂了,也不用费劲去推到底这里指向的是哪个属性了。如果你的嵌套多达四五层,那这种写法的优势就一下子体现出来了。

controller的定义不依赖$scope

定义controller时不用显式的依赖$scope,这有什么好处呢?仔细看定义,这不就是一个普通的函数定义嘛,对!这就是好处!例子中的ScopeController就是所谓的POJO(Plain Old Javascript Object,Java里偷来的概念),这样的Object与框架无关,里面只有逻辑。所以即便有一天你的项目不再使用AngularJS了,依然可以很方便的重用和移植这些逻辑。另外,从测试的角度看,这样的Object也是单元测试友好的。单元测试强调的就是孤立其他依赖元素,而POJO恰恰满足这个条件,可以单纯的去测试这个函数的输入输出,而不用费劲的去模拟一个假的$scope

另外,还有一个比较牵强的好处:防止滥用$scope$watch$on$broadcast方法。可能刚刚就有人想问了,不依赖$scope我怎么watch一个model,怎样广播和响应事件。答案是没法弄,这些事还真是只有$scope能干。但很多时候在controller里watch一个model是很多余的,这样做会明显的降低性能。所以,当你本来就依赖$scope的时候,你会习惯性的调用这些方法来实现自己的逻辑。但当使用controller as的时候,由于没有直接依赖$scope,使用watch前你会稍加斟酌,没准就思考到了别的实现方式了呢。

定义route时也能用controller as

除了在DOM中显式的指明ng-controller,还有一种情况是controller的绑定是route里定义好的,那这时能使用controller as吗?答案是肯定的,route提供了一个controllerAs参数:

1
2
3
4
5
6
$routeProvider
.when('/', {
templateUrl: 'partial/home.html',
controller: 'HomeCtrl',
controllerAs: 'home'
})

这样在模板里就可以直接使用别名home啦。

结论

总结下来,个人觉得还是偏向于使用controller as的,当然有一点要澄清,使用contoller as并没有什么性能上的提升,仅仅是一种好的习惯罢了。
————————————————————————————————————————————————————————————————————————————————

AngularJS: "Controller as" or "$scope"?

10 JULY 2014

I just finished reading a blog post by John Papa. He talks about the trend of using Controller as someName instead of injecting $scope into your controller. I wanted to expound on his point, but first let's demonstrate this technique for those of you who haven't heard of it yet. It's a pretty simple feature, but I think it has even more useful implications than what John covered.

Traditionally you're probably used to doing something like this:

<div ng-controller="MainController">
{{ someObj.someProp }}
</div>
app.controller('MainController', function ($scope) {
$scope.someObj = {
someProp: 'Some value.'
};
});

With the new Controller as technique you can now do something like this:

<div ng-controller="MainController as main">
{{ main.someProp }}
</div>
app.controller('MainController', function () {
this.someProp = 'Some value.'
});

John Papa points out in his post that the only real difference between the two is preference. He talks about the Controller as technique as "syntactic sugar" that you can use if you want to. I mostly agree with him, but I also think this solves some of the more complicated problems I've run into with Angular before.

One such problem has to do with the way scopes inherit prototypically. In JavaScript when one object inherits from another prototypically, you are able to access all the properties and methods from the parent object.

var obj1 = {
someProp: 'obj1 property!',
someMethod: function () {
alert('obj1 method!');
}
};
var obj2 = Object.create(obj1);
obj2.someProp = 'obj2 property!';

You might think from the above code that someProp was "changed" from "obj1 property!" to "obj2 property!" when obj2 was instantiated. However, you can't change properties on an object's prototype like that. All that code did was create a property called someProp on obj2 that masks the value of the underlying someProp on obj1. If you run delete obj2.someProp then someProp won't be gone, it will revert to showing the value of obj1.someProp. This is the way nested scopes work. Setting a property on a child scope does not change the property with the same name on the parent scope; it merely hides it.

There's a good reason why my example of the classic $scope technique assigns someProp to a new object called someObj. If my parent scope has a property called foo and I want to change it on my child scope, then foo must be a property on an object on the parent scope. Since objects are passed by reference, changing a property on an object attached to the parent scope actually does modify that object's property; it's only the property representing the object itself that we would end up masking if we set it on our child scope.

Here's an example of what happens when you nest controllers and use scalar values on the $scope.

<div ng-controller="ParentController">
ParentController: <input type="text" ng-model="foo" />
<div ng-controller="ChildController">
ChildController: <input type="text" ng-model="foo" />
</div>
</div>
app
.controller('ParentController', function ($scope) {
$scope.foo = "bar";
})
.controller('ChildController', function ($scope) { /*empty*/ });

Initially the child scope has no property called foo. Instead it's reading from the inherited foo property from the parent scope. This is why the child input updates when you change the parent input. However, once you modify the child input, it uses its value and updates foo on the child scope. Because of the way prototypal inheritance works, the child foo property is merely maskingthe parent foo property. In other words, foo on the parent scope remains unchanged while foo on the child scope has been changed to a new value. Once you've modified the child input, modifying the parent input does nothing to the child one anymore because the child scope now has its own foo property with a value.

The problem with scope inheritance is one I see newbies run into constantly on Stack. Traditionally, the fix is to do what I did in my first example and attach your scalar values to objects on the scope.

<div ng-controller="ParentController">
ParentController: <input type="text" ng-model="obj.foo" />
<div ng-controller="ChildController">
ChildController: <input type="text" ng-model="obj.foo" />
</div>
</div>
app
.controller('ParentController', function ($scope) {
$scope.obj = {
foo: "bar"
};
})
.controller('ChildController', function ($scope) { /*empty*/ });

You can see that the inputs properly update each other now. It just sucks that we have to use such a strange setup just to avoid this issue. Now with the addition of the new Controller as technique we don't have to worry anymore! We can simply refer to the controller we wish to refer to and stop worrying about the subtleties of scope inheritance.

<div ng-controller="ParentController as parent">
ParentController: <input type="text" ng-model="parent.foo" />
parent.foo: {{ parent.foo }}
<div ng-controller="ChildController as child">
ChildController: <input type="text" ng-model="parent.foo" />
parent.foo: {{ parent.foo }}
</div>
</div>
app
.controller('ParentController', function () {
this.foo = "bar";
})
.controller('ChildController', function () { /*empty*/ });

Not only does this help bypass this annoying inheritance issue, I think it makes the markup even cleaner than when we used $scope. You can clearly see, even in the DOM managed by the child controller, that we're explicitly binding things to a value on the parent controller. We no longer have to do any of this $scope.$parent nonsense or create complicated services and inject them all over. Now you can just simply refer to the controller and the value that you intended to refer to in the first place :D

It's important to keep in mind what Angular is actually doing with this new syntax. It's not some magical global variable that you can refer to from anywhere; it's just a variable that refers to that controller's execution contextand that variable is attached to $scope behind the scenes.

Essentially, this:

app.controller('MyController', function () {
this.someValue = "Hello!";
});

Is no different from this:

app.controller('MyController', function ($scope) {
$scope.myController = this;
this.someValue = "Hello!";
}

It's just that the "as" syntax implicitly creates a namespace on the controller's scope, whereas you must create a namespace manually in the latter example. Don't believe me? Here's the proof :)

As you can see, this and $scope.myController are the same object in the above example. That gives you a big clue to what Angular is doing behind the scenes. It merely attached the controller variable to the $scope, implicitly giving us a very readable and logical namespace for the values we'd like to expose. What that also means is that if we overrode the child scope with a property called myController, it would still mask the myController property implicitly defined on the parent scope. So as long as you aren't setting variables on your child scopes to the same value that you used in your "controller as someName" on the parent scope, the whole inheritance issue is kind of hidden from you and helps prevent you from making mistakes as easily.

angularJS 系列(五)--controller AS 语法的更多相关文章

  1. AngularJS 系列 01 - HelloWorld和数据绑定

    目录导读: AngularJS 系列 学习笔记 目录篇 前言: 好记性不如烂键盘,随笔就是随手笔记,希望以后有用. 本篇目录: 1. Hello World 2. AngularJS中的数据绑定 3. ...

  2. JVM系列五:JVM监测&工具

    JVM系列五:JVM监测&工具[整理中]  http://www.cnblogs.com/redcreen/archive/2011/05/09/2040977.html 前几篇篇文章介绍了介 ...

  3. SQL Server 2008空间数据应用系列五:数据表中使用空间数据类型

    原文:SQL Server 2008空间数据应用系列五:数据表中使用空间数据类型 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server 2008 R2调测 ...

  4. Javascript数组系列五之增删改和强大的 splice()

    今天是我们介绍数组系列文章的第五篇,也是我们数组系列的最后一篇文章,只是数据系列的结束,所以大家不用担心,我们会持续的更新干货文章. 生命不息,更新不止! 今天我们就不那么多废话了,直接干货开始. 我 ...

  5. Hexo系列(五) 撰写文章

    在利用 Hexo 框架搭建一个属于我们自己的博客网站后,下面我们就来谈谈怎样在网站上书写我们的第一篇博客吧 一.创建文章 在站点文件夹中打开 git bash,输入如下命令创建文章,其中 title ...

  6. AngularJS 系列 学习笔记 目录篇

    目录: AngularJS 系列 01 - HelloWorld和数据绑定 AngularJS 系列 02 - 模块 (持续更新)

  7. AngularJS 系列 02 - 模块

    引导目录: AngularJS 系列 学习笔记 目录篇 前言: 其实,在上篇文章介绍数据绑定的时候,我们的HelloWorld的代码案例中就已经使用了模块(module).哈哈. 本篇就着重介绍一下a ...

  8. CSS 魔法系列:纯 CSS 绘制各种图形《系列五》

    我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...

  9. Netty4.x中文教程系列(五)编解码器Codec

    Netty4.x中文教程系列(五)编解码器Codec 上一篇文章详细解释了ChannelHandler的相关构架设计,版本和设计逻辑变更等等. 这篇文章主要在于讲述Handler里面的Codec,也就 ...

  10. WCF编程系列(五)元数据

    WCF编程系列(五)元数据   示例一中我们使用了scvutil命令自动生成了服务的客户端代理类: svcutil http://localhost:8000/?wsdl /o:FirstServic ...

随机推荐

  1. C#中泛型默认关键字(default)详解

    我们在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型 T:(T 是引用类型还是值类型?)对此我们将如何处理? C#代码实例: /// <summary&g ...

  2. radiobutton以及checkbox背景图片拉伸变形的问题

    设置RadioButton的text属性,只需要有这个属性就可以(设置“”内容就行),然后再添加textsize属性,将字体大小属性值设置为比较小,我设置为2sp.运行后我们会发现图片变形问题不复存在 ...

  3. HDU 5813 Elegant Construction

    构造.从a[i]最小的开始放置,例如放置了a[p],那么还未放置的,还需要建边的那个点 需求量-1,然后把边连起来. #pragma comment(linker, "/STACK:1024 ...

  4. SMO 的环境

    Microsoft SQL Server System CLR Types - http://go.microsoft.com/fwlink/?LinkId=123721&clcid=0x40 ...

  5. ERROR 1406 : Data too long for column 解决办法

    解决办法: 在my.ini里找到 sql-mode=”STRICT_TRANS_TABLES,NO_AUTO_Create_USER,NO_ENGINE_SUBSTITUTION” 把其中的STRIC ...

  6. 准备着手学习python

    1. python 的框架 Tornado 网址: http://www.tornadoweb.org/en/stable/ github: https://github.com/tornadoweb ...

  7. C# API 大全

    C:\ProgramFiles\MicrosoftVisual Studio .NET\ FrameworkSDK\Samples\ Technologies\ Interop\PlatformInv ...

  8. java中json数据生成和解析(复杂对象演示)

    1.json简单介绍 1.1 json是最流行和广泛通用的数据传输格式,简称JavaScript Object Notation,最早在JavaScript中使用. 1.2 举个例子,下面是一个jso ...

  9. Goods transportation

    Goods transportation time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  10. WPF InkCanvas 画图 基础使用教程

    大家好,由于很多原因,我有很长一段时间没有在 CSDN 上分享我的学习成果了,如今终于可以回归分享之路了. 之前在做一个项目的时候,想在一个区域里绘制自己的图形,于是上网搜索资料,无意中找到了 Ink ...