直切主题

今天遇到一个这样的功能:

  • 写一个函数,该函数传递两个参数,第一个参数为返回对象的总数据量,第二个参数为初始化对象的数据。如:
var o = obj (4, {name: 'xu', age: 21})   //  返回了一个能容纳4条数据的对象,初始数据为name:'xu'和age: 21
  • 返回的该对象总会有以下属性:overLength(数据容纳量)、size(当前数据条数)
  • 返回的对象应该有以下方法:cache(保存一条数据)、delete(删除一条数据)
  • 每一次引用某属性后,该属性值消失。如:
o.name // xu
o.name //undefined
o.size //

那么问题来了,如何设置属性在使用一次后自动消除呢,经过思考,想到了,get和set方法,get和set又是什么呢,如下:

var o = {
_id: 11,
get id () {
return this._id + '_get'
},
set id (value) {
this._id = value + '_set'
}
} console.log(o.id) // 11_get
o.id = '666'
console.log(o.id) // 666_set_get

js中引用属性的值视为get,给属性赋值视为set,get和set方法可以在获取/设置属性值时进行一定的操作。

本文中所用到了get和set方法,不过并不是上述例子那样简单的在对象中书写,我们借助了本文的主角Object.defineProperty方法。

什么是Object.defineProperty

Object.defineProperty是es5新加的给对象属性设置描述符的方法,使用方法如下:

Object.defineProperty(obj, prop, descriptor)  // 对象、属性、描述符

基本的描述符有3个:

  • writable  --  是否为可写
  • configurable  --  是否为可配置的
  • enumerable  --  是否为可枚举的

下面分别举个简单的例子来说明其用法

writable

顾名思义,设置属性是否为可写,如果是false,则属性之后的赋值操作无效

var o = {
name: 'xu'
}
Object.defineProperty(o, 'name', {
writeable:false
})
o.name = 'lee'
console.log(o.name) //xu

configurable

属性是否可配置,设置为false后,该属性不可被删除,也不可再更改为可配置的,但是可以从可写改为不可写

var o = {
name: 'xu'
}
Object.defineProperty(o, 'name', {
configurable:false
})
o.name = 'lee'
console.log(o.name) // lee 不可配置可写
delete o.name
console.log(o.name) //lee 删除失败
Object.defineProperty(o, 'name', {
writable: false
})
o.name ='li'
console.log(o.name) // lee 不可配置不可写

enumerable

属性是否可枚举,如果是false,则属性不可枚举,不可枚举属性对  for ... in语句和Ojbect.keys是不可见的。

var o = {
name: 'xu',
age: 21
}
Object.defineProperty(o, 'name', {
enumerable: false
})
console.log(Object.keys(o)) //["age"]

分界线----------------------------------------------------------------------------

除了上面三个属性,defineProperty方法内部还可以定义属性的value值, get/set方法,那么本章则用到了使用Object.defineProperty方法定义属性的get/set值。

问题解答

思路:本题主要围绕着属性的get/set做进一步处理,要求引用一次属性值后,属性值消失(undefined),那么就需要在get方法中做文章,所以我们先制定一个定义属性描述符的方法,我把它定义成这样:

var _defineProperty = function (ret, key) {
Object.defineProperty(ret, key, {
set: function (value) {
// 针对 o.key = value 的set方法
if (!datas[key]) {
ret.size++
}
datas[key] = value
},
get: function () {
// 获取当前数据,如果当前数据有值,返回值并将当前属性值设置为undefined
var res = undefined
if (typeof datas[key] !== undefined) {
res = datas[key]
ret.size--
datas[key] = undefined
}
return res
}
})
}

本题的主要部分就在这里,这段代码利用的属性的get和set方法,针对题目的要求,做出了这个功能函数。注意:返回的对象ret并没有保存数据,他只是通过set和get方法对datas缓存对象中的数据进行的设置和读取。

datas对象是这样的,他利用的es6中的Object.assign方法,把init拷贝了一份作初始化

//  缓存数据
var datas = Object.assign({}, init)

整个代码就在这里,也很简单,写的也比较乱。如果有问题,请指出。

function FirstVaild (overLength, init) {

  //  定义最终返回对象,初始两个值,一个对象总容量,一个是当前长度
var ret = {
overLength: overLength,
size: Math.min(Object.keys(init).length, overLength) //如果传入初始数据条数大于容量,取容量值
}
// 缓存数据
var datas = Object.assign({}, init) // 定义属性的函数
var _defineProperty = function (ret, key) {
Object.defineProperty(ret, key, {
set: function (value) {
// 针对 o.key = value 的set方法
if (!datas[key]) {
ret.size++
}
datas[key] = value
},
get: function () {
// 获取当前数据,如果当前数据有值,返回值并将当前属性值设置为undefined
var res = undefined
if (typeof datas[key] !== undefined) {
res = datas[key]
ret.size--
datas[key] = undefined
}
return res
}
})
} // 将dirty初始化false,并定义每个属性的get/set
Object.keys(init).slice(0,ret.size).map(function (key) {
_defineProperty(ret, key)
}) Object.assign(ret, {
cache: function (key ,value) {
if (this.size >= this.overLength) {
throw '内存已满,请扩展容量'
}
// 属性不存在,定义他,并且长度+1, 属性存在但值不存在,长度+1,
if (!(key in datas)) {
_defineProperty(this, key)
this.size++
} else if (!datas[key]) {
this.size++
}
// 不论怎样,新值覆盖旧值
datas[key] = value
return this
},
// 删除属性直接把datas中的属性设置为undefined
delete: function (key) {
datas[key] = undefined
this.size--
return this
}
})
return ret
}

