zoukankan      html  css  js  c++  java
  • 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 = /^functions*[^(]*(s*([^)]*))/m;

        var STRIP_COMMENTS = /((//.*$)|(/*[sS]*?*/))/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可以稍微提升性能。

     

  • 相关阅读:
    AcWing 1135. 新年好 图论 枚举
    uva 10196 将军 模拟
    LeetCode 120. 三角形最小路径和 dp
    LeetCode 350. 两个数组的交集 II 哈希
    LeetCode 174. 地下城游戏 dp
    LeetCode 面试题 16.11.. 跳水板 模拟
    LeetCode 112. 路径总和 递归 树的遍历
    AcWing 1129. 热浪 spfa
    Thymeleaf Javascript 取值
    Thymeleaf Javascript 取值
  • 原文地址:https://www.cnblogs.com/ndos/p/8331693.html
Copyright © 2011-2022 走看看