Js对象属性的特性 和defineProperty方法

更新日期: 2019-10-19阅读: 1.9k标签: 特性

对象是无序属性的集合,而这些属性在创建是都带有一些特征值(可以理解为属性的属性,天生自带的),这些特征值是为了实现JavaScript引擎用的,因此JavaScript不能直接访问。

JavaScript通过这些特征值来定义属性的行为(属性是否删除,枚举,修改等)。

例如,在全局定义的属性是会挂载到window上的。当想删除window上的这个属性,是不可以的。也就是说window上的属性是不可配置的。delete window.obj     //false  

Function.prototype当你修改成其他值,其原始值并没有改变。是不可写的。

在比如,我们的for in是可以枚举原型链上属性的,但所有的原型顶端都是Object.prototype.但for in 并没有枚举出来。所以Object.prototype是不可枚举的。

属性分为两种类型:1数据属性 2访问器属性。例如:一般我们自己在对象设置的属性默认是数据属性,而Window上的那么属性是访问器属性。

怎样知道这个属性到底是数据属性还是访问器属性?

使用Object.getOwnPropertyDescriptor(属性所在的对象,属性)方法。 返回一个对象,当时访问器属性时,该对象属性有enumerable,configurable,get,set。当时数据属性,该对象返回的属性有value,writable,enumerable,configurable.

var obj  = {name:'zwq',age:18};
console.log(Object.getOwnPropertyDescriptor(obj,'name'));  //name属性属性
//{value: "zwq", writable: true, enumerable: true, configurable: true}

console.log(Object.getOwnPropertyDescriptor(window,'name'));  //window上的name属性时访问器属性
//enumerable: true, configurable: true, get: ƒ, set: ƒ}

数据属性

数据上行包含一个数据值的位置,可以读取和写入值,数据属性有4个描述其行为的属性,由于是这些值不能直接访问,是内部值,所以该规范把他们放在两对括号中。

  • 属性是否可配置:[[Configurable]]:表能否通过delete删除属性,能够修改属性的特性,能否把属性修改为访问器属性
  • 属性是否可枚举:[[Enumerable]]:表能否通过for-in循环返回属性
  • 属性是否可修改:[[Writable]]
  • 属性的数据值 :[[value]]读取属性的时候,从这个位置读,写入属性的时候,把新值保存到这个位置。

普通定义的属性 默认值前三个都是true,最后一个是undefined。

当我们想到修改属性默认的特性,使用Object.defineProperty(属性所在对象,属性的名字,描述符对象)方法。

当使用Object.defineProperty方法第二个参数属性的名字不存在时,该方法会创建这个属性,并且该属性的特性除了value剩下的特性的默认值都是false。也就是说当你想让这个用Object.defineProperty方法创建的属性跟正常的属性一样可枚举,配置,写入,必须把这个属性值的特性都改为true。否则就是false。

var obj  = {name:'zwq',age:18};
Object.defineProperty(obj,'name',{ 修改name属性的特性,值为haha,并且name属性不能修改值
     value:'haha',
     writable:false  //默认值是true,改为false,不可写。
})
Object.defineProperty(obj,'sex',{创建一个sex属性,这个属性不可枚举
     value:'woman',
     writable:true,
     configurable:true,
})


访问器属性

访问器属性不包含writable和value,他包含的是一对getter和setter函数,在读取访问器属性是,会调用getter函数,并返回有效的值,在写入访问器属性时(修改属性)会调用setter函数并传入新值。访问器包含4个特性

  • 属性是否可配置:[[Configurable]]:表能否通过delete删除属性,能够修改属性的特性,能否把属性修改为访问器属性
  • 属性是否可枚举:[[Enumerable]]:表能否通过for-in循环返回属性
  • [[Get]]:在读取属性时调用的函数。默认值是undefined。
  • [[Set]]:在写入(或修改)属性时调用的函数。默认值undefined。

定义访问器属性,同样也必须商用Object.defineProperty().

function Person(){
    this._name = 'zwq',
    this.age =  18
}
var person = new Person();

Object.defineProperty(person,'name',{
    set(newValue){
        console.log('set');
        this._name = newValue   //设置或修改属性时,会调用set函数,把设置的值通过参数传进去后,用一个变量或属性保存。并且当调用get,return就是返回的这个值
    },
    get(){
        return this._name;   //当读取属性时 返回return的值
    }
    
})

不一定非要同时指定getter和setter,只指定getter意味着属性是不能写。

vue的双向数据劫持绑定(主要应用于表单中)的原理就是利用Object.defineProperty来检测数据的变化。

