面试官或许也会要求你用某函数实现js下的数据双向绑定,可是这个函数的用法你了解吗,对象的某些内部属性不能直接访问时,你需要使用哪个函数呢,内部属性又包括哪些呢?带着这些疑问,继续往下读吧~
js中通常使用一些内部特性来描述属性的特征,这些特性是由为JS实现引擎的规范定义的,开发者不能在javascript中直接访问这些内部特性,比如:[[Enumerable]]。属性有两种,数据属性和访问器属性。
- 首先,数据属性包含一个保存数据值的位置,4个特性来描述数据值的行为。
[[configure]]: 表示属性是否可通过delete删除,并重新定义,是否可修改特性,默认情况均true。
[[Enumerable]]: 表示属性是否可通过for-in循环返回
[[Writable]]:属性值可否修改
[[Value]]:属性值
如果显示创建一个对象,将属性添加到对象,如下:意味着四个属性均为false。
let person = {
name: "liujie"
}
如果想修改属性的值,必须使用Object.defineProperty(obj,attr,3)方法(注意这里,当obj给定attr属性,即obj.attr=“aaaa”,只有修改obj的值时才调用该函数才生效,后面双向绑定会用到该函数),它接受三个属性,1:obj是要为其添加属性的对象,2:attr属性名称,3:属性描述符,如下:
Object.defineProperty(person, "name", {
writable: false,
value: "liyinhe"
})
console.log(person);//liyinhe
由于设置的属性configure为false,说明该属性值person.name为只读,不可修改,你也可尝试去修改,发现name不会变。
为属性值重新赋值被忽略。
类型的规则也可用于创建不可配置的属性,比如设置为configurable:false,属性不可从对象中删除。
- 访问器属性
访问器属性不包括数据值,他们包含一个getter和setter函数,在读取访问器属性时,调用getter函数,该函数的责任就是返回一个有效的值; 在写入访问器属性时,会调用setter值并传入新值。
访问器属性有4个特性描述他们的行为,
[[configurable]]
,[[Enumerable]]
[[Get]]
,[[Set]]
访问器属性不能直接定义,也必须使用Object.defineProperty(),见下面例子:
注意;year_常用来表示该属性不希望在对象方法外部被访问,而year则定义为访问器属性,这里设置year值导致内部sex也变化,这是典型的访问器属性的访问场景。
let baby = {
year_: 2002,
sex: 1
};
Object.defineProperty(baby, "year_", {
get() {
return this.year_;
},
set(newVal) {
if (newVal) {
this.year_ = newVal;
this.sex += newVal;
}
}
})
baby.year = 2011;
console.log(baby.sex);
- 另外还可在一个对象上定义多个属性。
- 使用Object.defineProperty实现双向绑定
先简单说一下什么是双向数据绑定,就是用户更新view时,Model的数据也会自动更新,而JavaScript代码更新Model时(输入框),View就会自动更新(h2),这就是双向数据绑定。
具体效果如图,在输入框中输入字符,在下面h2标签中渲染出对应文字,单向绑定实现。
在浏览器中改变obj.val的值,对应输入框和h2的值相应改变。
思路:首先在html中把输入框和h2节点写出来,script中获取对应节点,对input进行keyup监听,当键盘输入时,触发对应事件,给obj.val赋值为键盘输入的值(input模型->h2视图,类似需要操作的后台数据),即e.target.value。以后只有当键盘输入obj.val需要修改时,才调用Object.defineProperty,将输入框的值通过set赋值(键盘输入的值赋给input和h2),代码如图所示:
get函数可获取obj.val的值,对双向绑定没什么用,
console.log的值是测试时加入的,可帮你看清什么时候调用了函数。
具体代码:通过get函数,当你在后台对obj.val修改时触发该函数,
input_v = document.querySelector("#input_v");
h_v = document.querySelector("#h_v");
var obj = {};
function defineProperty(obj, val) {
console.log('``````````````````'); //step2
var val;
Object.defineProperty(obj, "val", {
set: function(val) {
input_v.value = val;
h_v.innerHTML = val;
console.log('4444');//当input的值改变时才触发object.defineProperty的set函数。
},
get: function(val) {
return val
}
})
console.log('3333'); //step3
}
console.log('2222'); //step1
defineProperty(obj, 'val');
console.log('1111111111111111'); //step4
input_v.addEventListener('keyup', function(e) {
console.log(e.target.value);
obj.val = e.target.value;
});