Angular面试题四
二十、angular 的缺点有哪些?
1.强约束
导致学习成本较高,对前端不友好。
但遵守 AngularJS 的约定时,生产力会很高,对 Java 程序员友好。
2.不利于 SEO
因为所有内容都是动态获取并渲染生成的,搜索引擎没法爬取。
一种解决办法是,对于正常用户的访问,服务器响应 AngularJS 应用的内容;对于 搜索引擎的访问,则响应专门针对 SEO 的HTML页面。
3..性能问题
作为 MVVM 框架,因为实现了数据的双向绑定,对于大数组、复杂对象会存在性 能问题。
可以用来 优化 Angular 应用的性能 的办法:
减少监控项(比如对不会变化的数据采用单向绑定)
主动设置索引(指定 track by ,简单类型默认用自身当索引,对象默认使用 $$hashKey ,比如改为 track by item.id )
降低渲染数据量(比如分页,或者每次取一小部分数据,根据需要再取)
数据扁平化(比如对于树状结构,使用扁平化结构,构建一个 map 和树状数据, 对树操作时,由于跟扁平数据同一引用,树状数据变更会同步到原始的扁平数据)
另外,对于Angular1.x ,存在 脏检查 和 模块机制 的问题。
4.移动端
可尝试 Ionic,但并不完善。
参考 如何看2015年1月Peter-Paul Koch对Angular的看法?
如何看待 angular 1.2 中引入的 controller as 语法?
5.最根本的好处
在 angular 1.2 以前,在 view 上的任何绑定都是直接绑定在 $scope 上的
function myCtrl($scope){
$scope.a = 'aaa';
$scope.foo = function(){
...
}
}
使用 controllerAs,不需要再注入 $scope ,controller 变成了一个很简单的 javascript 对象(POJO),一个更纯粹的 ViewModel。
function myCtrl(){
// 使用 vm 捕获 this 可避免内部的函数在使用 this 时导致上下文改变
var vm = this;
vm.a = 'aaa';
}
原理
从源码实现上来看,controllerAs 语法只是把 controller 这个对象的实例用 as 别名在 $scope 上创建了一个属性。
if (directive.controllerAs) {
locals.$scope[directive.controllerAs] = controllerInstance;
}<br>
但是这样做,除了上面提到的使 controller 更加 POJO 外,还可以避免遇到 AngularJS 作用域相关的一个坑(就是上文中 ng-if 产生一级作用域的坑,其实也是 javascript 原型链继承中值类型继承的坑。因为使用 controllerAs 的话 view 上所有字段都绑定在一个引用的属性上,比如 vm.xx,所以坑不再存在)。
<div ng-controller="TestCtrl as vm">
<p>{{name}}</p>
<div ng-if="vm.name">
<input type="text" ng-model="vm.name">
</div>
</div>
问题
使用 controllerAs 会遇到的一个问题是,因为没有注入 $scope ,导致 $emit 、 $broadcast 、 $on 、 $watch 等 $scope 下的方法无法使用。这些跟事件相关的操作可以封装起来统一处理,或者在单个 controller 中引入 $scope ,特殊对待。
栗子
依赖注入是一种软件设计模式,目的是处理代码之间的依赖关系,减少组件间的耦合。
举个栗子,如果没有使用 AngularJS,想从后台查询数据并在前端显示,可能需要这样做:
var animalBox = document.querySelector('.animal-box');
var httpRequest = {
get: function(url, callback){
console.log(url + ' requested');
var animals = ['cat', 'dog', 'rabbit'];
callback(animals);
}
}
var render = function(el, http){
http.get('/api/animals', function(animals){
el.innerHTML = animals;
})
}
render(httpRequest, animalBox);
但是,如果在调用 render 的时候不传参数,像下面这样,会报错,因为找不到 el 和 http(定义的时候依赖了,运行的时候不会自动查找依赖项)
render();
// TypeError: Cannot read property 'get' of undefined
而使用 AngularJS,可以直接这样
function myCtrl = ($scope, $http){
$http.get('/api/animals').success(function(data){
$scope.animals = data;
})
}
也就是说,在 Angular App 运行的时候,调用 myCtrl,自动做了 $scope 和 $http 两个依赖性的注入。
原理
AngularJS 是通过构造函数的参数名字来推断依赖服务名称的,通过 toString() 来找到这个定义的 function 对应的字符串,然后用正则解析出其中的参数(依赖项),再去依赖映射中取到对应的依赖,实例化之后传入。
简化一下,大概是这样:
var inject = {
// 存储依赖映射关系
storage: {},
// 注册依赖
register: function(name, resource){
this.storage[name] = resource;
},
// 解析出依赖并调用
resolve: function(target){
var self = this;
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
fnText = target.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS)[1].split(/, ?/g);
var args = [];
argDecl.forEach(function(arg){
if(self.storage[arg]){
args.push(self.storage[arg]);
}
})
return function(){
target.apply({}, args);
}
}
}
//使用这个 injector,前面那个不用 AngularJS 的栗子这样改造一下就可以调用了
inject.register('el', animalBox);
inject.register('ajax', httpRequest);
render = inject.resolve(render);
render();
问题
因为 AngularJS 的 injector 是假设函数的参数名就是依赖的名字,然后去查找依赖项,那如果按前面栗子中那样注入依赖,代码压缩后(参数被重命名了),就无法查找到依赖项了。
// 压缩前
function myCtrl = ($scope, $http){
...
}
// 压缩后
function myCtrl = (a, b){
...
}
所以,通常会使用下面两种方式注入依赖(对依赖添加的顺序有要求)。
// 数组注释法
myApp.controller('myCtrl', ['$scope', '$http', function($scope, $http){
...
}])
//显式 $inject
myApp.controller('myCtrl', myCtrl);
function myCtrl = ($scope, $http){
...
}
myCtrl.$inject = ['$scope', '$http'];
补充
对于一个 DI 容器,必须具备三个要素:依赖项的注册,依赖关系的声明和对象的获取。
在 AngularJS 中,module 和 $provide 都可以提供依赖项的注册;内置的 injector 可以获取对象(自动完成依赖注入);依赖关系的声明,就是前面问题中提到的那样。
下面是个栗子
// 对于 module,传递参数不止一个,代表新建模块,空数组代表不依赖其他模块
// 只有一个参数(模块名),代表获取模块
// 定义 myApp,添加 myApp.services 为其依赖项
angular.module('myApp', ['myApp.services']);
// 定义一个 services module,将 services 都注册在这个 module 下面
angular.module('myApp.services', [])
// $provider 有 factory, service, provider, value, constant
// 定义一个 HttpService
angular.module('myApp.services').service('HttpService', ['$http', function($http){
...
}])
二十一、 compile和link的区别: 看到一个比较6的答案。性能力(性能和能力)
编译的时候,compile转换dom,碰到绑定监听器的地方就先存着,有几个存几个,到最后汇总成一个link函数,一并执行,提升了性能。
function compile(tElement, tAttrs, transclude) { ... }tElement为编译前的element
function link(scope, iElement, iAttrs, controller) { ... } iElement为编译后的element,已经与作用域关联起来,所以可以数据绑定
如果指令只进行DOM的修改,不进行数据绑定,那么配置在compile函数中,如果指令要进行数据绑定,那么配置在link函数中。
二十二、. $apply()和 $digest()的区别
安全性:$apply()可以接收一个参数作为function(),这个 function 会被包装到一个 try … catch 块中,所以一旦有异常发生,该异常会被 $exceptionHandler service 处理。
$apply会使ng进入 $digest cycle , 并从$rootScope开始遍历(深度优先)检查数据变更。
$digest仅会检查该scope和它的子scope,当你确定当前操作仅影响它们时,用$digest可以稍微提升性能。
Angular面试题四的更多相关文章
- php面试题四
php面试题四 一.总结 二.php面试题四 01. 输出为 Mozilla/4.0(compatible;MSIE5.01;Window NT 5.0)时,可能的输出语句是: A.$_S ...
- Angular面试题二
十一.ng-repeat迭代数组的时候,如果数组中有相同值,会有什么问题,如何解决? 会提示 Duplicates in a repeater are not allowed. 加 track by ...
- Angular面试题一
一.ng-show/ng-hide 与 ng-if的区别? 第一点区别是, ng-if 在后面表达式为 true 的时候才创建这个 dom 节点, ng-show 是初始时就创建了,用 display ...
- angular学习(四)-- Controller
1.4 控制器:Controller ng 中的控制器用来对 scope 进行操作 包括初始化数据和定义事件响应函数等 ng 用来解耦业务逻辑层和视图层的关键 controller 操作 scope, ...
- U3D面试题四
1.配置Unity3D调试环境 在windows环境下,设置unity3d的编辑器调试环境方法: 点击“Edit‘---”Preferences“,弹出如下窗口 选择MonoDeveop即可. 在编辑 ...
- Java常考面试题(四)
序言 双十一那天去我女朋友那了,11.11到11.13 漏了两天的内容,今天中午刚回来的,赶紧补一下前两天漏下的博文,我相信,坚持下来,会有成长的,等到出去实习那一天,肯定会很有帮助,会感谢现在自己的 ...
- angular学习笔记(四)- input元素的ng-model属性
input元素的ng-model属性: 用于将input的值和变量的值进行双向绑定 <!DOCTYPE html> <html ng-app> <head> < ...
- Angular面试题三
十六.一个 angular 应用应当如何良好地分层? 目录结构的划分 1.对于小型项目,可以按照文件类型组织,比如: css Js { controllers models services ...
- Angular入门教程四
4.8依赖注入DI 通过依赖注入,ng想要推崇一种声明式的开发方式,即当我们需要使用某一模块或服务时,不需要关心此模块内部如何实现,只需声明一下就可以使用了.在多处使用只需进行多次声明,大大提高可复用 ...
随机推荐
- Alamofire源码导读五:错误表示
AFError is the error type returned by Alamofire. It encompasses a few different types of errors, eac ...
- POJ 2385
#include <algorithm> #include <cstdlib> #include <numeric> #include <iostream&g ...
- ubuntu 镜像站部署
定时任务 #mirror web */5 * * * * cd /mirror && git pull #mysql mirror 0 */3 * * * rsync -av --de ...
- 死锁、Lock锁、等待唤醒机制、线程组、线程池、定时器、单例设计模式_DAY24
1:线程(理解) (1)死锁 概念: 同步中,多个线程使用多把锁之间存在等待的现象. 原因分析: a.线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码, ...
- Spring Security构建Rest服务-1400-授权
安全分为 认证和授权,前边讲的都是认证,现在说授权. 前端业务系统的权限简单些,一般只区分是否登录,复杂点的还会区分 VIP用户等简单的角色,权限规则基本不变. 后台系统比较复杂,角色众多,权限随着业 ...
- Spring Boot 项目发布到 Tomcat 服务器
第 1 步:将这个 Spring Boot 项目的打包方式设置为 war.<packaging>war</packaging> SpringBoot 默认有内嵌的 tomcat ...
- svn新增文件时自动给文件设置强制只读属性needs-lock
1.从SVN客户端的“设置”->常规设置-> Subversion->Subversion 配置文件-> 编辑按钮 -> 打开配置文件 2.找到[miscellany], ...
- Oracle中的层次查询详解
1 语法格式 select [level], column, expr... from table [where condition] start with condition connect by ...
- jenkins 踩坑路 之 jenkins ssh 脚本
背景: 由于公司业务调整,整个业务要从阿里云迁移到aws,自然 jenkins 也是要进行迁移的.jenkins 迁移过程中遇到的问题在此记录下,希望能给遇到类似问题的朋友些许帮助.也便于我后期遇到此 ...
- 阿里云使用镜像安装freepbx
安装freepbx真的是历经坎坷,不过也收获了一些东西.freepbx可以通过源码安装也可以通过镜像安装.源码安装我们会在另外一篇文章中讲到,这里我们讲到的是镜像安装,在本地进行镜像安装还是比较简单的 ...