Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浴火重生的Angular #9

Open
xufei opened this issue Nov 21, 2014 · 27 comments
Open

浴火重生的Angular #9

xufei opened this issue Nov 21, 2014 · 27 comments

Comments

@xufei
Copy link
Owner

xufei commented Nov 21, 2014

浴火重生的Angular

Angular团队近期公布了他们对2.0版本的一些考虑,很详尽,很诚恳,我读了好几遍,觉得有必要写点东西。

对于一个运行在浏览器中的JavaScript框架而言,最喜欢什么,最害怕什么?是标准的变动。那么,放眼最新的这些标准,有哪些因素会对框架产生影响呢?

  • module
  • Web Components
  • observe
  • promise

这几点,我是按照影响程度从大到小排列的。下面逐条来说:

module

早期的JavaScript在模块定义方面基本没有约束,但作为框架来说,不按照某种约定的方式去写代码,就会导致一盘散沙,所以各家都自己搞一套,大部分还是各不兼容的,这是历史原因造成的,不能怪罪这些框架。最近几年,为了解决这些问题,人们又发明了AMD,CMD,以及各种配套库和工程库。好不容易有些框架向它们靠拢了,可是module又来了。

这真是没完。我知道很多人是对module有意见的,我自己也觉得有些别扭,但我坚信一个道理:有一个可用但是稍微别扭的标准,比没有标准要好得多。所以,不管怎样,既然他来了,就得想办法往上靠。不靠拢标准的后果是什么?非常严重,因为现在的Web是加速发展的,浏览器只要过了一个升级瓶颈,后面的发展快得出奇。不要看现在还有这么多老旧浏览器,很可能你睡一觉起来突然发现已经基本没人用了,到那时候,不紧跟标准的框架就很惨了,瞬间就边缘化了。

我们来看看Angular原先的module设计,如果是在五年前,它刚起步的时候看,可能觉得还可以,现在再看,问题就比较多了。Angular现有版本的module,其实跟我们在ES中看到的module不是一个概念,更像C#里面的namespace,它的各种controller,service,factory才是真的模块。

我认为现有版本的这块,有几个不好的地方:

  • 现有的module实际上毫无意义,根本不能起约束作用。
  • 从API的角度强制区分模块职责是没有必要的,比如说,service和factory的区别在哪里?仅仅在于返回与封装的方式不同,其实是可以通用的,所以只需一种工厂方法就可以了,用户愿意返回什么就返回什么,他自己通过命名来区分这个模块的职责。
  • 没考虑模块的动态加载。这是Angular目前版本最大的设计问题,对于大型应用来说,很致命,所以目前大家都是通过各种黑魔法来解决这个问题。

所以,Angular 2.0中,把这一块彻底改变了,使用ES6的module来定义模块,也考虑了动态加载的需求。变动很大,很多人有意见,但我是支持他们的。这件事不得不做,即使现在不做,将来也还是要做。毛主席教导我们:革命不彻底,劳动人民就要吃两茬苦,受两茬罪。在现在这个时代,如果还继续用非标准的模块API,基本等于找死,所以它需要改变。

Web Components

为什么Web Components也能带来这么大的影响呢,因为它同样会造成断代升级,也就是说,你非完全跟着它的路不可,没有选择。

Web Components标准本身同样是个见仁见智的话题,在本文中我不评价,它作为标准,既然来了,大家当然要往上靠。一个致力于大规模Web前端开发的现代框架,不考虑Web Components是完全不可想象的。那么,怎么去靠拢它呢?

Web Components提供了一种封装组件的方式,对外体现为自定义标签,对内体现为Shadow DOM,可以定义自己的属性、事件等,这样问题就来了。

我们看当前版本的Angular,能看到ng-click之类的扩展元素属性,那么,他为什么要写成ng-click?是因为这是对原生click的一层封装和转换,同理,如果我的原始事件不是click,是另外一个名字,你当然也得跟着加一个,不然针对这种东西的操作就玩不下去。所以说,其实它是给每个有价值的原生事件都写了扩展。

这就有问题了,你能这么做的原因是,你预先知道有这么一些元素,这么一些事件,也知道这些元素上的这些事件是什么行为,如果全是自定义的,他不告诉你,你急死也不知道,怎么办?所以这一块必须重新设计。

同理,属性也是这样,之前像img的src,就有一个ng-src,如果没这个,你设置在上面的表达式就会被当成真的url,先去加载一次,显然是不对的。所以,设置在ng-src上,它等表达式解析出结果了,再把结果设置到src去。如果是用Web Components扩展的自定义组件,它不知道你有哪些属性,就搞不下去了。

