ASSetPropFlags is used internally to hide/unhide properties and methods of object prototypes and to protect them from being deleted or overwritten. But it can also be used to do the same thing for any object. Hidden properties will not show up in the output window and will not be iterated over in a for..in loop, but they can still be accessed if targetted directly.
The main benefit of ASSetPropFlags is to allow you to add properties and methods to a Class prototype without risking the property showing up in for..in loops over instances of the class, which could cause any number of problems in your script. In Flash 5, this meant you could create global variables by creating them in Object.prototype.
Flash 5 player. Extended and modified in Flash 6 player. Not officially documented, so its availibility is not guaranteed in future players.
ASSetPropFlags(‘targetObject‘, ‘propertyList‘, ‘n‘, ‘setFalse‘);
Takes 4 parameters:
‘targetObject’ is a reference to the object whose properties will be affected by the action.
‘propertyList’ is a list of property names in the form of either a comma-delimited string or an array of strings. In the Flash 5, this must be an array. If this property is ‘null’ then it has the same effect as listing all properties.
‘n’ is an integer which which determines whether the method will hide the properties listed in ‘propertyList‘, protect them from being overwritten or protect them from being deleted. The lower three bits of ‘n’ are used for bitwise flags (see table). Thus, all values for ‘n’ are equivalent to ‘n‘%8, (with the exception of ‘n‘==0 in Flash 5). In Flash MX, attributes set by this argument may only be set to true. The ‘setFalse’ parameter may be used to set attributes to false.
nb. In the Flash 5 player, when ‘n’ is zero, ASSetPropFlags does not affect hiding or protection flags but adds a “length” property to ‘targetObject‘. This property will adjust itself automatically to equal the highest numerically named property + 1.
‘setFalse’ is an additional argument, introduced in flash MX. In Flash 5, this argument can be taken to be always 7. It works just like ‘n’ except that it sets the attributes to false.
Higher bits can also be used, which flag a property to be invisible to specific swf versions.
The primary use of this in the player is to ensure that there are no conflicts between new objects introduced in a new player version and custom objects that exist in swfs created for previous player versions. I don’t remember exactly what all the values do, but it shouldn’t take someone too long to test them out. For starters:
This can be useful to check the version of a swf that some code is running in. Also, in limited circumstances, to get features from a newer player to work in older swfs. For example, to use some Flash 7 features in a version 6 swf.
myColour = new Color(); ASSetPropFlags(Color.prototype,null,0,1); // ASSetPropFlags(Color.prototype,null,8); // (Flash 5) for(a in myColour)trace(a); // outputs setRGB, getRGB, ....etc
myObject = {a:0, b:0, c:0, d:0, e:0} // hide properties c and d ASSetPropFlags(myObject,"c,d",1); // ASSetPropFlags(myObject,[["c","d"],1); // (Flash 5) for(a in myObject)trace(a); // output: a,b,e // unhide property c ASSetPropFlags(myObject,"c",0,1); // ASSetPropFlags(myObject,[["c"],8); // (Flash 5) for(a in myObject)trace(a); // output: a,b,c,e
obj={} obj.f = function(){ return "The original f!!"; } // protect obj.f from being overwritten ASSetPropFlags(obj,"f",4); // try and overwrite obj.f obj.f = function(){ return "A replacement f!!"; } trace(obj.f()); // output: The original f!! // unprotect obj.f from being overwritten ASSetPropFlags(obj,"f",0,4); // try and overwrite obj.f obj.f = function(){ return "A replacement f!!"; } trace(obj.f()); // output: A replacement f!!
Wow, that could be really useful for making classes global without ruining for..in. (Among other things, but that’s number one for me right now.)
I have been careful to only use this function for debugging purposes because I have no clue on its future status. Have we had any comment on that? I would hate to prototype everything to Object hide it, and then have it completely break in newer versions of the player because of for ins seeing it or something. – [Greg Burch]
Use it enough, and they will be very reluctant to take it out.
Is equal to ASNative(1,n)
ASSetPropFlags(_level0,[["$version"],7);
The property attributes set by ASSetPropFlags are defined in the ECMA-262 spec| (3rd edition) section 8.6.1 although there is no recommendation for an implementation to give direct access to these attributes.
However, the hidden attribute may be retrieved, using the isPropertyEnumerable method, available in the Flash 6 player. This method is documented in the ECMA-262 spec, under the subtley different name, propertyIsEnumerable (section 15.2.4.7).
Flash unsets the property attributes, using the ‘setFalse’ argument before it sets them with ‘n‘, so there is no ambiguity. Thus, you should pass ‘m’ the same ‘n’ value that property was once set to in order to reset its behaviors.
// ie this: ASSetPropFlags(obj,"props",n,m); // is the same as this: ASSetPropFlags(obj,"props",0,m); ASSetPropFlags(obj,"props",n);
The interesting thing imho with this 4th argument, is that it makes it possible to easily set an attribute without bothering with the others...Jerome Cordiez
_global.setEnumerable = function(pObj, pProp, pBool){ ASSetPropFlags(pObj, pProp, pBool ? 0 : 1 , pBool ? 1 : 0 ); } _global.setModifiable = function(pObj, pProp, pBool){ ASSetPropFlags(pObj, pProp, pBool ? 0 : 4 , pBool ? 4 : 0 ); } _global.setErasable = function(pObj, pProp, pBool){ ASSetPropFlags(pObj, pProp, pBool ? 0 : 2 , pBool ? 2 : 0 ); } // Usage: // To hide anyObject.anyProp from enumeration: // setEnumerable(anyObject, "anyProp", false);
Or, as object methods:
Object.prototype.setPropEnumerable = function(pProp, pBool){ ASSetPropFlags(this, pProp, pBool ? 0 : 1 , pBool ? 1 : 0 ); } Object.prototype.setPropErasable = function(pProp, pBool){ ASSetPropFlags(this, pProp, pBool ? 0 : 2 , pBool ? 2 : 0 ); } Object.prototype.setPropWritable = function(pProp, pBool){ ASSetPropFlags(this, pProp, pBool ? 0 : 4 , pBool ? 4 : 0 ); } Object.prototype.getPropEnumerable = function(pProp){ // return this.isPropertyEnumerable(pProp); for(var p in this){ if(p == pProp) return true; } return false; } Object.prototype.getPropErasable = function(pProp){ var tmp = this[[pProp]; if(tmp === undefined) return false; delete this[[pProp]; if(this[[pProp] === undefined){ this[[pProp] = tmp; return true; }else{ return false; } } Object.prototype.getPropWritable = function(pProp){ var newVal = (this[[pProp] == 0) ? 1 : 0; var tmp = this[[pProp]; this[[pProp] = newVal; if(this[[pProp] == newVal){ this[[pProp] = tmp; return true; }else{ return false; } } ASSetPropFlags(Object.prototype,"setPropEnumerable,setPropErasable,setPropWritable,getPropEnumerable,getPropErasable,getPropWritable",1);
Object.prototype.setPropFlags = function(pProp, write, erase, hide){ theFlags = parseInt([[Number(write),Number(erase),Number(hide)].join(""),2); var player = $VERSION.split(" ")[[1].split(",")[[0]; if(player > 5) ASSetPropFlags(this, pProp, theFlags); else ASSetPropFlags(this, [[pProp], theFlags == 0 ? 8 : theFlags); } Object.prototype.setPropFlags("setPropFlags",false,false,true);
‘setPropFlags()’ takes 4 parameters;
push 1, ‘any string’, ‘trace’
callFunction
or a
push 'any string', 1, 'this' getVariable push 'trace' callMethod
but simply it will translate it to
push 'any string' trace
that means that the difference happens at compile time, not at runtime, which implies that you may be able to use a MovieClip or Object specific “trace” defined in the prototype, but trace as itself as a global function will never be compiled as a method, and will never be overridable this way - though defining it in Object.prototype can be a workaround provided that you always use this.trace instead of trace alone.
What about the following for a standard way to create an object and encapsulate the data correctly:
function myClass(){ } myClass.prototype.fieldFoo = new Object(); myClass.prototype.getFoo = function() { return this.fieldFoo; } myClass.prototype.setFoo = function(val) { this.fieldFoo= url; } myClass.prototype.addProperty("foo",myClass.prototype.getFoo, myClass.prototype.setFoo); ASSetPropFlags(myClass.prototype,"getFoo,setFoo", 7, 0 ); ASSetPropFlags(myClass.prototype,"fieldFoo", 3, 0 );
-Adam
Well, after beating on ASSetPropFlags for sometime, I finally came to the conclusion that the flag table that everyone has been referencing is wrong - it’s the same one on every page I’ve found, but in my simple tests and real application tests, this table represents the true flag settings:
Sorry John, the two tables are the same but the first one has the headers “protect overwrite” and “protect delete” while yours has “can overwrite” and “can delete” so the two first columns are reversed but the two tables along with their headers have the exact same meaning. - Martin
yes, the new table posted by Joel IS correct, but the one that had been posted here previously was wrong. I assume they saw my posting, and corrected the table. Here’s the old one:
The new, correct one with the same column headings (why did they change the column headings? the just confuses the hell out of everyone ;)
John
At first blush, you might think I’ve just reversed the table and maybe even read it wrong, but compare value/row 3 - that’s not inverted, that’s just wrong according to the code test below. Anyone else notice this at all?
Well, thanks to Werner Sharp over at Macromedia for confirming the new table:
“Hi John, Your new table is right. It is three bits.
0×1 is “don’t enumerate” 0×2 is “don’t delete” 0×4 is “read only”
That matches up with your table. I’m happy to help.
-Werner”
This code further illustrates with this new table shows. I followed the examples on 2 different sites (they seemed to have copied one another) and it seemed like they never bothered to test the code.
/* NOTES: There are 2 loops here: 1. loop through an object at _level0 2. loop through an object in _global */ function runTest(flag:Number):Void { trace("BitFlag :: " + flag); if(obj) delete obj; var obj:Object = new Object(); obj.name = "Original Value"; _global.ASSetPropFlags(obj, null, flag, true); obj.name = "Changed Value"; trace("Prop Change? :: " + obj.name); delete obj.name; trace("Prop delete? :: " + obj.name); delete obj; trace("==============="); } for(var x:Number=0;x<8;x++) { runTest(x); } trace("///////////////////"); trace("///////////////////"); function runGlobal(flag:Number):Void { trace("BitFlag :: " + flag); if(_global.obj) delete _global.obj; _global.obj = new Object(); _global.obj.mc = _level0.pointer; _global.obj.name = "Original Value"; _global.ASSetPropFlags(_global.obj, null, flag, true); _global.obj.name = "Changed Value"; trace("Prop Change? :: " + _global.obj.name); delete _global.obj.name; trace("Prop delete? :: " + _global.obj.name); delete _global.obj; trace("Obj delete? :: " + _global.obj); trace("==============="); } for(var x:Number=0;x<8;x++) { runGlobal(x); }
traces:
BitFlag :: 0 Prop Change? :: Changed Value Prop delete? :: undefined =============== BitFlag :: 1 Prop Change? :: Changed Value Prop delete? :: undefined =============== BitFlag :: 2 Prop Change? :: Changed Value Prop delete? :: Changed Value =============== BitFlag :: 3 Prop Change? :: Changed Value Prop delete? :: Changed Value =============== BitFlag :: 4 Prop Change? :: Original Value Prop delete? :: undefined =============== BitFlag :: 5 Prop Change? :: Original Value Prop delete? :: undefined =============== BitFlag :: 6 Prop Change? :: Original Value Prop delete? :: Original Value =============== BitFlag :: 7 Prop Change? :: Original Value Prop delete? :: Original Value =============== /////////////////// /////////////////// BitFlag :: 0 Prop Change? :: Changed Value Prop delete? :: undefined Obj delete? :: undefined =============== BitFlag :: 1 Prop Change? :: Changed Value Prop delete? :: undefined Obj delete? :: undefined =============== BitFlag :: 2 Prop Change? :: Changed Value Prop delete? :: Changed Value Obj delete? :: undefined =============== BitFlag :: 3 Prop Change? :: Changed Value Prop delete? :: Changed Value Obj delete? :: undefined =============== BitFlag :: 4 Prop Change? :: Original Value Prop delete? :: undefined Obj delete? :: undefined =============== BitFlag :: 5 Prop Change? :: Original Value Prop delete? :: undefined Obj delete? :: undefined =============== BitFlag :: 6 Prop Change? :: Original Value Prop delete? :: Original Value Obj delete? :: undefined =============== BitFlag :: 7 Prop Change? :: Original Value Prop delete? :: Original Value Obj delete? :: undefined ===============
Thanks - John grden
Based on all the info above and other information on the net I wrote some information on ASSetPropFlags from the most basic information to the nitty gritty details.
Wrapper classes based on the code (credits included) are available as well (MTASC Strict compatible). I have only tested the classes with Flash 7 & 8, however the wrapper class itself could be extended for other flash versions ofcourse.
Here is the post: http://objectpainters.com/blog/?p=33
– Hans Wichman
icee
The 2 tables exactly the same one? and both not very clear?
– ASSetPropFlags –
_global.ASSetPropFlags (target: Object, propList, ft: Number, ff: Number): Void
PARAMETERS:
target, the target object to be set prop flags. propList, list of property names, Array of Strings or a comma delimited String, null for all properties. ft, flag bits to be added to the target properties. ff, flag bits to be removed from target properties.
RETURN:
Nothing.
DESCRIPTION:
Flag is a 3-bits binary, bit 0×01, enumeration-protected; bit 0×02, deletion-protected; bit 0×04, write-protected.
ASSetPropFlags uses the following formula to calculate the new flag from the old one: fn=fo & (~ff) | ft, where fo is the original flag, ff and ft from the parameters.
Getting the properties’ flags:
function ASGetPropFlags (target: Object, prop: String): Number { if (target == undefined) { //undefined, null return NaN; } if (!target.hasOwnProperty(prop)) { return NaN; } var flag = 0x01; for (var i in target) { if (i == prop) { //not enumeration-protected flag = 0x00; break; } } var temp = target[prop]; if (target[prop] == 200) { target[prop] = 100; if (target[prop] != 100) { //write-protected flag |= 0x04; } } else { target[prop] = 200; if (target[prop] != 200) { //write-protected flag |= 0x04; } } delete target[prop]; if (target.hasOwnProperty(prop)) { //deletion-protected flag |= 0x02; } target[prop] = temp; return flag; }