本章就到这里,博主为一介前端菜鸟,并没有多少知识,try my best,写点基础知识,分享给正在学习前端的新人们。

javascript之Object.defineProperty的奥妙的更多相关文章

  1. JavaScript使用Object.defineProperty方法实现双数据绑定

    Object.defineProperty这个方法非常值得学习,很多mvc框架中的双向数据绑定就是通过它来实现的. 本着互联网分享精神,今天我就将我自己的见解分享给大家,希望能有所帮助. 开始使用 O ...

  2. javascript 之 Object.defineProperty

    语法: Object.definePropty(obj,prop,descriptor); 参数: obj:要在其上定义属性的属性 prop:要定义或修改的属性的名称 desriptor:将被定义或修 ...

  3. javascript的Object对象的defineProperty和defineProperties

    Object的属性 查看官网:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Obje ...

  4. Javascript Object.defineProperty()

    转载声明: 本文标题:Javascript Object.defineProperty() 本文链接:http://www.zuojj.com/archives/994.html,转载请注明转自Ben ...

  5. JavaScript Object.defineProperty()方法详解

    Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象. 语法 Object.defineProperty(obj, prop ...

  6. Javascript观察者模式(Object.defineProperty、Reflect和Proxy实现)

    什么是观察者模式? 答:在数据发生改变时,对应的处理函数自动执行.函数自动观察数据对象,一旦对象有变化,函数就会自动执行. 参考<原生JavaScript实现观察者模式>(https:// ...

  7. javascript面向对象之Object.defineProperty(a,b,c)

    /* Object.defineProperty(a,b,c);介绍 a:需要属性设置的对象 b:需要设置的属性名,(键值) c:是一个用于描述属性值得json数据.这个json数据有configur ...

  8. Vue 双向数据绑定原理分析 以及 Object.defineproperty语法

    第三方精简版实现 https://github.com/luobotang/simply-vue Object.defineProperty 学习,打开控制台分别输入以下内容调试结果 userInfo ...

  9. javascript ES5 Object对象

    原文:http://javascript.ruanyifeng.com/stdlib/object.html 目录 概述 Object对象的方法 Object() Object.keys(),Obje ...

随机推荐

  1. web前端基础知识

    #HTML    什么是HTML,和他ML...    网页可以比作一个装修好了的,可以娶媳妇的房子.    房子分为:毛坯房,精装修    毛坯房的修建: 砖,瓦,水泥,石头,石子....    精 ...

  2. SQL Server 无法连接到服务器。SQL Server 复制需要有实际的服务器名称才能连接到服务器。请指定实际的服务器名称。

    异常处理汇总-数据库系列  http://www.cnblogs.com/dunitian/p/4522990.html SQL性能优化汇总篇:http://www.cnblogs.com/dunit ...

  3. JavaScript正则表达式,你真的知道?

    一.前言 粗浅的编写正则表达式,是造成性能瓶颈的主要原因.如下: var reg1 = /(A+A+)+B/; var reg2 = /AA+B/; 上述两个正则表达式,匹配效果是一样的,但是,效率就 ...

  4. Phoenix综述(史上最全Phoenix中文文档)

    个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/users/6cb45a00b49c/latest_articles 网上关于P ...

  5. C#多线程之基础篇3

    在上一篇C#多线程之基础篇2中,我们主要讲述了确定线程的状态.线程优先级.前台线程和后台线程以及向线程传递参数的知识,在这一篇中我们将讲述如何使用C#的lock关键字锁定线程.使用Monitor锁定线 ...

  6. 如何避免git每次提交都输入密码

    在ubuntu系统中,如何避免git每次提交都输入用户名和密码?操作步聚如下:1: cd 回车: 进入当前用户目录下:2: vim .git-credentials (如果没有安装vim 用其它编辑器 ...

  7. OpenCV人脸识别LBPH算法源码分析

    1 背景及理论基础 人脸识别是指将一个需要识别的人脸和人脸库中的某个人脸对应起来(类似于指纹识别),目的是完成识别功能,该术语需要和人脸检测进行区分,人脸检测是在一张图片中把人脸定位出来,完成的是搜寻 ...

  8. c#多线程

    一.使用线程的理由 1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性. 2.可以使用线程来简化编码. 3.可以使用线程来实现并发执行. 二.基本知识 1.进程与线程:进程作为操作系统执行程序 ...

  9. # PHP - 使用PHPMailer发邮件

    PHPMailer支持多种邮件发送方式,使用起来非常简单 1.下载PHPMailer https://github.com/PHPMailer/PHPMailer,下载完成加压后, 把下边的两个文件复 ...

  10. Spark的StandAlone模式原理和安装、Spark-on-YARN的理解

    Spark是一个内存迭代式运算框架,通过RDD来描述数据从哪里来,数据用那个算子计算,计算完的数据保存到哪里,RDD之间的依赖关系.他只是一个运算框架,和storm一样只做运算,不做存储. Spark ...