我被问到这个问题:
编写一个执行以下功能的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:如果有人能指出我解决这个问题的正确方法,那我就无法写下最后一个'更改名称'。
答案 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); }
}