如何传递原型函数?

问题描述 投票:8回答:2

我是javascript的新手,我需要一些帮助。我试图按功能求和半径,但出现未定义的错误:(

function sumWithFunction(func, number) {
    return func() + number;
}

function Circle(X, Y, R) {
    this.x = X;
    this.y = Y;
    this.r = R;
}
Circle.prototype.getRadius = function () {
    return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
    this.r = sumWithFunction(this.getRadius, number);
}

function addFivetoIt(func) {
    func(5);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy);
javascript prototype
2个回答
23
投票

问题是,您要向一个函数传递对另一个函数的引用,因此传递的函数将失去作用域!这是令人反感的行:

Circle.prototype.increaseRadiusBy = function(number) {
    this.r = sumWithFunction(this.getRadius, number);
}

JavaScript对象在某些方面比它们看起来更简单。在将getRadius方法添加到Circle原型时,您没有像在传统OO中那样定义类方法。您只是在定义原型的命名属性,然后为该属性的值分配一个函数。当您将this.getRadius作为参数传递给静态函数(如sumWithFunction)时,this的上下文将丢失。它以绑定到thiswindow关键字执行,并且由于window没有r属性,因此浏览器会引发未定义的错误。

换一种说法,语句this.getRadius()实际上是说:“执行分配给getRadiusthis属性的函数,并在thiscontext中执行。通过该语句显式调用该函数,不会分配上下文。

一种常见的解决方案是在上下文中将期望的参数添加到接收另一个函数的任何函数。

function sumWithFunction(func, context, number) {
    return func.apply(context) + number;
}

function Circle(X, Y, R) {
    this.x = X;
    this.y = Y;
    this.r = R;
}
Circle.prototype.getRadius = function () {
    return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
    this.r = sumWithFunction(this.getRadius, this, number);
}

function addFivetoIt(func, context) {
    func.apply(context,[5]);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, myCircle);

一种更简单但更不可靠的解决方案是声明一个内联函数,该函数可以访问本地闭包中的上下文引用。

function sumWithFunction(func, number) {
    return func() + number;
}

function Circle(X, Y, R) {
    this.x = X;
    this.y = Y;
    this.r = R;
}
Circle.prototype.getRadius = function () {
    return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
    var me = this;
    this.r = sumWithFunction(function() {
        return me.getRadius()
    }, number);
}

function addFivetoIt(func) {
    func(5);
}

var MyCircle = new Circle(0, 0, 10);
addFivetoIt(function(number) {
    return MyCircle.increaseRadiusBy(number);
});

但是到目前为止,最简单的解决方案是使用ECMAScript的较新功能,这是一种称为bind的功能方法。 It is explained well here,包括并非所有浏览器都支持的事实。这就是为什么许多库(例如jQuery,Prototype等)具有跨浏览器功能绑定实用程序方法,例如$.proxy

$.proxy

0
投票

默认情况下function sumWithFunction(func, number) { return func() + number; } function Circle(X, Y, R) { this.x = X; this.y = Y; this.r = R; } Circle.prototype.getRadius = function () { return this.r; } Circle.prototype.increaseRadiusBy = function(number) { this.r = sumWithFunction(this.getRadius.bind(this), number); // or $.proxy(this.getRadius,this) } function addFivetoIt(func) { func(5); } var MyCircle = new Circle(0, 0, 10); addFivetoIt(MyCircle.increaseRadiusBy.bind(MyCircle)); // or $.proxy(MyCircle.increaseRadiusBy,MyCircle) 的棘手问题。因此,当您将this in JavaScript is that it contains the object the function was a property of when it was called作为参数传递时,然后将其称为this,因此该函数不是任何对象的属性。设置MyCircle.increaseRadiusBy的最简单方法是使用func()功能:

this

以下方法,也可以在调用call()之前将其设置为属性。在实践中,您永远不会这样做,因为它为function addFivetoIt(func, context) { // The first parameter to `call()` is the value of `this` in the function func.call(context, 5); } var MyCircle = new Circle(0, 0, 10); addFivetoIt(MyCircle.increaseRadiusBy, MyCircle); 添加了不必要的属性,但这是一个很好的教学示例,展示了func的工作方式。

context
© www.soinside.com 2019 - 2024. All rights reserved.