加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

(译)理解AngularJS中的Scopes

发布时间:2020-12-17 09:43:31 所属栏目:安全 来源:网络整理
导读:(初次翻译,有些地方翻译的不准确,还请对照原文理解:https://github.com/angular/angular.js/wiki/Understanding-Scopes) 概要 AngularJS中,子作用域通常是原型继承自他的父作用域。这个规则的一个例外就是使用了 scope:{...} 的指令——这个创建了一个

(初次翻译,有些地方翻译的不准确,还请对照原文理解:https://github.com/angular/angular.js/wiki/Understanding-Scopes)

概要

AngularJS中,子作用域通常是原型继承自他的父作用域。这个规则的一个例外就是使用了scope:{...} 的指令——这个创建了一个“隔离”的作用域,不是以原型继承的方式(以及使用了transclusion的指令)。这个结构通常用于创建“可复用的组件”指令。在指令中,默认父作用域直接被使用。这意味着你在指令中做的来自于父作用域的更改也会在父作用域中生效。如果你设置了scope:true (不是scope:{...}),那么原型继承就会被应用到该指令上。

作用域继承通常都是很直接明了的,并且你通常甚至不知道它发生了…直到你在子作用域应用了双向数据绑定(也就是ng-model)到定义在父作用域中原始类型(例如:数字,字符串,布尔值)。这种情况他不像大多数人认为的那样生效。原因就是子作用域生成了自己的属性,并且隐藏/覆盖了父作用域中的同名属性。这不是AngularJS做的,而是JavaScript中原型继承的工作方式。年轻的AngularJS开发者通常未意识到ng-repeatng-switchng-viewng-includeng-if 都会创建一个新的子作用域,所以问题经常出现当这些指令被使用的时候(看一个例子对这个问题有个快速认识)。

这个原始数据类型的问题可以很简单避免,通过使用“最佳实践”:总是使用.运算符在ng-models中,看三分钟很值得,他演示了一个ng-switch绑定原始数据类型的问题.

使用.在数据模型中将会确保原型继承生效,因此,使用
<input type="text" ng﹎odel="someObj.prop1">而不是
<input type="text" ng﹎odel="prop1">

如果你实在是想使用或者需要使用原始数据类型的话,这有两种解决方法:

  1. 使用$parent.parentScopeProperty在子作用域中,这将会阻止子作用域创建自己的属性。
  2. 在父作用域中定义一个方法,并且在子作用域中调用,直接传递原始类型数据给父作用域(不总是一个可行的方式)。

JavaScript中的原型继承

首先需要有一个清晰牢固的理解对于JavaScript的原型继承,特别如果你是从后端转来的并且你更熟悉类继承。

我们先来回复一遍:
假设父作用域拥有属性aString,aNumber,aArray,anObject,and aFunction。如果子作用域原型继承自父作用域,那么我们就有:

(注意存储空间,我显示anArray对象以单个蓝色对象,有着3个值,而不是单个蓝色对象有着三个灰色相间隔的灰色字符排版)

如果我们试图从子作用域访问一个定义在父作用域上的属性,JavaScript将会首先在子作用域上查找,如果未找到则查找继承作用域,并且找到了那个属性(如果未在父作用域中找到则继续向上查找原型链,直到根作用域),所以这些表达式的值都是true:

childScope.aString === 'parent string'
childScope.anArray[1] === 20
childScope.anObject.property1 === 'parent prop1'
childScope.aFunction() === 'parent output'

如果我们接下来这样做:

childScope.aString = 'child string'

原型链就不在被查询,并且一个新的aString属性就被添加到了子作用域上。这个新的属性隐藏了父作用域上的同名属性。这点非常重要当我们接下来讨论ng-repeatng-include的时候。

假如我们接下来这么做:

childScope.anArray[1] = 22
childScope.anObject.property1 = 'child prop1'

这个原型链将被查询因为这些对象(anArray和anObject)没有在子作用域中找到。这些对象在父作用域中找到了并且属性值被更新了在原来的对象上。没有在子作用域上添加新属性,没有新的对象被创建(注意,在JavaScript中数组和方法也是对象)。

如果我们接下来这么做:

childScope.anArray = [100,555] childScope.anObject = { name: 'Mark',country: 'USA' }

这个原型链没有被查询并且子作用域获得了两个新的对象属性,并且隐藏了父作用域中的同名属性。

要点

  • 如果我们读取子作用域中的propertyX,并且子作用域拥有propertyX,那么原型链将不被查询。

  • 如果我们设置子作用域的propertyX属性的话,原型链也不会被查询。

最后一中情况:

delete childScope.anArray
childScope.anArray[1] === 22 // true

我们先删除了子作用域的属性,然后我们试图再次访问这个属性,那么原型链将被查询。

这里有一个例子你会看到以上的JavaScript原型继承的修改后的例子和他们的结果

AngularJS作用域继承

重点:
- 以下将会创建新的作用域,以原型继承的方式:ng-repeat,ng-include,ng-switch,ng-view,ng-controller,scope:true的指令,transclude:true的指令
- 下面的不会创建原型继承的作用域,scope:{...}的指令,这个创建隔离作用域。

注意,默认情况下指令不会创建新的作用域,也就是说默认的是scope:false

ng-include

假设我们在自己的控制器中有:

$scope.myPrimitive = 50;
$scope.myObject = {aNumber: 11};

以及我们的HTML:

<script type="text/ng﹖emplate" id="/tpl1.html"> <input ng﹎odel="myPrimitive"> </script>
<div ng                        

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读