javascript 如何传递原型函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11387127/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pass prototype function?
提问by user1510539
I'm a newbie to javascript and I need some help. I was trying to sum radius by function, but got an undefined error:(
我是 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);
回答by zetlen
The problem is that you're passing a function a reference to another function, and the passed function is therefore losing scope! Here's the offending line:
问题是您将一个函数传递给另一个函数的引用,因此传递的函数失去了作用域!这是违规行:
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, number);
}
JavaScript objects are in some ways simpler than they appear. When you added the getRadius
method to the Circle
prototype, you were not defining a class method like you would in classical OO. You were simply defining a named property of the prototype, and assigning a function to the value of that property. When you pass this.getRadius
as an argument to a static function, like sumWithFunction
, the context of this
is lost. It executes with the this
keyword bound to window
, and since window
has no r
property, the browser throws an undefined error.
JavaScript 对象在某些方面比它们看起来更简单。当您将getRadius
方法添加到Circle
原型时,您并没有像在经典 OO 中那样定义类方法。您只是定义了原型的命名属性,并为该属性的值分配了一个函数。当您将this.getRadius
参数作为参数传递给静态函数时,例如sumWithFunction
, 的上下文将this
丢失。它使用this
绑定到的关键字执行window
,并且由于window
没有r
属性,浏览器会抛出未定义的错误。
Put another way, the statement this.getRadius()
is actually saying "execute the function assigned to the getRadius
property of this
, and execute it in the contextof this
.Without calling the function explicitly through that statement, the context is not assigned.
换句话说,该语句this.getRadius()
实际上是在说“执行分配给 的getRadius
属性的函数this
,并在 的上下文中执行它this
。没有通过该语句显式调用该函数,上下文未分配。
A common solution to this is to add an expected argument to any function which receives another function, for context.
对此的常见解决方案是向任何接收另一个函数的函数添加一个预期参数,用于上下文。
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);
A simpler, but less robust solution would be to declare a function inline that can access a context reference in the local closure.
一个更简单但不太健壮的解决方案是声明一个内联函数,该函数可以访问本地闭包中的上下文引用。
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);
});
But by far the simplest solution is to use a newer feature of ECMAScript, a function method called bind
. It is explained well here, including the fact that it is not supported by all browsers. That's why a lot of libraries, like jQuery, Prototype, etc., have cross-browser function-binding utility methods like $.proxy
.
但到目前为止,最简单的解决方案是使用 ECMAScript 的一个新特性,一个名为bind
. 在这里解释得很好,包括并非所有浏览器都支持它的事实。这就是为什么很多库,比如 jQuery、Prototype 等,都有跨浏览器的函数绑定实用方法,比如$.proxy
.
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)
回答by vkarpov15
The tricky thing with this
in JavaScript is that it contains the object the function was a property of when it was calledby default. So when you pass MyCircle.increaseRadiusBy
as a parameter, you then call it as func()
, so the function isn't a property of any object. The easiest way to set this
is to use the call()
function:
this
JavaScript 中的棘手之处在于它包含该函数是默认调用时的属性的对象。因此,当您MyCircle.increaseRadiusBy
作为参数传递时,您将其称为 as 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);
The below approach, setting func
as a property before calling it, also works. You would never do this in practice because it adds an unnecessary property to context
, but it's a good didactic example to show how this
works.
下面的方法,func
在调用它之前设置为一个属性,也有效。在实践中您永远不会这样做,因为它为 增加了一个不必要的属性context
,但这是一个很好的教学示例,可以展示如何this
工作。
function addFivetoIt(func, context) {
context.func = func;
context.func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, MyCircle);