所以,Angular 2.0团队在这一块还很纠结,需要很多探索,很多权衡才能找到一种能接受的方式。

后来在这一块,我跟@RubyLouvre 探讨了一下,他的观点是不要让数据绑定接触到Web Components,也就是说,不让扫描进入“暗世界”,我想了想,觉得也有道理,只是这样Web Components跟原生元素就要区别对待了。

或者对所有Web Components使用同一个壳子再次封装?感觉还是很怪。

observe

当前版本的Angular使用脏检测的方式来实现数据的关联更新,这种机制有一定优点,但缺点也非常明显。

在其他语言中要监控数据的变更,很多在语言层面上有get和set,一般都是从这个角度入手,有不少JavaScript框架也是从这个方面做下去的,Angular不是。

Angular的脏检测很有特色,它采用的是新旧值比对的方式,也就是说,对每个可变动的模型,保存上一次的值,然后通过手动,或者是封装事件调用检测,一遍又一遍地刷新模型,直到稳定,或者超出容忍限度。

为什么这里面会有不稳定现象呢?我举个简单的例子,这是伪代码,仅供演示:

function Entity() {
    //初始化
    this.a = 1;
    this.b = 1;
    this.c = 1;

    //监控语句,伪代码
    this.b = this.a + 1;
    this.c = this.b + 1;
}

这里面几条语句不是真的赋值,是用来表示:每当a变化了,b就跟着变,然后c也跟着变,那我们在这里就要创建两个监控,一个是对a的监控,在里面给b赋值,一个是对b的监控,在里面给c赋值。

好了,比如有人给a赋了个新值,我们一个脏检测循环下来,b增加了1,c也跟着增加了,好像没什么问题。那我们怎么知道整个模型稳定了呢?很简单也很无奈,再运行脏检测一次,这次a没变,所以另外两个也不变了,跟上一次检测之后的结果一样,所以就认为它稳定了。

这里我们看到,不管你怎样,只要变过数据,至少要跑两次脏检测。为什么说至少呢,因为我们这种情况刚好把坑给绕过了,来改下代码:

function Entity() {
    //初始化
    this.a = 1;
    this.b = 1;
    this.c = 1;

    //监控语句,伪代码
    this.c = this.b + 1;
    this.b = this.a + 1;
}

没改什么,只是把两条监控语句互换了,这个结果就不对了。为什么呢,比如a赋值为1之后,第一遍结果是这样的:

  • a = 1;
  • c = 2;
  • b = 2;

这里讨厌的是c的监控语句先执行了,但b还没有变,可是我们当时是不知道的。然后,我们想看看模型稳定了没有,就再检测一次。所谓的检测,其实是两个步骤:把所有监控语句跑一遍,对比本次结果与上次的差异。

那么,这次变成了:

  • a = 1;
  • c = 3;
  • b = 2;

第二轮结束。模型稳定了吗?其实已经稳定了,但是代码是不知道的,它判断稳定的依据是,本次结果与上次相同,可事实是不同的,所以它还得继续跑。

第三次跑完,终于跟第二次结果一样了,于是他认为模型稳定了,开始把真正的值拿出去用了。

所以这个过程的效率在很多种情况下偏低,但好在他这个变更不是实时的,而是通过某些东西批量触发,所以也还凑合。另外有些框架,是每次对数据赋值了就去立刻更新关联值,这当数据结构比较复杂的时候,这样比较高效。

Object.observe与之相比,在定义监控的时候比较直观一些,而且,基于set get的绑定框架,有些会在原始数据的原型上定义一些“私有”方法,相比来说,observe这种方式从数据的外部视角来处理变更,更合理一些。

Angular 2.0的数据绑定机制应该会使用observe重写,可以期待这个方面有较大的提升。

但不管什么绑定方式,都是有坑的。我知道读者中有不少坏人,你们看到这里肯定想到很多坏主意了,比如刚才的脏检测,有没有办法把这个过程搞死?很容易,我帮你写个简单的:

function Entity() {
    //初始化
    this.a = 1;
    this.b = 1;

    //监控语句,伪代码
    this.a = this.b + 1;
    this.b = this.a + 1;
}

这个代码死循环了,形成了监控闭环。所以,在Angular里面发现循环到一定量的时候,就会觉得它停不下来,终止这个循环。在其他技术实现的绑定框架中,同样要解决此类问题,所以监控到变更的时候,也不是直接拿去应用。

