Created
August 8, 2012 16:23
-
-
Save rwaldron/3296375 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Object.extend = function( LeftHandSideExpression, AssignmentExpression ) { | |
var target, src, needToThrow; | |
// Let target be ToObject(LeftHandSideExpression). | |
target = Object( LeftHandSideExpression ); | |
// Let src be ToObject(AssignmentExpression). | |
src = Object( AssignmentExpression ); | |
// Let needToThrow be false. | |
needToThrow = false; | |
// For each own property of src, let key be the property key | |
// and desc be the property descriptor of the property. | |
Object.getOwnPropertyNames( src ).forEach(function( key ) { | |
var desc, f, status; | |
desc = Object.getOwnPropertyDescriptor( src, key ); | |
// If desc describe a data property , then | |
// Let f be desc.[[Value]]. | |
// If f is a function with a super binding that is bound to src, then, | |
// Let desc.[[Value]] be a new function will all the same | |
// internal properties as f except that its super binding is set to target. | |
if ( desc.value !== undefined ) { | |
f = desc.value; | |
if ( typeof f === "function" ) { | |
desc.value = f.bind( target ); | |
} | |
} | |
// If desc describe an accessor property and has a [[Get]] attribute, then | |
// Let f be desc.[[Get]]. | |
// If f is a function with a super binding that is bound to src, then | |
// Let desc.[[Get]] be a new function will all the same | |
// internal properties as f except that its super binding is set to target. | |
if ( desc.get !== undefined ) { | |
f = desc.get; | |
desc.get = f.bind( target ); | |
} | |
// If desc describe an accessor property and has a [[Set]] attribute, then | |
// Let f be desc.[[Set]]. | |
// If f is a function with a super binding that is bound to src, then | |
// Let desc.[[Set]] be a new function will all the same | |
// internal properties as f except that its super binding is set to target. | |
if ( desc.set !== undefined ) { | |
f = desc.set; | |
desc.set = f.bind( target ); | |
} | |
// Let status be the result of calling the [[DefineOwnProperty]] | |
// internal method of target with arguments key, desc, and true. | |
status = Object.defineProperty( target, key, desc ); | |
// If status is an abrupt completion, set needToThrow to true; | |
// ... | |
// omitted | |
// ... | |
// console.log( desc ); | |
}); | |
if ( needToThrow ) { | |
throw new TypeError("Something bad happened"); | |
} | |
return target; | |
}; | |
// Basic tests... | |
// | |
var original, ref, arr, result, div; | |
original = { | |
get one() { | |
return 1; | |
}, | |
two: 2, | |
// this will be paved over | |
// and no longer update this.two | |
set val( value ) { | |
this.two = value; | |
} | |
}; | |
ref = { b: "baz" }; | |
arr = [ ref, 1, 2 ]; | |
result = Object.extend( original, { | |
val: 10, | |
get f() { | |
return "foo"; | |
}, | |
boundOp: function( x ) { | |
return this.val * x; | |
}, | |
ref: ref, | |
arr: arr | |
}); | |
result.val = 4; | |
console.log( result.one /* 1, Nothing happened here */ ); | |
console.log( result.two /* 2, set val(){} was paved; no longer sets "two" */ ); | |
console.log( result.boundOp(2) /* 8, this.val */ ); | |
// add a new prop to the reference object | |
ref.a = "alpha"; | |
console.log( result.ref.a /* "alpha" */ ); | |
// Of course it will appear in the resulting extended object | |
// Is this ideal? | |
// change an element in the reference array | |
arr[0] = 0; | |
console.log( result.arr[0] /* 0 */ ); | |
// Of course it will appear in the resulting extended object | |
// Is this ideal? | |
// | |
// | |
// DOM example... | |
// | |
if ( document ) { | |
div = document.createElement("div"); | |
Object.extend( div, { | |
// Devs will expect this to "just work" | |
innerHTML: "<p>P child element that contains a Text node</p>", | |
id: "my-div", | |
hidden: true | |
}); | |
document.body.appendChild( div ); | |
console.log( div.innerHTML /* "" */ ); | |
// This is dissappointing. | |
// in JS today, devs will expect this | |
// to work (as it does in major libraries) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment