Adding methods to built-in objects: it’s one of JavaScript’s most powerful features. It’s also a great way to offend the sensibilities of your colleagues. We all hear that it’s irresponsible, that it’s sloppy, that it’s flat-out bad practice and should be avoided.
I’m tired of this one-sided battle. In this talk, I’m going to push back against whatever blog post you read that told you that extending built-ins was unconditionally and universally bad. I’m gonna go all Howard Beale on your asses.
3. “ There’s a whole lot of know-nothing advocacy
that’s still happening in the JS/webdev/design
world these days, and it annoys me to no end.
I’m not sure how our community got so religious
and fact-disoriented, but it has got to stop.”
Alex Russell
4. “If you use this book as a guide, by all means
leave the road when you wish. That is precisely
the use of a road: to reach individually chosen
points of departure. By all means break the
rules, and break them beautifully, deliberately
and well. That is one of the ends for which they
exist.”
Robert Bringhurst,
The Elements of Typographic Style
5. “Break any of these rules sooner than say
anything outright barbarous.”
George Orwell,
“Politics and the English Language”
8. @DonaldGlover
Donald Glover
Fuck what you heard, SHORTS ARE
DOPE. Just wear them right. Not mid leg
like you’re at a fuckin Creed concert.
30 Jul via Echofon
44. “I only re-open a class after I’ve tried every other
option like subclassing, wrapping, etc. If nothing else
works or is too much effort for the modification, then
I document the hell out of my modification and try
desperately to localize the change so that it doesn't
hurt anyone else.”
Zed Shaw,
“The Chainsaw Infanticide Logger Manuever”
http://is.gd/chainsaw_infanticide
45. “Don't slip a concrete dildo into someone's box of Fruit
Loops. They won't be happy with your Morning
Breakfast Surprise. Put the concrete dildo in a
clearly labeled box, with instructions. Then when
someone encounters a problem (‘Hey, something is
screwing me here. Maybe it's the concrete dildo?’) at
least they know to ask.”
The Higgs Bozo
http://is.gd/concrete_dildo
46. “In my mind, in Ruby < 2.0, there’s a category of library
which is ‘provide a number of useful core
extensions.’ The three major ones are ActiveSupport,
Extlib and Facets. In general, applications need to
choose one, but not more of these libraries to avoid
conflicts.”
Yehuda Katz
http://is.gd/cQar9O
48. Make it obvious when you’re defining core extensions.
module SomeLibrary
module CoreExtensions
module Object
def foo
# ...
end
end
end
end
class Object
include SomeLibrary::CoreExtensions::Object
end
49. Make core extensions as atomic as possible.
require 'active_support/core_ext/numeric/bytes'
3.megabytes
#=> 3145728
3.days.ago
# NoMethodError: undefined method `days' for 3:Fixnum
50. If you must monkey-patch, do so seamlessly.
Don’t break the old method’s contract.
class Array
alias_method :foo_original :foo
def foo(arg)
puts "Adding advice to the 'foo' method"
foo_original(arg)
end
end
53. Libraries I require will o en decide for themselves
which core extensions will be used.
{}.blank?
# NoMethodError: undefined method `blank?' for {}:Hash
require 'rails'
{}.blank?
#=> true
57. ES5 to the rescue?
Object.defineProperty(Object.prototype, 'extend',
{
writable: true,
configurable: true,
enumerable: false,
value: function() {
for (var i = 0, len = arguments.length, source; i < len; i++) {
source = arguments[i];
for (var property in source) {
if (source.hasOwnProperty(property))
this[property] = source[property];
}
}
}
}
);
58. var whiteHouse = { washington: 'adams' };
whiteHouse.extend({ adams: 'jefferson' });
for (var president in whiteHouse)
console.log(president);
//=> washington, adams
59.
60. But wait…
var whiteHouse = { extend: 'adams' };
whiteHouse.extend({ adams: 'jefferson' });
// TypeError: Property 'extend' of object #<Object>
// is not a function
68. var time = require('time');
var date = new Date();
date.setTimeZone('America/Chicago');
console.log(date.toString());
console.log(date.getTimezone());
console.log(date.getTimezoneAbbr());
Output:
Tue Apr 26 2011 02:45:21 GMT-0500 (CDT)
America/Chicago
CDT
70. We’ll be needing ES5 polyfills
“A polyfill … is a piece of code (or plugin) that
provides the technology that you, the
developer, expect the browser to provide
natively.”
Remy Sharp
http://remysharp.com/2010/10/08/what-is-a-polyfill/
71. if (!Object.keys) {
Object.keys = function(object) {
if (object !== Object(object))
throw new TypeError('Object.keys called on non-object');
var results = [];
for (var property in object) {
if (object.hasOwnProperty(property))
results.push(property);
}
return results;
};
}
72. if (!Function.prototype.bind) {
Function.prototype.bind = function(object) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1),
self = this;
var nop = function() {};
var bound = function() {
return self.apply(
this instanceof nop ? this : (object || {}),
args.concat(slice.call(arguments))
);
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
77. “[W]e present classboxes, a module system for object-
oriented languages that allows method addition and
replacement. Moreover, the changes made by a
classbox are only visible to that classbox (or
classboxes that import it), a feature we call local
rebinding.”
So ware Composition Group,
University of Bern
http://scg.unibe.ch/research/classboxes
78. A classbox-like system called “refinements”
has been proposed for Ruby 2.0.
module TimeExtensions
refine Numeric do
def minutes; self * 60; end
end
end
2.minutes #=> NoMethodError
using TimeExtensions
2.minutes #=> 120