一、问题场景

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. Django之csrf中间件及auth模块使用

    目录 一.基于配置文件的编程思想 1. importlib 模块 2. 配置文件 二.跨站请求伪造(csrf) 1.csrf简介以及由来 2.Django中的csrf中间件如何使用 2.1 普通for ...

  2. 第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)

    静态代理  package com.kuang.demo03; //静态代理模式总结 //真实对象和代理对象都要实现同一个接口 //代理对象要代理真实角色 //好处:  //代理对象可以做很多真实对象 ...

  3. finally会执行吗:try/catch的测试

    翻译练习 原博客地址:Will it finally: a try/catch quiz 你知道try和catch是怎么工作的,但是你知道finally是怎么工作的吗?它是在抛出异常后执行还是在ret ...

  4. Python 过滤字母和数字

    [前言]在写爬虫时,正则表达式有时候比较难写,一个是自己不熟练,二者数据分析提取数据千奇百怪. 一.好在python有个re模块,提供了很多更加简便的方法:可参考此文档:https://www.cnb ...

  5. Kubernetes-5.Pod资源控制器(1)

    docker version:20.10.2 kubernetes version:1.20.1 本文概述Kubernetes Pod资源控制器的ReplicaSet.Deployment.Daemo ...

  6. 后端程序员之路 28、一个轻量级HTTP Server的实现

    提到http server,一般用到的都是Apache和nginx这样的成熟软件,但是,有的情况下,我们也许也会用一些非常轻量级的http server.http server的c++轻量级实现里,M ...

  7. c++类的简介

    一 类的定义 在c++中,我们使用"类"来描述"对象",可以说"类"的实现是c++OOP的核心. 类中包括对象的"属性" ...

  8. SSAS表格模型

    Analysis Services 是在决策支持和业务分析中使用的分析数据引擎 (Vertipaq) . 它为商业智能提供企业级语义数据模型功能 (BI) .数据分析和报告应用程序,如 Power B ...

  9. 【Arduino学习笔记08】使用串口监视器显示数据

    代码及相关说明: 1 // 示例:读取模拟输入并显示在串口监视器中 2 3 const int ANALOG_IN = 0; 4 int val = 0; 5 6 void setup(){ 7 Se ...

  10. C#中事件流程的简单理解

    C#中事件流程的简单理解 C#中事件基于委托,要理解事件要先理解委托,但是现在我还没想好怎么写委托,如果不懂委托可以先找找委托的文章 事件基于委托,为委托提供了一种发布/订阅机制 一上来就是这句话,很 ...