Laan's steps..

Feed Rss

as3中属性访问原理

04.09.2010, flash, by .

今天写代码,发现一个问题:

package {
	public class B {
		//私有属性
		private var doo:String = "abc";

		public function test(target:B):* {
			return target.doo;
		}

	}
}

然后我在另一个类里面,这样操作:

var value = new B().test(new B());
trace(value);

竟然能输出B实例的私有变量doo。doo这个变量所在的namespace应该是当前实例中——也就是说是有当前实例中才能访问该属性。但是很不幸,测试证明在其他B的实例中也能访问。于是想到as3中属性访问的原理:MultiName。
在as3中,访问属性是通过MultiName来实现的。最基本的情况这样的:MultiName包含两个数据段,一个是name,一个namespace。当你访问一个对象的属性时,会通过name来查找该对象的属性,如果该属性名等于name,而且该属性的namespace和MultiName中的namespace也相等的话,就认为该属性就是该MultiName要访问的属性了。
我看了下swf的结构,在B类的test方法中,target.doo编译后生成的指令中,访问属性doo的MultiName中的namespace和B类中属性doo的namesapce相同。这样的话,上面这个例子就可以理解了。

接下来,我做了一个测试:

//在别类中,直接新建一个B实例,直接访问doo1。通过非严格模式编译
var b:B = new B();
trace(b.doo);

运行的结果当然会报找不到doo属性的错误。因为b.doo编译后所生成的查找doo的MultiName中所包含的namespace和和B类中doo属性的namespace不相等(name数据是相等的)。于是我将B类中doo属性的namespace直接注入到查找doo的MultiName中去。然后重新组合swf——整个世界终于清静了。

既然原理确实是这样的,我就想到是不是可以提供一个方法专门用来访问对象的私有属性呢,比如:

function getPrivate(obj:*, pro:String):* {
	return obj[pro];
}

这个想法纠结了我一个下午,最后的结论是:不可能——至少我没想到有方法可以的。主要原始是:私有属性的namespace必须是和查找MultiName中的namespace在内存中的地址一样才能访问——我尝试保持数据一样但是内存地址不一样,失败了。

联想到一个动态属性访问的问题。动态访问属性时所使用的MultiName,不包含namespace数据段,但是有一个namespace set数据段,里面包含当前域能访问的所有namespace。这样,在查找属性时,得来一个循环来比对,会消耗更多的资源。

as3中属性访问原理 有 6 条回应

  1. 比较深。而且暂时没发现此发现有啥实际作用,留个脚印走人

    回复
  2. 恩,厉害,不过既然设为私有的,为什么要去访问呢,同意楼上的

    回复
  3. 哈哈 博主对虚拟机很熟学习不少 刚刚自己调试了第一个例子并未打印出doo还是doo的值 然后第二个例子 未作测试不过我觉得就算使用动态属性访问 私有的还是无法访问的

    回复
  4. 哦,这第一段代码中的return target.doo;
    可以理解成 编译器在编译的时候自动转成 return this.doo;

    回复
  5. 高深…

    @温泉 那数据不一样了

    回复
  6. 似乎Java里也有类似

    回复

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>