使用defineProperty实现自定义setter, 简化前端Angular的重构工作
一、问题场景
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的重构工作的更多相关文章
- 怎样使用自定义标签简化 js、css 引入?
国庆将至,工作兴致全无,来总结点项目里平时不起眼干货. 前端引入 js .css 一般是这样: <script type="text/javascript" src=&quo ...
- AutoHotKey (AHK) 按键表+自定义快捷键简化操作的教程
自定义快捷键简化操作的教程 ① 下载安装AutoHotKey,并用记事本新建一个MyHotKey.ahk文件,录入如②中信息 ② 下图可以实现,按F6即可触发“Ctrl+C”的复制快捷键,同理F7可实 ...
- abp.zero 9.0框架的前端Angular使用说明
abp.zero 9.0框架的前端Angular使用说明 目录 abp.zero 9.0框架的前端Angular使用说明 摘要 1 部署及启动 1.1 依赖包安装 1.2 使用yarn安装依赖包 1. ...
- 用脚本来简化iOS美术同学的工作
用脚本来简化iOS美术同学的工作 问题 我们知道,在 iOS 开发中,为了使我们的 app 能够同时支持 iPhone 的 Retina 屏幕和普通屏幕,美术同学需要对 UI 设计稿中的每个元素进行 ...
- 想要入行web前端要知道web前端的的基本工作职责
入一行,要先知一行 ”:我们来看看web前端开发职位 无论什么门派都要做到的一些基本工作职责 首先,你必须是一个合格的“页面仔”,这个叫法不好听,但很生动: 我们都知道,所有呈现的内容都是基于HTML ...
- 前端 angular 和 bootstrap 的安装步骤
1.安装bower模块: npm install -g bower --registry=http://registry.npm.taobao.org 2.创建.bowerrc 文件存放 前端相关的模 ...
- 利用js里的Dom和Date,自定义cookie的前端设置方法
通过浏览器访问url时候浏览器会携带cookie,可利用cookie进行信息验证如用户验证,cookie前后端都可获取设置,后端用self.get_cookie和self.set_cookie,前端可 ...
- webpack + vue 项目 自定义 插件 解决 前端 JS 版本 更新 问题
Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 它的异步加载原理是,事先将编译好后的静态文件,通过js对象映射,硬编 ...
- Django模版语言自定义标签-实现前端 关联组合过滤查询
前端关联 组合过滤查询 实现效果如图: models.py 创建表代码 from django.db import models # Create your models here. class Le ...
随机推荐
- springboot项目打包成jar包在Linux服务器默认80端口运行
springboot项目端口设置 在application.properties文件 server.port=80 在application.yml文件 server: port: 80 然后在ide ...
- Vue3.0+Electron聊天室|electron跨平台仿QQ客户端|vue3.x聊天应用
基于vue3+electron11跨端仿制QQ桌面应用实战Vue3ElectronQchat. 使用vue3+electron+vuex4+ant-design-vue+v3scroll+v3laye ...
- 微信支付 V3 的 Java 实现 Payment Spring Boot-1.0.7.RELEASE 发布
Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 功能特性 实现微信支 ...
- Python3.x 基础练习题100例(61-70)
练习61: 题目: 打印出杨辉三角形. 程序: if __name__ == '__main__': a = [] for i in range(10): a.append([]) for j in ...
- golang-Zap和Go Logger日志库
目录 在Go语言项目中使用Zap日志库 介绍 默认的Go Logger日志库 实现Go Logger 设置Logger 使用Logger Logger的运行 Go Logger的优势和劣势 优势 劣势 ...
- Redis工具收费后新的开源已出现
作者:三十三重天 博客: zhouhuibo.club 引言 Redis工具哪家强,中国山东找蓝翔.哎呀,串台了. 众所周知,开源的最终还是收费. Reids Desktop 秉承了这一理念,苦逼的程 ...
- Java 语言基础 (初识Java语言, 变量和数据类型, 运算符, 流程控制语句, 数组)
初始 Java 语言 Java SE -- Java Platform, Standard Edition 是 Java 平台的基础 Java SE 以前称为 J2SE, 可以编写桌面应用和基于 we ...
- Java 多线程 | 并发知识问答总结
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- 使用docker搭建sonarqube
sonarqube是一款代码质量检查工具,使用sonar扫描我们写过的代码,可以有助于检查出代码的bug.规范性和健壮性,有助于提高我们的代码质量. 一.安装docker 安装完成之后,命令行输入 d ...
- 了解 Vue 的 Compsition API
在这篇文章中,我将讲讲 Vue 的 Composition API 为什么比之前的 Options API 要好,以及它是如何工作的. Options API 有什么问题 首先,这里不是要大家放弃 O ...