用JavaScript构造模型

时间:2017-11-09 06:16:50

标签: javascript model

我被问到这个问题:

编写一个执行以下功能的JavaScript函数(Model):

const person = new Model();
person.set('name', 'Bob')
console.log(person.get('name')) // Bob

// Unset
console.log(person.has('name')) // true
person.unset('name')
console.log(person.has('name'))// false

// Call Method
const person2 = new Model({ name: 'Bob', age: 27 });
console.log(person2.get('name'))
console.log(person2.get('age'))

// Event Listener on Change
person2.on('change', function(attrName, oldValue, newValue) {
  console.log(`1. ${attrName} has changed from ${oldValue} to ${newValue}`)
})
// Second time again
person2.on('change', function(attrName, oldValue, newValue) {
  console.log(`2. ${attrName} has changed from ${oldValue} to ${newValue}`)
})

person2.set('age', 28) // 2 print statements of age has changed from 27 to 28

/*
// this will only get triggered if name changes
person2.on('change:name', function(oldValue, newValue) {
  console.log(`3. ${attrName} has changed from ${oldValue} to ${newValue}`)
})
*/

我已经提供了以下解决方案,但我想知道我的解决方案是否正确或是否有更好的编写方式。请帮忙。

我的解决方案:

function Model(args) {

  if(!args) {
    this.store = {};
  } else {
    this.store = args;
  }
  
  this.listeners = {};
  this.listenerKeys = [];
 
}


Model.prototype.set = function(k, v){
  
  //k == "age"
  
  const oldValue = this.store[k] ? this.store[k]: undefined;
  
  //Check to see if we are listening to the key.
  if(this.listenerKeys.indexOf("change") > -1) {
    
    
    
    //If we do, then get the list of callbacks.
    const lists = this.listeners["change"];
    
    //Iterate through callbacks and fire em' ;-) 
    lists.forEach((list) => {
        list(k, oldValue, v ); //callback(attrName, oldValue, newValue)
    });
  }
  
  this.store[k] = v;
}

Model.prototype.get = function(k) {
  if(this.store.hasOwnProperty(k)){
    return this.store[k];
  } else {
    throw new Error("No Key existing");
  }
}

Model.prototype.has = function(k){
  const keys = Object.keys(this.store);
  
  if(keys.indexOf(k) > -1) {
    return true;
  } else {
    return false;
  }
}

Model.prototype.unset = function(k) {
  delete this.store[k];
}

Model.prototype.on = function(name, callback) {
  this.listenerKeys.push(name);
  
  if(this.listeners.hasOwnProperty(name)) {
    this.listeners[name].push(callback);
  } else {
    this.listeners[name] = []; //create an array
    this.listeners[name].push(callback); //push
  }
}


//QUESTION

const person = new Model();
person.set('name', 'Bob')
console.log(person.get('name')) // Bob

console.log(person.has('name')) // true
person.unset('name')
console.log(person.has('name'))// false

const person2 = new Model({ name: 'Bob', age: 27 });
console.log(person2.get('name'))
console.log(person2.get('age'))

person2.on('change', function(attrName, oldValue, newValue) {
  console.log(`1. ${attrName} has changed from ${oldValue} to ${newValue}`)
})
//first
person2.on('change', function(attrName, oldValue, newValue) {
  console.log(`2. ${attrName} has changed from ${oldValue} to ${newValue}`)
})

person2.set('age', 28) // 2 print statements of age has changed from 27 to 28

/*
// Part two. lets worry about this later
// this will only get triggered if name changes
person2.on('change:name', function(oldValue, newValue) {
  console.log(`3. ${attrName} has changed from ${oldValue} to ${newValue}`)
})
*/

但是,我想知道是否有任何其他简单/优雅的方式来写这个。因为有人告诉我这不是正确的方法: - (

PS:如果有人能指出我解决这个问题的正确方法,那我就无法写下最后一个'更改名称'。

1 个答案:

答案 0 :(得分:1)

最优雅的是:

class Model extends Map {
 constructor(obj){
   super();

   this.listeners = {};

   for(const key in obj)
     this.set(key, obj[key]);
 }

 set(key,value){
   for(const listener of (this.listeners["change"] || []))
      listener(key, this.get(key), value);

   for(const listener of (this.listeners["change:" + key] || []))
      listener(key, this.get(key), value);

   super.set(key,value);
 }

 on(evt, func){
   (this.listeners[evt] || (this.listeners[evt] = []).push(func);
 }

 unset(key){ this.delete(key); }
}

Try it