js笔记 基础篇(七)Object.defineProperty与数据劫持

26 篇文章 0 订阅
20 篇文章 1 订阅

es5 (Object.definePropety)

我们先来了解一下Object.defineProperty,这个方法是es5中提出用来限制用户对对象属性与方法的操作。其实在js内部的对象中有很多地方都是限制用户操作的。例如:

var obj = {}
console.log(obj.__proto__);
/* 	constructor: ƒ Object()
	hasOwnProperty: ƒ hasOwnProperty()
	isPrototypeOf: ƒ isPrototypeOf()
	propertyIsEnumerable: ƒ propertyIsEnumerable()
	toLocaleString: ƒ toLocaleString()
	toString: ƒ toString()
	valueOf: ƒ valueOf()
	__defineGetter__: ƒ __defineGetter__()
	__defineSetter__: ƒ __defineSetter__()
	__lookupGetter__: ƒ __lookupGetter__()
	__lookupSetter__: ƒ __lookupSetter__()
	get __proto__: ƒ __proto__()
	set __proto__: ƒ __proto__()       */
	//有这么多的属性  但是。。。
for (var ele in obj.__proto__) {
	console.log(ele);    // undefined
}

what?? 因为该对象中的属性,不可枚举,这可以通过Objetc.defineProperty设置:

var obj = {
	name: 'oldDeng'
}
					//设置哪个对象   哪个属性
//Object.defineProperty(obj,         'age',   {
//描述符
//	value: 18,           //属性值
//	writable: true,      //是否可写
//  enumerable: true,    //是否可枚举
//  configurable: true	 //是否可配置
//})
//这里要注意只要用defineProperty进行设置的属性三个描述符默认都是false
//例子
Object.defineProperty(obj, 'age', {
//描述符
	value: 18,           //属性值
});
for (var ele in obj) {
	console.log(ele);  //只有name
}
obj.age = 22;
console.log(obj.age); // 依然是  18

delete obj.age;
console.log(obj.age); // 18  并没有删除掉
//obj的age属性不可枚举,不可配置(就是删除),不可写

ok,Object.defineProperty可以利用描述符对对象的属性进行相关的配置,是否可枚举(enumerable),是否可写(writable),是否可配置(configurable),
一定要注意三个属性默认都是false,在这里我就不多做实验了。
那这玩意和数据劫持有啥关系呢?当然Object.defineProperty不只有这几个描述符,还有两个最重要的东西,getter,setter。怎么用呢?有啥用呢?上代码

var obj = {
	name: 'oldLiu'
}
var value = 18;
Object.defineProperty(obj, 'age', {
	get () {
		console.log('来读取了');
		return value   // 这里的返回值就是当你obj.age的值
	},
	set (newValue) {   // 这里接受的参数就是当你obj.age = xx 的 xx
		console.log('数据更新了');
		value = newValue;
	},
	//如果你想此属性可配置,可枚举,别忘了enumerable与configurable
	//当使用get和set时value与writable不能使用了因为使用get与set就默认此属性可写了,value肯定也是动态给的
	enumerable: true,    
    configurable: true	
});
console.log(obj.age) //来读取了   18
obj.age = 22         // 数据更新了  22

ok这就是getter与setter的具体用法,要注意的是,当使用get和set时value与writable不能使用了因为使用getter与setter就默认此属性可写了,value肯定也是动态给的。
每次读取值时get都会执行一次,每次赋值时set都会执行一次,我们就要在这里做文章。

数据劫持

数据劫持听起来好像高大上的样子,其实就是当一个属性值改变时我们可以监听到。
说到数据劫持的应用最经典的肯定时vue的双向数据绑定。我们就来简单的模拟一下:

  • html代码部分
	<html>
		<body>
			<input type="text" id="demo" />
			<p id="show"></p>
		</body>
	</html>

css部分就不在这里写了呢。。。

  • js部分
  • 首先我们要获取两个标签
	var oIput = document.getElementById('demo');
	var oP = document.getElementById('show');
  • 初始化数据
    • 要绑定哪个对象
	var oData = {
		value: 'hi'
	}

  • 标签绑定相应事件
	oInput.oninput = function () {
		oData.value = this.value;
	}

	function upDate () {
		oInput.value = oData.value;
		oP.innerHtml = oData.value;
	}
	upDate();
  • 监控函数
	function Observer (data) {
		//如果要监控的属性的层级觉深可以递归
		if (!data || typeof data !== 'object') return data;
		//便利对象的key进行监控
		Object.keys(data).forEach(function (key) {
			watchValue(data, key, data[key]);
		});
	}

	function watchValue (data, key, val) {
		//先监控一下 如果val是引用值则递归下去
		Observer(val)
		Object.defineProperty(data, key, {
			get () {
				return val;
			},
			set (newVal) {
				// 两次的值相等则不更新
				if (val === newVal) return;
				val = newVal
				upDate()
			}
		})
	}
	Observer(oData)

ok,这样数据劫持就做完了,当然只是简单的模拟,效果还是ok的可检测对象的深层属性,不过这个方法对数组的pop呀.push这些方法,没法检测,不过那就不在今天的讨论范围之内了。
gitHub地址:https://github.com/lifei5859/Observer.git
demo展示地址:http://www.fgdemoshow.cn/smallDemo/js/Observer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值