一、问题场景

Angular的双向绑定给我们开发提供了很大的遍历,将父scope的引用变量作为参数传递给子指令,这样就可以方便的在父作用域内进行业务操作,数据变更会自动传递到子指令。但是如果你基于一个已有的复杂业务模块进行扩展开发,同时要将耦合其中一个功能提取为指令,这个时候就涉及到参数的传递问题。最简的方式就是直接将已有的根数据对象作为参数直接传递过去,参数携带数据大而全,指令内部肯定数据够用不会报错,但是缺点就是参数结构复杂,使用者无法准确的连接所需参数,极大地降低了指令的可用性;

二、问题分析

新开发的指令一般都是只传递需要的参数,一般结构形式比较简单,直接在原有的复杂结构中找到对应的字段直接赋值到新的参数即可;但是这里会涉及到一些非引用类型的字段,会给Angular的双向绑定带来问题;这就需要两者之间进行数据的同步更新,最简单的方式就是找到原来数据变更的地方,然后给指令的参数进行赋值即可,但是这种方式不仅繁琐容易出错,而且给以后的开发维护带来不便。

那么有没有更好的方式来解决这个问题呢,从代码的重构实践来说,最好将数据的变更封装在一个方法中,方便对数据字段的访问控制,那么js是否提供有相关的机制来实现字段的自定义settor和getter呢?

三、js的属性描述符

从ES5开始,所有的属性都具备了属性描述符。我们可以通过getOwnPropertyDescriptor获取属性的描述符信息,这个普通的对象属性对应的属性描述符可不仅仅只是一个字符串。它还包含另外三个特性:writable(可写)、enumerable(可枚举)和configurable(可配置)。

  var myObj ={
name:'mango'
}; descriptor = Object.getOwnPropertyDescriptor(myObj,'name');
console.log(descriptor); // {
// "value": "mango",
// "writable": true,
// "enumerable": true,
// "configurable": true
// }

在创建普通属性时属性描述符会使用默认值,我们也可以使用Object.defineProperty(..)来添加一个新属性或者修改一个已有属性(如果它是configurable)并对特性进行设置。我们使用defineProperty(..)给myOb添加了一个普通的属性并显式指定了一些特性。然而,一般来说我们不会使用这种方式,除非想修改属性描述符。

var myObj = {};
Object.defineProperty(myObj, 'name', {
value: 'apple',
writable: true,
configurable: true,
enumerable: true
}); //apple

writable决定是否可以修改属性的值。

var myObj = {};
Object.defineProperty(myObj, 'name', {
value: 'apple',
writable: false,
configurable: true,
enumerable: true
}); myObj.name='pear'
console.log(myObj.name) //apple

可以看到,我们对于属性值的修改静默失败(silently failed)了。如果在严格模式下,这种方法会出错,TypeError错误表示我们无法修改一个不可写的属性。

'use strict'

var myObj = {};
Object.defineProperty(myObj, 'name', {
value: 'apple',
writable: false,
configurable: true,
enumerable: true
}); myObj.name='pear'
console.log(myObj.name) // Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'

通过configurable可以控制是否可以修改属性描述符,同时会限制不能删除属性;

enumerable控制这个属性是否会出现在对象的属性枚举中,比如说for..in循环。如果把enumerable设置成false,这个属性就不会出现在枚举中,虽然仍然可以正常访问它。相对地,设置成true就会让它出现在枚举中。

在ES5中可以使用getter和setter部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter是一个隐藏函数,会在获取属性值时调用。setter也是一个隐藏函数,会在设置属性值时调用。当你给一个属性定义getter、setter或者两者都有时,这个属性会被定义为“访问描述符”(和“数据描述符”相对)。对于访问描述符来说,JavaScript会忽略它们的value和writable特性,取而代之的是关心set和get(还有configurable和enumerable)特性。

var myObj = {
_no:0,
get no(){
return this._no;
},
set no(val){
this._no = val;
}
} Object.defineProperty(myObj, 'name', {
get:function(){
return 'mango' + this.no;
}
}); console.log(myObj.no);
console.log(myObj.name) myObj.no = 3
console.log(myObj.name) // 0
// mango0
// mango3

四、解决方案

通过了解js提供的属性描述符机制,我们可以通过defineProperty来给需要同步的字段添加getter和setter访问控制器,实现方式如下

    function addPropertyControl(obj, property, syncObj, syncProperty) {
syncProperty = syncProperty ? syncProperty : property;
var dProperty = '_' + property;
obj[dProperty] = obj[property];
Object.defineProperty(obj, property, {
get: function () {
return obj[dProperty];
},
set: function (value) {
syncObj[syncProperty] = value;
obj[dProperty] = value;
}
});
} function autoSyncDataModel() {
var sObj = $scope.dataModel;
var syncObj = $scope.option;
addPropertyControl(sObj, 'name', syncObj);
addPropertyControl(sObj, 'parents', syncObj);
addPropertyControl(sObj, 'age', syncObj);
addPropertyControl(sObj, 'isMan', syncObj);
}

原文地址

