npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

prop-filter

v0.0.1

Published

A lightweight, non-intrusive object property read-write filter proxy. Can be easily and freely combined with any project environment.

Downloads

3

Readme

prop-filter - 对象属性读写代理

Npm version Build Status Dependencies Status

一个羽量级、非侵入式的对象属性读写过滤器代理,能轻松、自由的与任何项目环境结合,瞬间提升你的编程效率,更好的提升你的代码的重用性。

写 Javascript 代码时经常伴随着大量的对象属性的读写,常常需要针对特定范围的对象实例,编写特定的 get/set 的方法。这些方法不但让一个类设计变得臃肿,往往实际情况是,费劲巴拉的写了一大堆 get/set ,真正被用到的可能只有那么一两个,一个项目写下来,总会思考,有没有可能将 set/get 方法可以作为独立模块或者 Class ,进行统一的管理和升级,但同时又不破坏原生类的业务逻辑呢?

经过很长时间的思考和总结,将属性读写(get/set)作为代理,是最佳的模式,最终呈现为 prop-filter 这个类库。

虽然基于 ES 的 Object.definedProperties 属性可以很好实现 get/set ,但他某种程度上,让你的实际代码变得非可预期性,后来者需要花更多的精力去理解、调试你的代码,或者依赖于你的文档,去解释和说明那些属性有 getter 或 setter ,这样并不能让一个项目变得更加直观。

如无意外,所有本人发布的项目统一优先发布在 码云

并且,再如无意外,都是基于面向对象的方式继承重载,也不会再去写什么原型链,forget it, embrace the future!

项目依赖类库

  • deepmergelodash.merge 的行为方式已经改为和 Object.assign 一样,但 deepmerge 现存一个问题,就是如果 deepmerge([], {}),第一个参数为数组 [] 时候,合并的返回的结果也会转为一个对象结构 {} ,其他方面还是符合对 deepmerge 行为的需求,所以继续使用这个类库。
  • lodash,这里使用的是 _.has_.get_.set 这三个方法,一直在别的项目使用这一组方法,非常合用,也就没必要单独再造轮子了。
  • typecheckerAPI DOC,主要用于变量类型判定,这个库的判断结果,基本与 javascript 原生的 typeof 的结果一致。npm上用于判定类型的库很多,但很多库自己导入了一些新的设定,你需要花时间去理解和消化那些新的设定和返回结果,这样非常不好,典型自造轮子。
  • php-trim-plus,自己的类库,主要用于强化字符串的处理、空字符的检查和强化JS trim 函数。

打包说明

index.js - 不合并依赖库,采用 commonjs 风格,作为 nodejs 环境引入的推荐。

PropFilter.js - 作为引入 src/PropFilter.mjs 的入口,不合并依赖库,采用 mjs 风格( import / export ),用于需要使用 mjs 环境下。 lodash 方法使用 import getProp from "lodash/get" 方式引入

PropFilter.lodash-standalone.js - 区别在于直接引入 import _ from "lodash" ,一些项目可能存在 lodash 作为外部包,没有和 webpack 项目一起打包合并。

dist/prop-filter.bundle.js - 全部依赖库合并打包(采用 rollup.js ),使用 commonjs 风格。

dist/prop-filter.bundle.umd.js - 全部依赖库合并打包(采用 rollup.js ),使用 umd 风格,全局变量名称 PropFilter

dist/prop-filter.lodash-standalone.js - lodash 作为项目的独立包存在,只有 lodash 使用 require('lodash')

dist/prop-filter.lodash-standalone.umd.js - lodash 作为全局对象存在(注意是 _ ),没有合并打包

安装说明

npm install prop-filter
// or
yarn add prop-filter

基础使用示例

基础三连星 has get set

const Filter = require('prop-filter');

let firstFilter = new Filter({
	key1: {
		/**
		 * 对象属性 getter 过滤器
		 * @param {*} value 从取值的对象的 key 中所取得到的值
		 * @param {{}} data 要取值的对象
		 * @param {string} key 要取值的 key
		 * @return {*} 返回的结果,为到 filter.get 方法所返回的值。
		 */
		get: (value, data, key) => { // getter
			return value; // 返回 get 的值
		},
		/**
		 * 对象属性 setter 过滤器
		 * @param {*}      value 要向对象的 key 写入的值
		 * @param {{}}     data  要写入属性的对象
		 * @param {string} key   要写入值的 key
		 * @return {*}           返回的结果,为最终要写入到对象属性上的值。
		 */
		set: (value, data, key) => { // setter
			return value; // 返回 要写入 的值
		},
		/**
		 * 判定对象的某个 key 是否有定义值
		 * @param {*}       value 从取值的对象的 key 中所取得到的值
		 * @param {boolean} has   判定该值是否存在的初步结果
		 * @param {{}}      data  要取值的对象
		 * @param {string}  key   要判断值是否存在的 key
		 * @return {boolean}      返回的结果,最终输出 filter.has 的结果。
		 */
		has: (value, has, data, key) => { // has
			return has;
		}
	}
});

// 目标对象
let target = {key1: 'value1'};
let anotherTarget = {key1: 'another-value1'};

filter.attach(target); // 将 filter 附着到目标对象上
if (filter.has('key1')) { // exists ?
	let key1Value = filter.get('key1'); // getter
    filter.set('key1', `changed-${key1Value}`); // setter
}

filter.unattach(target); // 解除附着
// or
filter.attach(anotherTarget); // 直接附着另外一个目标

基础三连星 - 特别说明:

