javascript .bind 可以上升多个级别吗?

Can the javascript .bind go up multiple levels?

我在 JavaScript 和 JQuery 中有一个钢琴键盘对象,像这样:

function Keyboard(name, size, xPos, yPos, octaves) {
    this.name = name;
    this.size = size;

    this.setDimensions = function (){};

    this.highlightKeyboard = function (){};
    ...
    etc.
}

它有很多方法可以设置尺寸,使用 div 作为按键生成键盘,参考 div 的 类 生成大调和小调音阶,等等。

我写了 4 种方法来在我按下某个键时突出显示大音阶,在我按下不同的键时突出显示小音阶,以及其他两个键的大调和小调三合奏。它们都有效,但在编写它们之后,我意识到所有 4 种方法都使用了很多相同的代码,因此我一直在尝试通过将大部分代码提取到主键盘对象中的单独方法中来进行整合,以便我可以重复调用它们。

我现在正在整合的问题是让 $(document).keypress 对象与外部代码配合得很好。

我想要的是这样的东西(部分代码示例——我省略了生成键盘的所有代码以及其他所有不相关的代码,因为除了这个问题之外它似乎工作正常):

function Keyboard(name, size, xPos, yPos, octaves) {

    this.getMajorTonic = (function(userNote) {
        // code to determine myTonic
        return myTonic;
    });

    this.setMajScale = function(myTonic) {
        var scale = [];
        // code to determine scale[];            
        return scale;
    };

    this.setScaleClasses = function(scale) {
        // code to determine scale_classes[]
        return scale_classes;
    };

    this.highlightKeyboard = function (scale, scale_classes){};
        // code to add highlighted classes to my divs based
        // on the values in scale and scale_classes 
    };

    this.findMajorScales = function(userNote);
        var myTonic = this.getMajorTonic(userNote);
        var scale = this.setMajScale(myTonic);
        var scale_classes = this.setScaleClasses(scale);
        var highlightKeyboard = this.highlightKeyboard;

        $(document).keypress(function (event) {        
            if (event.which === 109) {
                highlightKeyboard(scale, scale_classes)    
            }
        });
    };
}

var keys = new Keyboard("piano", 1, 0, 0, 2);
keys.findMajorScales("E");

想要的效果是,当我加载页面时,它会生成一个空白键盘,但是当我按下 "m" 键时,它会使用 this.highlightKeyboard 方法突出显示 E 大音阶。所以我想向 this.findMajorScales 方法传递一个不带参数的 this.highlightKeyboard 方法,然后填充参数并在按下 "m" 键时执行该方法。大多数一切正常,包括 ($document).keypress 对象——它执行其他代码,只是不执行具有正确参数的 this.highlightKeyboard 方法。

我该如何做到这一点? .bind 与它有关吗?我真的不知道它是否适用于此,或者我是否需要做其他事情。

非常感谢!

杰克

键盘对象中没有名为 highlightScales 的方法。我想你的意思是 this.highlightKeyboard.

也就是说 - bind() 用于将上下文传递给方法。它允许您手动设置 this 而不是使用该范围内的任何 this

So I want to pass the this.findMajorScales method a this.highlightKeyboard method with no arguments, and then have the arguments filled in and the method executed when the "m" key is pressed.

你正在监听 M 很好,所以你唯一的问题是在正确的上下文中调用 highlightKeyboard

考虑

var foo = {bar: function () {return this}),
    bar = foo.bar;

什么会 foo.bar() return? (foo)
什么会 bar() return? (windownull 或抛出错误等)


你有很多选择

有几种解决方法,您已经提到 Function.prototype.bind and it may be conceptually easier for you to use Function.prototype.call, Function.prototype.apply 甚至通过使用另一个标识符来传递 this 变量。

在任何一种情况下,处理程序中的默认 this 将不再是 Keyboard 的实例,因为事件来自 document

使用 Function.prototype.bind 你有几个选择

var highlightKeyboard = this.highlightKeyboard.bind(this);
$(document).keypress(function (event) {        
    if (event.which === 109) {
        highlightKeyboard(scale, scale_classes);
    }
});

// or binding args ahead of time too

var highlightKeyboard = this.highlightKeyboard.bind(this, scale, scale_classes);
$(document).keypress(function (event) {        
    if (event.which === 109) {
        highlightKeyboard();
    }
});

// or binding the handler

$(document).keypress(function (event) {        
    if (event.which === 109) {
        this.highlightKeyboard(scale, scale_classes);
    }
}.bind(this));

使用 Function.prototype.call.apply,需要参考 this

var highlightKeyboard = this.highlightKeyboard;
var me = this;

$(document).keypress(function (event) {        
    if (event.which === 109) {
        highlightKeyboard.call(me, scale, scale_classes);
    }
});

只是使用对 this

的引用
var me = this;

$(document).keypress(function (event) {        
    if (event.which === 109) {
        me.highlightKeyboard(scale, scale_classes);
    }
});

最后,另一种解决方案是编写一个生成所需内容的函数,这与 .bind 所做的非常相似,但在不支持 .bind 的环境中受支持(阅读:遗产)

$(document).keypress(function (me) { // this function generates the inside one
    return function (event) { // this is the function used as the handler
        if (event.which === 109) {
            me.highlightKeyboard(scale, scale_classes);
        }
    };
}(this)); // passing in `this` as param `me`