1
0
Fork 0

Provided a more accurate mechanism for detecting Object.defineProperty (tests in IE8 fixed)

closure/master
Mike Gerwitz 2011-03-07 09:03:03 -05:00
parent 522165fb6a
commit fbc58384b4
4 changed files with 53 additions and 30 deletions

View File

@ -35,13 +35,33 @@ var getset = ( Object.prototype.__defineGetter__ === undefined )
; ;
/** /**
* Whether we can actually define secure properties, or we need to fall back * Whether we can actually define properties, or we need to fall back
*
* This check actually attempts to set a property and fails if there's an error.
* This is needed because IE8 has a broken implementation, yet still defines
* Object.defineProperty for use with DOM elements. Just another day in the life
* of a web developer.
*
* This test is only performed once, when the module is first loaded. Don't
* expect a performance hit from it.
*
* @type {boolean} * @type {boolean}
*/ */
var secure_fallback = ( Object.defineProperty instanceof Function ) var can_define_prop = ( function()
? false {
: true if ( typeof Object.defineProperty === 'function' )
; {
try
{
// perform test, primarily for IE8
Object.defineProperty( {}, 'x', {} );
return true;
}
catch ( e ) {}
}
return false;
} )();
/** /**
@ -65,8 +85,8 @@ exports.freeze = function( obj )
/** /**
* Gets/sets whether the system needs to fall back to defining normal properties * Gets/sets whether the system needs to fall back to defining properties in a
* when a secure property is requested * normal manner when use of Object.defineProperty() is requested
* *
* This will be set by default if the JS engine does not support the * This will be set by default if the JS engine does not support the
* Object.defineProperty method from EcmaScript 5. * Object.defineProperty method from EcmaScript 5.
@ -75,14 +95,14 @@ exports.freeze = function( obj )
* *
* @return {boolean|Object} current value if getter, self if setter * @return {boolean|Object} current value if getter, self if setter
*/ */
exports.secureFallback = function( val ) exports.definePropertyFallback = function( val )
{ {
if ( val === undefined ) if ( val === undefined )
{ {
return secure_fallback; return !can_define_prop;
} }
secure_fallback = !!val; can_define_prop = !val;
exports.defineSecureProp = getDefineSecureProp(); exports.defineSecureProp = getDefineSecureProp();
return exports; return exports;
@ -343,7 +363,7 @@ function getDefineSecureProp()
obj[ prop ] = value; obj[ prop ] = value;
}; };
if ( secure_fallback ) if ( !can_define_prop )
{ {
return fallback; return fallback;
} }
@ -367,7 +387,7 @@ function getDefineSecureProp()
{ {
// let's not have this happen again, as repeatedly throwing // let's not have this happen again, as repeatedly throwing
// exceptions will do nothing but slow down the system // exceptions will do nothing but slow down the system
exports.secureFallback( true ); exports.definePropertyFallback( true );
// if there's an error (ehem, IE8), fall back // if there's an error (ehem, IE8), fall back
fallback( obj, prop, value ); fallback( obj, prop, value );

View File

@ -24,7 +24,8 @@
var common = require( './common' ), var common = require( './common' ),
assert = require( 'assert' ), assert = require( 'assert' ),
Interface = common.require( 'interface' ) Interface = common.require( 'interface' ),
util = common.require( 'util' )
; ;
@ -167,7 +168,7 @@ var common = require( './common' ),
; ;
// if we have getter/setter support, add those to the tests // if we have getter/setter support, add those to the tests
if ( Object.defineProperty ) if ( !( util.definePropertyFallback() ) )
{ {
// getter // getter
tries.push( function() tries.push( function()

View File

@ -22,14 +22,9 @@
* @package test * @package test
*/ */
// no need to test getters/setters in browsers that do not support them
if ( !Object.defineProperty )
{
return;
}
var common = require( './common' ), var common = require( './common' ),
assert = require( 'assert' ), assert = require( 'assert' ),
util = common.require( 'util' ),
buildGetter = common.require( 'member_builder' ).buildGetter, buildGetter = common.require( 'member_builder' ).buildGetter,
buildSetter = common.require( 'member_builder' ).buildSetter, buildSetter = common.require( 'member_builder' ).buildSetter,
@ -44,6 +39,13 @@ var common = require( './common' ),
; ;
// no need to test getters/setters in browsers that do not support them
if ( util.definePropertyFallback() )
{
return;
}
function setUp() function setUp()
{ {
// clear out the members for a fresh start // clear out the members for a fresh start

View File

@ -30,20 +30,20 @@ var obj = {},
val = 'bar'; val = 'bar';
var expected = ( ( Object.defineProperty instanceof Function ) ? false : true ), var expected = ( ( Object.defineProperty instanceof Function ) ? false : true ),
fallback = util.secureFallback(); fallback = util.definePropertyFallback();
// IE 8 will fall back on first failure // IE 8 will fall back on first failure
if ( !expected && fallback ) if ( !expected && fallback )
{ {
try try
{ {
util.secureFallback( false ); util.definePropertyFallback( false );
util.defineSecureProp( {}, 'foo', 1 ); util.defineSecureProp( {}, 'foo', 1 );
// If the fallback was changed on us, then there was a problem (and this // If the fallback was changed on us, then there was a problem (and this
// is likely IE8). Change the value we're expecting so our tests don't // is likely IE8). Change the value we're expecting so our tests don't
// fail. // fail.
if ( util.secureFallback() === true ) if ( util.definePropertyFallback() === true )
{ {
expected = true; expected = true;
} }
@ -54,14 +54,14 @@ if ( !expected && fallback )
assert.equal( assert.equal(
expected, expected,
fallback, fallback,
"util.secureFallback() returns whether defining a secure property is " + "util.definePropertyFallback() returns whether defining a secure property is " +
"unsupported" "unsupported"
); );
assert.equal( assert.equal(
util.secureFallback( fallback ), util.definePropertyFallback( fallback ),
util, util,
"util.secureFallback() returns self when used as a setter" "util.definePropertyFallback() returns self when used as a setter"
); );
// perform secure property tests only if our parser supports it // perform secure property tests only if our parser supports it
@ -108,7 +108,7 @@ if ( fallback === false )
// be naughty so we can test the alternative implementation // be naughty so we can test the alternative implementation
util.secureFallback( true ); util.definePropertyFallback( true );
var obj2 = {}, var obj2 = {},
val2 = 'baz'; val2 = 'baz';
@ -149,5 +149,5 @@ if ( fallback === false )
} }
// restore in case the tests are not being run in separate processes // restore in case the tests are not being run in separate processes
util.secureFallback( fallback ); util.definePropertyFallback( fallback );