1、因为使用了 _.has 作为 has 的判定基础,形成基础的 has 值,而 lodash 的 _.has ,某程度上,更应该叫做 existsKey 或 containKey ,即他返回的结果,是以目标对象是否存在这个 key 为判定基础,所以,如下情况:

let obj = {key: undefined};

_.has(obj, 'key'); // 这里会返回 true ,因为是 existsKey 或 containKey 的逻辑,而不是检查 key 的值是否为 undefined

所以,如果对应到 filter 的使用上,如果要过滤掉 undefined 和 null 的话:

let filter = new Filter({
	key1: {
		has: (value, has, data, key) => {
			if (typeof value === 'undefined' || value === null)
				return false;
			return has;
		}
	}
});

2、三连星的方法声明区别,箭头函数 vs function。箭头函数,默认是不绑定 this 上下文的,所以当你需要使用到 filter 一些自带的类型判定时,则应该清楚知道 箭头函数 和 function 的区别。如果在箭头函数希望引用回当前 filter ,可在参数声明添加一个参数。

let filter1 = new Filter({
	key1: {
		get: (value, data, key, filter) => { 
			// 这里的 this 不是当前的 filter ,而是全局对象。
			if (filter.isEmptyString(value))
				return "hello world!";
			return value;
		}
	}
});

let filter2 = new Filter({
	key1: {
		get: function(value, data, key) { 
			// 这里的 this 指向了 filter。
			if (this.isEmptyString(value))
				return "hello world!";
			return value;
		}
	}
});

当然,你也可以这样写:

let filter2 = new Filter((filter) => {
	key1: {
        get: (value, data, key) => { 
            // 这里的 this 指向了 filter。
            if (filter.isEmptyString(value))
                return "hello world!";
            return value;
        }
    }
});

三连星的实现本体 filter 方法

实际上实现三连星的本体,是 Filter.filter ,所以如果你需要有自定义的 filter ,请尽情在你自己的子类中重载这个方法:

// 实现1:前置重载
class MyFilter1 extends Filter {
	
	// override
	filter(target, method, prop, value = undefined) {
		
		if (method === 'get') {
			// do something
			return 'anything';
		}
		return super.filter(target, method, prop, value);
	}
}
// 实现1:后置重载
class MyFilter1 extends Filter {
	
	// override
	filter(target, method, prop, value = undefined) {
		try {
			return super.filter(target, method, prop, value);
		} catch (e) { // 未知的处理 method 默认会抛出一个异常,这里先接住这个异常
			switch (method) { // 开始加入自己的一些后置方法处理
				case 'hello' :
					// do something
					return '...';
					break;
			}
			throw e; // 其他未知的处理方法,继续抛出异常。
		}
		
	}
}

多层级属性的读写过滤代理

是的,这也是引入 lodash 的根本原因。

let obj = {
	key: {
		subkey: ['a']
	}
}

let filter1 = new Filter({
	'key.subkey.0': { // 
		get: (value, data, key, filter) => { 
			// 这里的 this 不是当前的 filter ,而是全局对象。
			if (filter.isEmptyString(value))
				return "hello world!";
			return value;
		}
	}
});

Filter.convertPropName 这个方法,是对属性名的过滤的实现,因为 lodash 的 _.get 支持两种多层级的 key 访问 key.subkey.0 or key.subkey[0]Filter.convertPropName 主要为了统一属性名的访问,可根据自己喜欢,重载这个方法,默认的行为将 [] 替换为了 . 操作符。

基础构成方法

filter.setFilters(filters)

设置绑定更多的 filters ,filters 必须为非空对象( object )。

filter.isValidTarget(target)

判定目标是否为有效的可附着目标,当前这个目标必须是一个 object。

filter.verifyTarget()

检查当前 filter 是否附着了有效的目标,如果没有,会直接抛出异常,正常则返回目前附着的目标。

filter.attach(target)filter.unattach(target)

附着目标 和 解除附着

filter.isAttached(target = undefined)

判定当前 filter 是否已经附着了有效的目标,如果指定了 target 参数,则判定 filter 附着的目标是否为 target。

其他辅助工具方法

php-trim-plus 系列,请参考 使用说明

filter.toSafeString(str);              // 转换为安全字符串
filter.trim(str, charList, isPlus);    // trim
filter.ltrim(str, charList, isPlus);   // trimStart
filter.rtrim(str, charList, isPlus);   // trimEnd
filter.isString(str);                  // 是否字符串
filter.isEmptyString(str);             // 是否空字符
filter.isEmptyStringOrWhitespace(str); // 是否空字符,或 空格
filter.isNothing(value);      // 是 undefined or null
filter.isNotNothing(value);   // 非 undefined or null
filter.isUndefined(value);    // 是 undefined
filter.isNotUndefined(value); // 非 undefined
filter.isArray(value);        // 是 数组
filter.isEmptyArray(value);   // 是 空数组
filter.isStringNumber(value); // 是 字符串数值
filter.isFunction(value);     // 是 函数,目前版本使用的是 typeof value === 'function' ,
							  // 目前发现,typechecker.isSyncFunction 和 typechecker.isAsyncFunction 判定失效,
							  // 部分 js 环境无法识别出来。

typechecker 系列,请参考 API DOC

filter.getType(value);       // 获取变量基础类型
filter.isObject(value);      // 是 对象
filter.isPlainObject(value); // 是 纯 object
filter.isEmptyObject(value); // 是 空 object
filter.isNumber(value);      // 是 数值类型
filter.isRegExp(value);      // 是 正则表达式
filter.isError(value);       // 是 异常错误对象