双向劫持绑定时当视图(页面的某一元素)发生改变时,数据跟着改变,当数据改变时,视图也跟着改变。例如下面的输入框里面的内容改变时,数据(对象或数组)改变。检测数据改变。底下的div文本根据数据的改变而改变。

上面我们介绍到,当数据改变时会触发set方法。由此我们就可以检测数据的变化。

<input type="text"id="Oinput"><div id="view"></div>
var input = document.getElementById('Oinput');
var view = document.getElementById('view');

var data = {
    valueObj :{
        value:'zwq'
    }
}
//当输入框数据发生改变时,数据跟着改变
input.oninput = function(){
    data.valueObj.value = this.value;
}

// 更新视图
function upData(){   
    view.innerText = data.valueObj.value;
}

upData(data);
obServe(data);

// 监控某个对象是否发生改变
function obServe(data){
   //判断当前传的是否是对象,如果不是,直接return
            if(!data || !(data instanceof Object)){return data}
       //获取所有属性名。使用keys方法可以获取所有属性名(包括原型上的)并保存带数组中
            var arrProperty = Object.keys(data);
       //遍历数组,调用defindRective检测每一个属性值的改变 
            arrProperty.forEach(function(key){
          defindRective(data,key,data[key]); //传入3个参数,当前对象,当前属性,当前属性值
    })
}

function defindRective(obj,key,val){
   obServe(val);   //使用递归,当想上面的数组,对象套对象的形式,由于里面的对象是一个引用值,无法检测里面的数据变化,所以使用递归。
    Object.defineProperty(obj,key,{  //核心:使用Object,definPropert的set检测数据的改变。
        set(newValue){
            console.log(5);
            if(newValue == val) return val;
            val = newValue;
            upData();   //当数据变化,跟新视图
        },
        get(){
            return  val;
        }
    })
}



 

 

链接: https://www.fly63.com/article/detial/6511

CSS新特性contain,控制页面的重绘与重排

contain 属性允许我们指定特定的 DOM 元素和它的子元素,让它们能够独立于整个 DOM 树结构之外。目的是能够让浏览器有能力只对部分元素进行重绘、重排,而不必每次都针对整个页面。

Html5、Css3、ES6的新特性

Html5的新特性语义化标签:有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重。表单新特性,多媒体视频(video)和音频(audio)

ES6新特性--var、let、const

var不存在块级作用域,具有变量提升机制。 let和const存在块级作用域,不存在变量提升。在同一作用域内只能声明一次。const在声明时需要赋值且无法修改,但如果常量是对象,则对象的属性可以修改。

Js即将到来的3个新特性

Optional Chaining(可选链式调用);Nullish coalescing(空值合并);Pipeline operator(管道运算符)通过三个函数对字符串进行处理;

Angular 8的新特性介绍

在今天早些时候Angular团队发布了8.0.0稳定版。其实早在NgConf 2019大会上,演讲者就已经提及了从工具到差分加载的许多内容以及更多令人敬畏的功能。下面是我对8.0.0一些新功能的简单介绍,希望可以帮助大家快速了解新版本

使用 React 要懂的 Js特性

与我使用的其他框架相比,我最喜欢 React 的原因之一就是它对 JavaScript 的暴露程度。没有模板DSL( JSX 编译为合理的 JavaScript),组件 API 只是通过添加 React Hooks 变得更简单,并且该框架为解决的核心 UI 问题提供非常少的抽象概念

ES2019 新特性汇总

最近 ECMAScript2019,最新提案完成:tc39 Finished Proposals,我这里也是按照官方介绍的顺序进行整理,如有疑问,可以查看官方介绍啦~另外之前也整理了 《ES6/ES7/ES8/ES9系列》,可以一起看哈。

Js的用途和特性

JavaScript 最初的目的是为了“赋予网页生命”。这种编程语言我们称之为脚本。它们可以写在 HTML 中,在页面加载的时候会自动执行。脚本作为纯文本存在和执行。它们不需要特殊的准备或编译即可运行。

十个超级实用的 JS 特性

你可能刚上手 JavaScript,或者只是曾经偶尔用过。不管怎样,JavaScript 改变了很多,有些特性非常值得一用。 这篇文章介绍了一些特性,在我看来,一个严肃的 JavaScript 开发者每天都多多少少会用到这些特性

解密HTTP/2与HTTP/3 的新特性

HTTP/2 相比于 HTTP/1.1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何优雅降级应该是国内还不普遍使用的原因之一。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!