promise

很奇怪啊,我一直喜欢promise这种编写异步代码的方式。可能我对它的喜好来自一些背景,比如说,做可视化组件编程。这个可视化的意思是指通过拖拽配置,配置逻辑流程(注意,不是拖UI)。

比如说,流程细到方法的粒度,每个步骤映射到一个方法,然后拖拽这些步骤,配置出执行流程。这里面有个麻烦就是异步,比如说,某个方法异步了,那就麻烦了,因为在一个纯拖动的配置系统中,如果你还要让他手工调整什么东西甚至改代码的话,这个事情基本就白做了。

所以你看,promise在这里优势很大。每一个有异步倾向的方法,我都让它返回promise,甚至为了一致性,不异步的方法也这么干,每个方法的入参出参都是map,让promise带着,是不是就很好了?

以上是我个人见解,可忽略,谢谢。

那么,在Angular 2.0中promise有什么影响呢?

回顾Angular 1.x版本,在其中已经可以看到很多promise的身影,只是那时候用了$q,一个小型的promise实现。在2.0中,promise的使用将更加广泛,因为更多的东西是异步的了,比如新的路由系统。

promise本身是很容易被降级的,在原生不支持它的浏览器中也很容易搞出一个polyfill来。

这个事情在我个人看来是很喜闻乐见的。

Angular 2.0除了作出符合标准的改进,还有一些提升的方面:

依赖注入

Angular大量使用了依赖注入。在JavaScript里面怎样做依赖注入呢?比如这段代码:

function foo(moduleA, moduleB) {
    moduleA.aaa(moduleB);
}

a跟b这两个模块都要注入进来。对于依赖注入系统而言,首先要知道注入什么,比如这里,至少要先知道a和b是什么,怎么知道呢?很多框架都用一种方式,就是先把foo这个待注入函数toString,这就取得了函数定义的文本,然后使用正则表达式提取参数名。

这个办法可行,但不可靠,它害怕压缩。随便什么压缩工具,肯定认为形参名是没用的,随手就改成a或者b了,这样你连正确的模块名都找不到了。那怎么办呢,只能老土一些:

foo.$inject = ["moduleA", "moduleB"];

这样总可以了吧?

这样写起来还是有些折腾,而且运行时的数据也不够完全,所以Angular 2.0很激进地引入了一种类似TypeScript的语言叫AtScript,支持类型和注解,比如它的这个例子:

import {Component} from 'angular';
import {Server} from './server';

@Component({selector: 'foo'})
export class MyComponent {
  constructor(server:Server) {
      this.server = server;
  }
}

一些配置信息就可以搞在注解里,类型信息也就丰富了,然后这代码编译成ES6或者5,多么美好。更美好的是,2.0借助这种语言,可能把原来的指令、控制器之类的东西统一成组件,使用普通ES6 class加注解的方式来编写它们的代码,消除原来那么多复杂冗余的概念。

其实还有很多改进点,比如路由等等,没法一一列出了,感兴趣的可以查阅Angular 2.0已经流出的文档,或者查阅它的github库。

小结

Angular 2.0这次的规划真是脱胎换骨,看了介绍文档,简直太喜欢了,之前我考虑过的所有问题都得到了解决。这一次版本跟之前有太大变化,从旧版本迁移可能是个难题,不过相对它所带来的改进,这代价还是值得的。勇于革自己的命,总比被别人革命好,期待Angular的浴火重生!

@huang-xiao-jian
Copy link

感谢博主翻译。
跟随最新标准,站在未来的角度上来规划2.0版本本来无可厚非,我唯一不理解的地方,在于AtScript。因为时间精力问题,只能够使用coffeescript,所以也搞不清coffeescript,typescript,atscript之间的关系,而且因为个人喜好问题,一股浓浓的Python即视感真的让人有点纠结。

@xufei
Copy link
Owner Author

xufei commented Nov 22, 2014

对官方公布细节的翻译在这里:#8

@ychow
Copy link

ychow commented Nov 22, 2014

Nice!

@LiuJi-Jim
Copy link

