JavaScript封装函数foreach、foreachAll、attributeListener,绑定到对象原型上

方文锋  2023-07-02 16:31:55  753  首页学习JavaScript

最近写js代码,想用到类似PHP里面的foreach功能,刚开始的封装还需要传入对象类似 foreach(obj,function(k,v){}); ,太麻烦了,想要直接是 obj.foreach(function(k,v){}); 这样。好了直接上相关代码:

/**
 * 判断是否是数组
 * @param argument
 * @param {number|boolean} opt 是否用严格模式
 * @return {*}
 */
function is_array(argument, opt) {
    if (opt === 1 || opt === true) {
        return Object.prototype.toString.call(argument) === "[object Array]";
    }
    return argument && (typeof argument === "object") && ("length" in argument) && (typeof argument.length === "number");
}

/**
 * 判断是否是对象
 * @param argument
 * @return {*}
 */
function is_object(argument) {
    if (argument && (typeof argument === "object") && ("length" in argument)) {
        return Object.prototype.toString.call(argument) === "[object Object]";
    }
    return argument && (typeof argument === "object") && !("length" in argument);
}

/**
 * 判断是否是函数
 * @param argument
 * @return {*|boolean}
 */
function is_function(argument) {
    return typeof argument === "function";
}

/**
 * 判断是否是字符串
 * @param argument
 * @return {*|boolean}
 */
function is_string(argument) {
    return typeof argument === "string";
}

/**
 * 搜索数组中是否存在指定的值
 * @param {string} needle
 * @param {array} haystack
 * @param {boolean} argStrict
 * @return {boolean}
 */
function in_array(needle, haystack, argStrict) {
    var key = "", strict = !!argStrict;
    if (strict) {
        for (key in haystack) {
            if (haystack[key] === needle) {
                return true
            }
        }
    } else {
        for (key in haystack) {
            if (haystack[key] == needle) {
                return true
            }
        }
    }
    return false
}

/**
 * 设置对象属性不可修改,不可删除,不可枚举等
 * @param {Object|Array|function|Storage} obj
 * @param {array|object|string} attrList
 */
function attrNotEach(obj, attrList) {
    var O = {writable: false, configurable: false, enumerable: false}; //设置对象属性不可修改,不可删除,不可枚举
    var list = ["[object Function]", "[object Storage]", "[object Window]"], val;
    if (is_object(obj) || is_array(obj) || in_array(Object.prototype.toString.call(obj), list, true)) {
        if (is_array(attrList)) {
            for (var i = 0, len = attrList.length; i < len; i++) {
                val = attrList[i];
                is_string(val) && Object.defineProperty(obj, val, O);
            }
        } else if (is_object(attrList)) {
            for (var attr in attrList) {
                val = attrList[attr];
                is_string(val) && Object.defineProperty(obj, val, O);
                is_object(val) && Object.defineProperty(obj, attr, Object.assign({}, O, val));
            }
        } else {
            is_string(attrList) && Object.defineProperty(obj, attrList, O);
        }
    }
}

/**
 * 遍历数组或对象(Object原型链上)
 * @param {function} fn 传入两个参数:key,value。返回值为0或false时停止循环遍历
 */
Object.prototype.foreach = function (fn) {
    if (typeof fn === "function") {
        var rv;
        if (is_array(this, 1)) {
            for (var i = 0, len = this.length; i < len; i++) {
                rv = fn.call(this, i, this[i]);
                if (rv === 0 || rv === false) {
                    break;
                }
            }
        }
        if (is_object(this) || is_function(this)) {
            for (var attr in this) {
                rv = fn.call(this, attr, this[attr]);
                if (rv === 0 || rv === false) {
                    break;
                }
            }
        }
    }
};

/**
 * 遍历对象属性(对象,数组,函数)
 * @param {function} fn
 */
Object.prototype.foreachAll = function (fn) {
    if (typeof fn === "function") {
        var list = ["[object Storage]", "[object Window]", "[object Function]"], rv;
        if (is_object(this) || is_array(this, 1) || is_function(this) || in_array(Object.prototype.toString.call(this), list, true)) {
            for (var attr in this) {
                rv = fn.call(this, attr, this[attr]);
                if (rv === 0 || rv === false) {
                    break;
                }
            }
        }
    }
};

/**
 * 对象属性监听
 * @param {string} key
 * @param {function|object} getFun
 * @param {function} setFun
 */
Object.prototype.attributeListener = function (key, getFun, setFun) {
    if (/^[\S\s]+$/.test(key)) {
        var O = {writable: true, configurable: true, enumerable: false, value: this[key]}, tk = "__tempKey__", temp_key = "temp__" + key, temp;
        if (!is_object(this[tk])) {
            this[tk] = {};
            Object.defineProperty(this, tk, {writable: true, configurable: true, enumerable: false});
        }
        if (is_object(getFun)) {
            temp = getFun;
            temp.writable && (O.writable = temp.writable);
            temp.configurable && (O.configurable = temp.configurable);
            temp.enumerable && (O.enumerable = temp.enumerable);
            temp.value && (O.value = temp.value);
            getFun = temp.get;
            setFun = temp.set;
        }
        var cFn = {
            get: function () {
                is_function(getFun) && getFun.call(this);
                return this[tk][temp_key];
            },
            set: function (newValue) {
                this[tk][temp_key] = newValue;
                is_function(setFun) && setFun.call(this, newValue);
            }
        };
        Object.defineProperty(this, key, O);
        Object.defineProperty(this, key, cFn);
    }
};

(function () {
    attrNotEach(Object.prototype, ["foreach", "foreachAll", "attributeListener"]);
}()); 


foreach和foreachAll使用,如图:


attributeListener 的使用,如图: