与许多事件侦听器和函数引用一个对象相比,什么是更好的方法

Instead of many event listeners and functions referring to one object what is a better way?

本文关键字:什么 更好 方法 一个对象 事件 许多 侦听器 引用 函数      更新时间:2023-09-26

有没有比写四个基本上做相同事情的函数更好的方法来写这个?我怎么能调用同一个函数,但使用该函数显示同一对象的不同属性呢。

在以下示例中,a是一个"段落"元素。事件侦听器与类型为button的"input"元素绑定。

function $(id){
    return document.querySelector(id);
};
function Person(name, age, weight, favoriteActivity) {
    this.name = name;
    this.age = age;
    this.weight = weight;
    this.favoriteActivity = favoriteActivity;
}
var Jack = new Person("Jack Crish", 29, 200, "coding");
var a = document.querySelector("#person");
function showAge(){
    a.innerHTML = Jack.age;
}
function showName(){
    a.innerHTML = Jack.name;
}
function showWeight(){
    a.innerHTML = Jack.weight;
}
function showActivity(){
    a.innerHTML = Jack.favoriteActivity;    
}
$("#age").addEventListener("click", showAge);
$("#name").addEventListener("click", showName);
$("#weight").addEventListener("click", showWeight);
$("#enjoys").addEventListener("click", showActivity);

JSFiddle在这里找到:http://jsfiddle.net/metkjnyn/

当然,只需让函数接受一个参数,该参数指示要显示的属性。

function $(id){
    return document.querySelector(id);
};
function Person(name, age, weight, favoriteActivity) {
    this.name = name;
    this.age = age;
    this.weight = weight;
    this.favoriteActivity = favoriteActivity;
}
var Jack = new Person("Jack Crish", 29, 200, "coding");
var a = $("#person");
function showProperty(property) {
    this.innerHTML = Jack[property];
}
/*
function showAge(){
    a.innerHTML = Jack.age;
}
function showName(){
    a.innerHTML = Jack.name;
}
function showWeight(){
    a.innerHTML = Jack.weight;
}
function showActivity(){
    a.innerHTML = Jack.favoriteActivity;    
}
*/
$("#age").addEventListener("click", showProperty.bind(a, 'age'));
$("#name").addEventListener("click", showProperty.bind(a, 'name'));
$("#weight").addEventListener("click", showProperty.bind(a, 'weight'));
$("#enjoys").addEventListener("click", showProperty.bind(a, 'favoriteActivity'));
p{
    width:200px;
    height:20px;
    border:1px solid grey;
}
<p id ="person"></p>
<input id ="age" type = "button" value = "age"></input> 
<input id ="name" type = "button" value = "name"></input> 
<input id ="weight" type = "button" value = "weight"></input> 
<input id ="enjoys" type = "button" value = "enjoys"></input> 

由于对象属性可以作为字符串索引访问,并且基于元素的id正是属性名称这一事实,因此可以使用事件调用方的id引用作为要更改的属性:

更新JsFiddle

function show() {
    a.innerHTML = Jack[this.id];
}
$("#age").addEventListener("click", show);
$("#name").addEventListener("click", show);
$("#weight").addEventListener("click", show);
$("#enjoys").addEventListener("click", show);

编辑

正如Kevin B所指出的,您需要他们将享受id与实际的属性名称相匹配,如:

http://jsfiddle.net/metkjnyn/4/

<input id ="favoriteActivity" type = "button" value = "enjoys"></input> 
$("#favoriteActivity").addEventListener("click", show);

有,但也更糟。例如:

function Person(...) { ...; this.setup(); };
Person.prototype = {
  setup: function() {
    var self = this;
    ['name','age','weight','activity'].forEach(function(propName) {
      var fname = "show"+propName;
      self[fname] = function() { return self[propName]; }
      document.getElementById(propName).addEventListener("click", self[fname]);
    });
  }
};

它更好吗?好吧,是和否。这更简洁,因为它没有重复,所以可能出错的代码更少,但现在你有了一个需要更新的硬编码属性列表,并且你的对象的API几乎和mud一样透明(你现在必须分析代码以找出你的Person对象有什么功能)。

最佳实践是使用易于阅读的API:使对象透明

function Person(name, age, weight, favoriteActivity) {
    this.name = name;
    this.age = age;
    this.weight = weight;
    this.favoriteActivity = favoriteActivity;
}
Person.prototype = {
  showAge: function(evt){
    evt.target.textContent = this.age;
  },
  showName: function(evt){
    evt.target.textContent = this.name;
  },
  showWeight: function(evt){
    evt.target.textContent = this.weight;
  },
  showActivity: function(evt){
    evt.target.textContent = this.favoriteActivity;
  },
  bindToElement: function(a){
    a.querySelector(".name").addEventListener("click", this.showAge);
    a.querySelector(".age").addEventListener("click", this.showName);
    a.querySelector(".weight").addEventListener("click", this.showWeight);
    a.querySelector(".fav").addEventListener("click", this.showActivity);
  }
};

然后有一些单独的代码来初始化人员:

function makePerson(name) {
  var person = new Person(name);
  var el = document.querySelector("....");
  person.bindToElement(el);
}
...
makePerson("Jack");

尽量远离那些id选择器。它们是确保您永远不会在页面中添加其他内容的好方法。

在JavaScript中,您既可以通过Jack.name格式访问对象的属性,也可以通过Jack['name']格式访问对象。因此,如果你在每个函数中所做的都是访问给定对象的属性,那么你可以创建一个名为showInfo的函数,它采用你想要访问的属性的名称:

function showInfo(field) {
    a.innerHtml = Jack[field];
}

这样,调用showInfo('name')将与调用showName()相同。然后,您可以让每个侦听器将一个字符串传递给同一个函数,甚至可能根据按钮的ID来确定这些字符串。希望这能为您指明更好地减少代码重复的方向。

在Person.prototype 中添加一个"get"方法

Person.prototype.get = function (p) {
    a.innerHTML = this[p]; 
}

并在您的eventListener 中调用它

$("input").addEventListener("click", function() {Jack.get(this.value);});
$("#name").addEventListener("click", function() {Jack.get(this.value);});
$("#weight").addEventListener("click", function() {Jack.get(this.value);});
$("#enjoys").addEventListener("click", function() {Jack.get(this.value);});

请参见Fiddle。

您可以创建一个函数来执行事件绑定,并同时指定哪个属性:

function showProperty(id, property) {
    $("#" + id).addEventListener("click", function(e) {
        a.innerHTML = Jack[property];
    });
}
showProperty("age", "age");
showProperty("name", "name");
showProperty("weight", "weight");
showProperty("enjoys", "favoriteActivity");

jsfiddle.net/metkjn/2/

或者,您可以采用更具声明性的方法,并从按钮推断属性。这需要为enjoys按钮添加一个属性:

<input type="button" value="enjoys" data-property="favoriteActivity" />
function showProperty(e) {
    var property = this.getAttribute("data-property") || this.value;
    a.innerHTML = Jack[property];
}
var buttons = document.querySelectorAll("input[type=button]");
for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener("click", showProperty);
}

jsfiddle.net/metkjn/5/

两者都比原来的更干燥。