2012-07-08 38 views
7

Tôi là người mới tham gia javascript và tôi cần trợ giúp. Tôi đã cố gắng để tổng hợp bán kính bằng chức năng, nhưng có một lỗi không xác định :(Làm thế nào để vượt qua chức năng nguyên mẫu?

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); 

Trả lời

17

Vấn đề là bạn đang đi qua một hàm một tham chiếu đến chức năng khác, và do đó các chức năng thông qua là mất phạm vi! Dưới đây là dòng vi phạm:.. đối tượng

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

Javascript là trong một số cách đơn giản hơn chúng xuất hiện khi bạn thêm một phương thức getRadius để nguyên mẫu Circle, bạn không được xác định một phương pháp học như bạn sẽ trong OO cổ điển bạn là đơn giản xác định thuộc tính có tên của nguyên mẫu và gán af unction đến giá trị của tài sản đó. Khi bạn vượt qua this.getRadius làm đối số cho hàm tĩnh, như sumWithFunction, ngữ cảnh this bị mất. Nó thực thi với từ khóa this được liên kết với window và do window không có thuộc tính r, trình duyệt sẽ phát ra lỗi không xác định.

Nói cách khác, tuyên bố this.getRadius() đang thực sự nói "thực hiện chức năng giao cho getRadius tài sản của this, và thực hiện nó trong bối cảnh của this. Nếu không gọi hàm một cách rõ ràng thông qua tuyên bố rằng, bối cảnh không được phân định.

một giải pháp chung cho điều này là thêm một đối số dự kiến ​​đến bất kỳ chức năng mà nhận chức năng khác, ví ngữ cảnh.

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); 

Một giải pháp đơn giản hơn nhưng ít mạnh mẽ hơn là khai báo một hàm nội tuyến có thể truy cập tham chiếu ngữ cảnh trong phần đóng cục bộ.

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); 
}); 

Nhưng đến nay giải pháp đơn giản nhất là sử dụng một tính năng mới hơn của ECMAScript, một phương thức chức năng được gọi là bind. It is explained well here, bao gồm thực tế là nó không được hỗ trợ bởi tất cả các trình duyệt. Đó là lý do tại sao rất nhiều thư viện, như jQuery, Prototype, v.v., có các phương thức tiện ích liên kết chức năng cross-browser như $.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) 
+1

gạch cũng có một vài công cụ ràng buộc: [ '_.bind'] (http://underscorejs.org/#bind) và [' _.bindAll'] (http://underscorejs.org/ #bindAll). –

+0

Wow, deatailed! Không bao giờ mong đợi rằng khó khăn. cần một chút thời gian để tiêu hóa ... – user1510539

+0

@muistooshort Đúng! Hầu hết mọi thư viện đều có, bao gồm [Ext] (http://docs.sencha.com/ext-js/4-1/#!/api/Ext-method-bind), [MooTools] (http: // mootools. net/docs/core/Types/Function # Chức năng: bind), [YUI] (http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_bind) ... bạn có được ý tưởng. – zetlen

Các vấn đề liên quan