脏检查和observe现在感觉就是背道而驰,这一点估计改动会很大,但也非常值得期待。
打个比方,我喜欢用defineProperty来给$scope添加一些带逻辑的纯getter属性,或者带逻辑的setter属性。
为什么?因为用原始值配合expression绑定可能做不出这么复杂的逻辑,expression绑定也解决不了v->m反向绑定中的逻辑。
而且也许我仅仅是想做一个genderText属性,getter就是return this.gender == 0 ? '男' : '女',这的确是一个expression,但它也是个逻辑,因为有一天我可能会改成'帅哥'/'美女',那时候也许会不幸发现那个expression已经遍布全球,改起来很费劲。
但在实际使用中我发现因为脏检查循环的存在,我的getter经常要被调用好几次,原因你懂的。
如果用observe取代脏检查,我们就可以建立起来一个真正的VM层,VM层的数据,甚至是各种复杂类型的字段,是带逻辑的,也就是所谓“视图逻辑”,expression还可以照用不误,方便,灵活。更复杂的组合属性、依赖属性就可以用getter实现了。
web component这一块,我觉得不是“不应该让扫描进入shadow dom的暗世界”,而是就像shadow dom的初衷一个样,就是隔离。外面扫外面的,里面扫里面的,这不正是现在ng的$scope隔离的概念吗。
所以这一点我觉得可真是殊途同归呀~
而我对web component比较期待的地方其实是它的dom事件隔离和css隔离。
dom事件隔离可以让组件的实现和使用都更轻松惬意,具体就不举例了,说起来都是泪。
最近也在用ng,我想尝试语义化(而非结构化)classname,比如用.color-picker>.preview取代.color-picker-preview`,因为“结构化”classname会像叠罗汉一样越来越长,越来越蛋疼。
现在我是靠less来“隔离”,但是写的不好的时候,比如子选择符写成后代选择符的时候,就很容易跪,随随便便就跟别的冲突没商量。css隔离可以让我们对css的架构和规范化这回事的理解产生一定颠覆性的变化,这是我比较期待的一点,而且这是我所知道现在CSS隔离的唯一的一个办法了……

@xufei
Copy link
Owner Author

xufei commented Nov 22, 2014

@LiuJi-Jim getter这个的问题在哪里啊,我没明白,getter里面本来就是不该放逻辑的……这种文本的转换应当是通过filter去做啊,因为如果你需要在模型里做getter的转换,基本上一定是给视图用的,所以用filter很合适。假如模型中还存在别的转换,那就是动用$watch的时候,属于在模型内部的关联。

web components这段,可能你没明白我意思,我举个例子:

你有一个组件

<foo bar="123"></foo>

bar属性用于接收一个数字,然后把组件内部的某个东西创建这个数字这么多个,并且显示出来,这本身不会有任何问题,但考虑一个场景,我想把这个数字动态传入,这个数字从哪里来呢?从外层作用域的某个变量中来,如果是普通元素,是不是你要写:

<div ng-controller="TestCtrl">
  <input type="number" ng-model="a"/>  
  <span ng-bind="a"></span>
  <foo bar="{{a}}"></foo>
</div>

你看,a的值可以从输入框传入span并显示,但是传不到组件的bar里。如果你想里面扫里面的,那么,组件在解析插值表达式的时候,从哪里去获取这个a?所以这个问题的关键在于外层世界与组件的传值,别的是没有问题的,其他时候大家都各自做自己的事好了。

样式这块,碰到web components的时候,还是需要重新规划,思路跟之前的大有不同,我想想。

@LiuJi-Jim
Copy link

@xufei 我对filter的看法是它应该是高度可复用的util类型的东西,比如urlencode、camelCase这种就是filter,但上面我说的那个例子,或者fullName定义getter为return firstName + lastName我觉得就应该是VM属性,因为它根本不能被除了这个模型以外的别的东西所复用……因为受C#影响,我喜欢用getter/setter,于是这种事情我会觉得不是一码事。

对于<foo bar="{{a}}"></foo>的情况我感觉也没问题啊,如果ng发生了改变那么foo组件会触发attribute的修改回调,这个是web component支持的。web component内部维护一个属性,内部视图可以和这个内部苏醒双向绑定。剩下的就是维护内部属性与外部暴露出来的attribute之间的绑定了。相当于内部的绑定和外部的绑定隔离开了,中间通过attribute来做桥梁。

@xufei
Copy link
Owner Author

xufei commented Nov 22, 2014

@LiuJi-Jim 在Angular里面,是可以把filter看作数据getter的装饰器的,它的职责其实就是干这些事。

绑定是有问题的。

这个绑定实现不了,原因是angular不知道组件有bar属性,它必须先穷举,必须预先知道元素上有哪些可插值属性,然后挨个去解析,还要区分找到的是属性还是方法。就算找到了bar,也没法知道它是不是要插值。就算知道它是要插值的,在计算出真实结果传入之前,已经把整个插值表达式传到组件内部了,一个不合法字符串。

所以问题都在内外传递这一步上。

@RubyLouvre
Copy link

Polymer基础层使用了以下技术:

  1. DOM Mutation OberserversObject.observe():用于监视DOM元素和简单JavaScript对象的改变。该功能可能会在ECMAScript 7中正式标准化。
  2. Pointer Events :在所有的平台上以同样的方式处理鼠标和触摸操作。
  3. Shadow DOM:将结构和样式封装在元素内(比如定制元素)。
  4. Custom Elements:定义自己的HTML5元素。自定义元素的名字中必须包括一个破折号,它的作用类似于命名空间,为了将其与标准元素区分开来。
  5. HTML Imports:封装自定义元素,包中包括HTML、CSS、JavaScript元素。
  6. Model-Driven Views(MDV):直接在HTML中实现数据绑定。仍没有标准化的计划。
  7. Web Animations:统一Web动画实现API。

你们所说的问题就是MDV吧,慢慢等吧,否则自己实现扫描器

@bodyno
Copy link

bodyno commented Nov 24, 2014

支持Polymer,未来的趋势!!!

@nighca
Copy link

nighca commented Nov 24, 2014

@xufei

这个绑定实现不了,原因是angular不知道组件有bar属性,它必须先穷举,必须预先知道元素上有哪些可插值属性,然后挨个去解析,还要区分找到的是属性还是方法。就算找到了bar,也没法知道它是不是要插值。就算知道它是要插值的,在计算出真实结果传入之前,已经把整个插值表达式传到组件内部了,一个不合法字符串。

我对angular不是很熟,但是对于它解决的问题大概清楚,有点疑问:

为什么angular不是扫描元素的attributes,读到bar,然后根据值bar="{{a}}"进行插值;而是需要事先知道一个元素可插值属性列表['bar',...]

在计算出表达式结果之前,传入组件内部的值是不合法内容。这不算问题吧,现在的angular+html元素也有这个问题。所以angular在逻辑完成之前会先隐藏内容,计算完成后再更新属性,这时候的属性是合法的,控件对应地更新状态就好了。

@huang-xiao-jian
Copy link

Polymer还没碰过,周末看一下先。

@hax
Copy link

hax commented Nov 25, 2014

@RubyLouvre 正美同学的“不要让数据绑定接触到Web Components”是什么意思?

按说你是区分不出一个自定义元素和html本身元素的,所以机制应该是一视同仁的。

当然你可以说我根据自定义元素的规则(带有 - 的)来区分。可是别忘了还有 type extension 的情况(尽管我觉得type extension这个名字有点问题),就是对现有元素的增强,如 <div is="my-decorator">,所以那上面既有本身html的属性和事件,也有扩展的属性和事件。

@xufei
Copy link
Owner Author

xufei commented Nov 26, 2014

@hax 他的意思是:不要让绑定扫描机制跨越组件内外。我举个例子:

之前Angular里面的元素指令,如果我们造这么个元素Panel,把它放在一个div中:

<div ng-controller="TestCtrl">
  <Panel></Panel>
</div>

比如这个TestCtrl是外层的视图模型,里面的所有变量,其实可以在Panel的内部实现中用于绑定。

但是如果用Web Components来实现这个自定义元素Panel,这个事情是非常困难的,所以干脆就不要想这些事,组件外的东西限制到组件外,组件内的东西如果有绑定,内部自行通过一个公共类处理。

但我的疑问在于,假如恰好在组件直接使用的时候,要从外部带入一个值,怎么办?

比如TestCtrl里面有变量a和b,我只是想这样:

<div ng-controller="TestCtrl">
  <Panel title="{{a + b}}"></Panel>
</div>

这个从使用者的角度,并未破坏Web Components的封装性,因为没有干涉内部实现,所以应当还是允许比较好,否则,自定义元素与原生元素的行为就不一致了。

@hax
Copy link

hax commented Nov 26, 2014

@RubyLouvre “自行通过公共类处理”是什么意思?让组件自己import相关的model?这不是break了封装和复用性嘛。

我理解中组件必然需要数据绑定。因为可以把组件理解为增强性的form controls,所以是最需要数据绑定的部分。

@xufei
Copy link
Owner Author

xufei commented Nov 26, 2014

@hax 他意思是,内外各自绑各自的,但是如果像我上面举的例子,那个表达式只能让外层去解析,内层能拿到表达式,拿不到执行上下文,还是绑不了

@chinfeng
Copy link

chinfeng commented Mar 8, 2015

浴火是了,重生倒未必,我有几点不太同意楼主:

  1. module 更多是被 es6 的语言机制 import + class 取代了,至于楼主说的几个所谓的缺点,我认为本来就不是 module 设计上的初衷,楼主似乎把这个东西的设计初衷的臆想成与 AMD 等价物了。
  2. 考虑动态加载机制,并不只是 module 机制能解决的问题。其实 hack 2-3行 ng 的源码,动态加载模块的功能就可以实现,所以 module 不是动态加载机制的元凶。hack 以后的代码基本上就是所有节点都 complie-link 一次,差不多就是再运行一次 bootstrap。所以这需要生命周期管理的整个设计要改变,然后各种算法也要重新设计成可以多次重入。所以 ng 的生命周期机制才是动态加载的元凶。
  3. ES 没有语法机制的支持,也没有 getter/setter 的编码文化,如果支持 POJSO 除了 dirty-checking 循环比较新旧值,你还有更好的办法吗?就如 Rivet.JS 那样强制使用 getter/setter,但对于多层嵌套的对象,getter/setter 就让编码的难度加大了,缺点也是同样也很明显。
  4. web component 一块,我认为“不让扫描进入暗世界”不是正确的思路,入口点应该给予程序员选择的余地,这个参数是按值(组件内不可改变该值)还是按引用(组件内可以改变这个值)传递,都应该予以支持。可以看到 angular.module 的 value 和 constant,directive 的 '@' 和 '=' 传参,都体现了这个属性传递处理的明确性,我认为这个在 ng1 里面就已经没什么可以纠结的了。

所以,还能叫 ng,只是利用了一些语言上的新特性来重写一次 angular。从目前的文档来看,浴火的是:class 取代了 controller,干掉了 $scope,annotation 取代了 module。但是骨架仍然 1.x 的形状,重生是未必。

@tsingson
Copy link

感谢,文章翻译得好啊,后面的讨论也有趣。谢谢上面各位。

@steelli
Copy link

steelli commented Jul 25, 2015

nice

@shikelong
Copy link

nice.

@yalishizhude
Copy link

还打算学Angular,Angular2出来Angular是不是就没用了,还有必要学Angualr么?

@hbbpb
Copy link

hbbpb commented Jan 4, 2016

大家的讨论很精彩,赞一个。

@cdll
Copy link

cdll commented Feb 5, 2016

学习了~原来ng2的变革如此之大!

@jthmath
Copy link

jthmath commented Mar 26, 2016

ng2已经弃用AtScript改用TypeScript了

@luozt
Copy link

luozt commented May 16, 2016

@xufei 已经说得很清楚了,angular1是不能动态加载组件的 @nighca

比如:

<div id="container" ng-controller="myController">
  <p class="text-center bg-info" ng-hide="testValue">加载中...</p>
  <p ng-show="testValue">testValue: {{testValue}}</p>
  <hello data-some-val="{{testValue}}"></hello>
</div>

指令hello的属性值这样传进去就报错了。所以这时只能通过事件广播的方式对指令进行更新,非常不方便

@jusfeel
Copy link

jusfeel commented Oct 8, 2016

谷歌把angular毁了。angular本不配称框架,现有知识的敏捷利用的价值让一代备受追捧,但真不是框架,也没想。谷歌非要强加自己天下一统舍我其谁的个性,完蛋。重写也是个自恋的说法,不得不扔出DI,显示性编程,设计模式里的古怪名字来,一团乱麻,又一个Java类语言。本质问题是异步不是主要问题,service根本就是evil。数据本地化才是app的王道,而所谓的稀释依赖不过是自找麻烦,web app那些需求全世界都知道,你多做点,开发人就少做点。占领市场对谷歌才是最重要的,就跟安卓一样,哭的是码农们,跟着这么个利益驱动,没有品味的大佬,永远痛苦抑郁。同样是框架,ember2年前就明白核心问题。完全是好比苹果和安卓的情况。也难怪,ember的创始人就是来自苹果。

@freedomdebug
Copy link

啥玩意都不能免俗,临近秋天大家都要吃起羊肉了。。es6、组件化都是当下趋势,与时俱进,蛮好的,各位可以马上玩起来

@zhoulujun
Copy link

再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结
http://www.zhoulujun.cn/zhoulujun/html/webfront/ECMAScript/angularjs/2018_0417_8097.html,
依照本人的口味对您的面试题做了些整理。如有不妥,望告知。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests