Create a class extending from ES6 Map

后端 未结 5 1173

Trying to get away with custom get/set functionality on ES6 Maps. Currently using Babel to transpile my code to ES5.

Chrome Version 41.0.2272.101 m

5条回答
  •  囚心锁ツ
    2021-01-04 01:30

    Yup, until Proxies arrive in full force the only way to achieve what you were trying to do is to shadow the built-in methods on the Map/Set, etc. yourself.

    For instance, if you have your map like so:

    var myMap = new Map([ ['key1', 'value1'], ['key2', 'value2']])
    

    You'd have to have some wrapper to pass it into to add the built-in methods, for instance for get/set:

    function proxify(obj){
        var $fnMapGet = function(key){
            console.log('%cmap get', 'color:limegreen', 'key:', key)
            if(!Map.prototype.has.call(this, key)){
                throw(new Error('No such key: '+ key))
            } else {
                return Map.prototype.get.call(this, key)
            }
        }
        var $fnMapSet = function(key, value){
            console.log('%cmap set', 'color:tomato', 'key:', key, 'value:', value)
            if(Map.prototype.has.call(this, key)){
                throw(new Error('key is already defined: ' + key))
            } else {
                if(Map.prototype.get.call(this, key) == value){
                    console.log('%cmap set', 'color:tomato', '*no change')
                    return this
                }
                return Map.prototype.set.call(this, key, value)
            }
        }
    
        Object.defineProperty(obj, 'get', {
            get(){
                return $fnMapGet
            }
        })
        Object.defineProperty(obj, 'set', {
            get(){
                return $fnMapSet
            }
        })
    
        return obj
    }
    

    So then:

    proxify(myMap)
    
    myMap.get('key1') // <= "value1"
    myMap.get('key2') // <= "value2"
    myMap.get('key3') // <= Uncaught Error: No such key: key3
    myMap.set('key3', 'value3') // <= Map {"key1" => "value1", "key2" => "value2", "key3" => "value3"}
    myMap.set('key3', 'another value3') // <= Uncaught Error: key is already defined: key3
    

    That would add the ability to do your own custom set/get on the map, not nearly as nice as subclassing Map nor as straightforward as es6 proxies but it at least it works.

    The full code snippet running below:

    var myMap = new Map([ ['key1', 'value1'], ['key2', 'value2']])
    
    function proxify(obj){
    	var $fnMapGet = function(key){
    		console.log('get key:', key)
    		if(!Map.prototype.has.call(this, key)){
    			throw(new Error('No such key: '+ key))
    		} else {
    			return Map.prototype.get.call(this, key)
    		}
    	}
    	var $fnMapSet = function(key, value){
    		console.log('set key:', key, 'value:', value)
    		if(Map.prototype.has.call(this, key)){
    			throw(new Error('key is already defined: ' + key))
    		} else {
    			if(Map.prototype.get.call(this, key) == value){
    				console.log('*no change')
    				return this
    			}
    			return Map.prototype.set.call(this, key, value)
    		}
    	}
    
    	Object.defineProperty(obj, 'get', {
    		get(){
    			return $fnMapGet
    		}
    	})
    	Object.defineProperty(obj, 'set', {
    		get(){
    			return $fnMapSet
    		}
    	})
    
    	return obj
    }
    
    proxify(myMap)
    myMap.get('key1')
    myMap.get('key2')
    try {
      myMap.get('key3')
    } catch(ex){
      console.warn('error:', ex.message)
    }
    myMap.set('key3', 'value3')
    try {
      myMap.set('key3', 'another value3')
    } catch(ex){
      console.warn('error:', ex.message)
    }

提交回复
热议问题