Looking for Magento 2? Check out the new article: Modifying Magento 2's Javascript.

Because Magento uses object prototype properties for most of it's functionality, it's quite easy to change it's behaviour without editing core files.

This article shows four ways to change the Product.Zoom.prototype.toggleFull method as defined in js/Varien/product.js.

Direct prototype override

Product.Zoom.prototype.toggleFull = function() {
    // your code
}

Cons: No access to the original method

Using Prototype's addMethods()

Product.Zoom.addMethods({
    toggleFull: function() {
        // your code
    }
})

Cons: Still no access to the original method...

Reference: Class#addMethods

Using Prototype's wrap()

Product.Zoom.prototype.toggleFull = Product.Zoom.prototype.toggleFull.wrap(function(superMethod){
    // your code
    return superMethod();
});

Pros: You can call the super method

Reference: Function#wrap

OOP subclassing

var MyClass = Class.create(Product.Zoom, {

    // add other properties

    // redefine the speak method
    toggleFull: function($super) {
        // your code

        // execute original function
        return $super();
    }
});

Pros: You're not changing the behaviour of Magento's core classes - the code will still have original functionality unless you explicitly tell it to use your class instead. You also have access to the super method.

Cons: Requires you to edit template files. In this case you'll need to change

product_zoom = new Product.Zoom('...');

to

product_zoom = new MyClass('...');

in app/design/frontend/base/default/template/catalog/product/media.phtml on line 55 (Magento 1.8.1.0).

Reference: Defining classes and inheritance

Conclusion

Wrap seems the best way if you need access to the super method.

Similarly to the Magento backend, consider using your class directly (like the last example) instead of blindly rewriting functionality. This might give you better compatibility with third party modules in the future.

Also, lately I've been using Prototype custom events in my code instead of rewriting functionality where possible. This is very similar to the observer pattern on the server.

Here's an example of fireing a custom event in one of the Onepage checkout functions:

Checkout.prototype.reloadReviewBlock =
Checkout.prototype.reloadReviewBlock.wrap(function(superMethod){
    var name = 'checkout:reload_review_block';

    $(document).fire(name + '_before', this);
    var r = superMethod();
    $(document).fire(name + '_after',   this);

    return r;
});

You could even pass the return value with the event:

var r = superMethod();
$(document).fire('eventname...', {
    checkout: this,
    returnValue: r
});

And you can listen to these event like so:

document.observe("checkout:reload_review_block_after", function(e) {
    console.log(e.memo.returnValue);
});

This should make upgrading easier.

(Also see http://solutoire.com/2007/11/08/firing-custom-events-with-the-prototype-javascript-framework)

javascript prototype.js magento