使用defineProperty实现自定义setter, 简化前端Angular的重构工作的更多相关文章

  1. 怎样使用自定义标签简化 js、css 引入?

    国庆将至,工作兴致全无,来总结点项目里平时不起眼干货. 前端引入 js .css 一般是这样: <script type="text/javascript" src=&quo ...

  2. AutoHotKey (AHK) 按键表+自定义快捷键简化操作的教程

    自定义快捷键简化操作的教程 ① 下载安装AutoHotKey,并用记事本新建一个MyHotKey.ahk文件,录入如②中信息 ② 下图可以实现,按F6即可触发“Ctrl+C”的复制快捷键,同理F7可实 ...

  3. abp.zero 9.0框架的前端Angular使用说明

    abp.zero 9.0框架的前端Angular使用说明 目录 abp.zero 9.0框架的前端Angular使用说明 摘要 1 部署及启动 1.1 依赖包安装 1.2 使用yarn安装依赖包 1. ...

  4. 用脚本来简化iOS美术同学的工作

    用脚本来简化iOS美术同学的工作 问题 我们知道,在 iOS 开发中,为了使我们的 app 能够同时支持 iPhone 的 Retina 屏幕和普通屏幕,美术同学需要对 UI 设计稿中的每个元素进行 ...

  5. 想要入行web前端要知道web前端的的基本工作职责

    入一行,要先知一行 ”:我们来看看web前端开发职位 无论什么门派都要做到的一些基本工作职责 首先,你必须是一个合格的“页面仔”,这个叫法不好听,但很生动: 我们都知道,所有呈现的内容都是基于HTML ...

  6. 前端 angular 和 bootstrap 的安装步骤

    1.安装bower模块: npm install -g bower --registry=http://registry.npm.taobao.org 2.创建.bowerrc 文件存放 前端相关的模 ...

  7. 利用js里的Dom和Date,自定义cookie的前端设置方法

    通过浏览器访问url时候浏览器会携带cookie,可利用cookie进行信息验证如用户验证,cookie前后端都可获取设置,后端用self.get_cookie和self.set_cookie,前端可 ...

  8. webpack + vue 项目 自定义 插件 解决 前端 JS 版本 更新 问题

    Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 它的异步加载原理是,事先将编译好后的静态文件,通过js对象映射,硬编 ...

  9. Django模版语言自定义标签-实现前端 关联组合过滤查询

    前端关联 组合过滤查询 实现效果如图: models.py 创建表代码 from django.db import models # Create your models here. class Le ...

随机推荐

  1. SpringCloud Stream整合RabbitMQ3.5.0

    前言 点击进入Spring官网文档 本文章为单体项目,将消费者和生产者写在同一个项目中,介意者不用向下看了. 本文介绍三种应用方式: 1:普通整合RabbitMQ 2:消息分区 3:按条件消费(多个消 ...

  2. python进阶(6)深拷贝和浅拷贝

    深拷贝和浅拷贝 不管对于浅拷贝.还是深拷贝,针对不可变对象str.int.tuple(有点特殊).boolean,它的内存地址是不变的,拷贝的仅仅是值 import copy a = 1 b = co ...

  3. 缓存cache和缓冲区buffer

    一.cache 1.cache的定义.从宏观上讲,缓存是处理速度不匹配的问题.可以是静态缓存(内存缓存.磁盘缓存).动态缓存(前端的缓存)和数据库缓存.另一个角度,从CPU来看,可以是寄存器和内存之间 ...

  4. token、cookie和session区别以及django中的cookie,csrf

    参考:https://my.oschina.net/xianggao/blog/395675?fromerr=GC9KVenE [前言]登录时需要post的表单信息. 先跳过具体案例,讲解基础知识: ...

  5. vue打开新窗口并且实现传参,有图有真相

    我要实现的功能是打开一个新窗口用来展示新页面,而且需要传参数,并且参数不能显示在地址栏里面,而且当我刷新页面的时候,传过来的参数不能丢失,要一直存在,除非我手动关闭这个新窗口,即浏览器的标签页. 通过 ...

  6. windows 之间内网开启远程桌面连接

    win7设置远程桌面1.找到我的电脑\计算机图标,右键"属性"如图2.进入系统和安全设置-选项卡中,找到"远程设置"右上角位置点击打开3.在随后的"系 ...

  7. java基础:数据类型拓展

    public static void main(String[] args) { //单行注释 //输出hello,world! //System.out.println("hello,wo ...

  8. [笔记] 扩展Lucas定理

    [笔记] 扩展\(Lucas\)定理 \(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P} ...

  9. 关于Python编写时候的一些数据格式调用问题

    utf-8 可变长度字符串,互联网通用,目的是减少内存占用Unicode 万国码, 对于英文多占用一个字节ASCII码 美国编码1个字节Gb2313 中国编码 编码 encode解码 decodepy ...

  10. Windows系统添加虚拟串口及CanToolApp功能1的实现

    项目开始尝试用com0com添加虚拟串口,但是遇到了问题,系统中可以看到添加的虚拟串口,但是用C#无法获取串口.经过多次尝试后,决定换用Virtual Serial Port Driver添加虚拟串口 ...