`
hax
  • 浏览: 951155 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

IE全局变量的Dissociative Identity Disorder(人格分裂症)

    博客分类:
  • JS
阅读更多
最近,小麦提出了一个疑惑
小麦 写道
最后介绍一个我也搞不明白的问题:

在HTML文档里写上这段代码:

<script type="text/javascript">
    window['a'] = 'Hi';
</script>
<script type="text/javascript" src="out.js"></script>
<script type="text/javascript">
    alert(a);
</script>

然后在out.js里写上这句:

if(false) {
     var a = 'Hello';
}

然后用FF和IE6分别运行,看看你得到什么。

在FF里会弹出“Hi”,但是在IE6中,会得到“undefined”。

很神奇吧?按语法,无论如何,a都不可能是undefined。但是IE6里就会。

如果把两个语句都写在同一个文件里,就不会有这个情况。
如果把out.js里改成window.a,或者把前一个改成var a,也不会有这个情况。
如果把out.js里的var a移到if语句之外,或是把if的条件改为true,也不会有这个情况。


这里刨去其实无关的 if 语句,可以把问题简化成这样的形式:
<script>
window.x = 1
</script>

<script>
var x
alert(x)
</script>

按理应该输出“1”,但是在IE中输出“undefined”。

而将两段script合并在一起
<script>
window.x = 1
var x
alert(x)
</script>

或者先加上一句“x = xxx”的赋值语句
<script>
x = null
window.x = 1
</script>

<script>
var x
alert(x)
</script>

输出结果就是正常的“1”。

这神奇的现象到底是为什么涅?


Dr. Hax告诉你:这是因为IE下的全局变量存在DID
Dr. Hax 写道
所谓DID,就是Dissociative identity disorder,译成中文就是“解离性自我认同紊乱”,放到人的身上,就是解離性人格疾患,即俗称“多重人格”、“人格分裂”是也。


我们知道创建global变量有三种方式,一种是直接用名字:

x = 1
alert(x)

一种是用var声明:

var x = 1
alert(x)

除了明确进行了变量声明外,主要区别是,var x声明所创建的x是不能被delete的。
x = 1
alert(delete x) // true
var y = 1
alert(delete y) // false


还有一种呢,就是通过global对象的属性,即window.x或window["x"]的赋值来创建:

window.x = 1
alert(window.x)


在创建完成之后,存取全局变量就是两种方式,一种是直接通过名字,如:

if(x == 1) x = 2

另一种则通过global对象的属性来存取,如:

if (window["x"] == 1) window.x = 2


按照BE大神的设计,全局变量的三种创建方式本应是三位一体的,两种存取方式也应是等同的,但是在M$IE中,其window.x的实现导致了DID问题——根据Dr. Hax的观察,在IE中全局变量分裂出了至少两种变量格


我们来看看临床症状

维基百科 写道
多重人格患者的每一個人格都是穩定、發展完整、擁有各別思考模式和記憶的。……分裂出的人格之間知道彼此的存在,也有一些情況,人格之間並沒有察覺彼此的存在,這會導致嚴重的「遺失時間」現象。

翻译到我们的语境则是:
Dr. Hax 写道
IE下的每一种全局变量格都是稳定、开发完整、拥有各自操作模式和存储的。……分裂的变量格之间知道彼此的存在(因此,通常来说,无论用哪种方式存取,结果是一致的),但也有一些情况,它们之间没有察觉彼此的存在,这会导致严重的“遗失引用”现象。


x = {}
// window.x
alert(x)
alert(delete x)
try {
	alert(x)
} catch(e) {
	alert(e.name + ":" + e.description)
}


以上代码可正常执行。但是如果把第二行的注释去掉,可以观察到在执行 alert(x) 时报出一个“Out of memory”的错误!其后你也将不能对x或者window.x做任何事情。
这短短的代码怎么能out of memory呢——显然这里产生了一个空指针(“遗失引用”)错误!


让我们进行成因分析。

维基百科 写道
多重人格的產生與童年創傷有密切相關,尤其是性侵害。患者的男女比(1:9)可以作為佐證,這或許是女孩比男孩易受到性侵害的緣故。當受到難以應付的衝擊時,患者以「放空」的方式,以達到「這件事不是發生在我身上」的感覺,這對長期受到嚴重傷害的人(如近親相姦)來說,或許是必要的。

转换一下语境:
Dr. Hax 写道
多重变量格的产生与最初设计的bug有密切相关,尤其是对接的bug。开源软件和私有软件出现对接问题的比例(0:1?)可以作为佐证,这或许是私有软件(因不遵循标准)比开源软件更多受到对接问题困扰的缘故。当受到难以应付的调用时,问题软件以“out of memory”的方式,以达到“这件事不在我的记忆体中”的感觉,这对长期受到严重自大症困扰的公司(如开发者)来说,或许是必然的。



为什么会这样?大体是因为JScript引擎的设计与IE DOM对接的缺陷所导致。

我们也可以从另一个方面来观察这个问题——我们来做一个性能测试:
var size = 1000000

x = 0
// var x = 0
// window.x = 0

var code = new Array(size + 1).join('x;')
// var code = new Array(size + 1).join('x=0;')
// var code = new Array(size + 1).join('window.x;')
// var code = new Array(size + 1).join('window.x=0;')

var f = new Function(code)
var start = new Date()
f()
alert(new Date - start)


结果如下:
                x   x=  window.x  window.x=
x = 0          156  172   3187      3469
var x = 0      156  172   3281      3422
window.x = 0  1516 1906   3297      3422


这个性能测试告诉我们:

一、无论以何种方式创建全局变量,访问window.x总是比直接访问x要慢许多。访问window.x慢,这还是容易理解的。因为window.x实际上是DOM调用,可理解成被转换为node.getAttribute('x')。而直接访问x,则很可能做了不同的处理(比如也许省略了跨域安全检查)。

二、“x = 0”和“var x = 0”所创建的全局变量,存取性能上没有什么区别,而“window.x = 0”则差很多。这说明在创建全局变量时,前者和后者的存储方式很可能是完全不同的。

以上这两点,都完全符合Dr. Hax在临床症状中所描述的“……拥有各自操作模式存储”。


由于无法进行病理解剖(没有IE和JScript引擎的源码),我们无法搞清楚所有细节,但是我们可以推断出个大概:

1. JScript引擎当然可以独立使用,而不依赖于DOM。在这样一种情况下,它本身就要处理全局变量的问题——譬如所有built-in的那些方法和对象。当引擎被嵌入到IE中时,就将JScript引擎的Global对象和DOM的window对象连接起来,而window对象,如同所有DOM对象一样,能够以expando属性方式保存额外的属性。这样就有了两个变量格,一个是基于JScript引擎内建的全局变量机制,一个是基于DOM的expando机制。

2. 对于x的存取和对于window.x的存取,前者是对于x这个引用的存取,而后者是对于window这个引用上进行x属性的存取。注意到这一区别,有助于理解下面的分析。

3. 以“x = xxx”方式新建全局变量时(前提是之前不存在任何形式的x引用),引擎并不会将x作为window的expando属性保存,而是按照JScript引擎的内建方式保存,并建立指向内部存储的x引用。内建方式是很高效的,比expando属性存取要快20倍以上。

上述判断,由DOM中的 document.expando 特性也可以佐证。当 document.expando=false 之后,你将不能使用 window.x = xxx 的方式新建全局变量,但是仍然可以用 x = xxx / var x = xxx 。

4. 在访问window.x时,如果已经有按照内建方式建立的x,则进行window.x到x的绑定,即产生一个指针指向内建方式创建的x,然后就凭借此指针来进行存取操作。然而在这里IE的开发者忘记了x引用可能被delete的情况,在x被delete之后,指针就失效了,从而导致之前的“Out of memory”错误。

5. 在对window.x进行赋值时,如果不存在按照内建方式保存的x,则会以window的expando属性方式保存(如果允许expando的话)。

6. 而在访问x时,如果没有按照内建方式建立的x引用,则检查引擎所连接的window对象上是否有x,即window上是否有expando。如果有,就建立x引用并指向window上的expando。如果没有,就扔出TypeError(按照标准其实应该扔出ReferenceError)。

7. 那么为什么在以expando方式建立变量后,存取window.x比存取x慢呢?
老实说,这个问题很难回答,只能大胆猜想一下:

存取window.x的步骤:
a. JScript引擎调用DOM对象存取属性的方法,假设记做 DOM::Window.get/setAttribute("x")
b. DOM::Window.get/setAttribute()方法先询问JScript引擎是否已经有内建全局变量x,假设记做 JScript::Global.hasProperty("x")
c. JScript::Global.hasProperty("x")返回false
d. 于是DOM::Window.get/setAttribute()方法存取expando属性,假设记做 DOM::Window.get/setExpando("x")
e. 将结果返回给JScript引擎

存取x的步骤:
a. JScript引擎查找是否存在x引用
b. JScript引擎根据x引用调用DOM::Window.get/setExpando("x")
c. DOM::Window.get/setExpando("x")返回结果给JScript引擎

根据上述猜想,存取window.x,是JScript调用DOM,DOM再回调JScript;而存取x,则只有JScript调用DOM。这就是性能差大概一倍的原因。


好了,绕了一大圈之后,我们来解释一下最初的代码为什么会有这样的结果。

<script>
window.x = 1
</script>

<script>
var x
alert(x)
</script>

这段代码会先以expando方式创建x。而后var x声明所进行的初始化操作,并不依赖于DOM,所以不会检测是否存在expando。道理上说应该检测,但是由于罹患DID,恰好此处JScript引擎并没有检测expando,而只会检测内建存储。并不存在内建的x,所以x引用就被重新初始化了,而且这次是以内建方式建立的。

而合并在一起后
<script>
window.x = 1
var x
alert(x)
</script>

var x声明会被提前,所以会以内建方式创建。执行 window.x = 1 时,已经有了内建的x,所以会建立到内建x的绑定,并对其赋值,而不会以expando方式保存。

先加上一句 x = xxx 的赋值语句
<script>
x = null
window.x = 1
</script>

<script>
var x
alert(x)
</script>

也会以内建方式创建x。这样之后的var x就不会重新初始化了。


最后说说治疗方案

维基百科 写道
多重人格的根治需要好幾年的時間。

换到我们的语境下:
Dr. Hax 写道
IE的DID的根治可能还需要很多年时间(IE9?)。




当然,我们有些简单的应对之道。

1. 不用全局变量,不折腾window对象。

从编程上说,使用全局变量不是一个好习惯。从JS效率而言,全局变量效率比局部变量要低许多。再加上IE独有的DID症,咱能不用就不用吧!

2. 如果一定要用全局变量,坚持直来直去,不折腾window对象。

也就是只用 var x 的方式。效率最高,也避免了DID症的可能发作。

3. 宁可折腾DOM元素,也不折腾window对象。

动态变量名,即window[name]之类的,可用一个 var container={name:value} 来替代,或者最不济的情形,你存到一个DOM元素上也好!

一样expando,DOM元素相比window,有个重要优点是有clearAttributes()方法可以清空所有属性(相当于delete操作),或者更快捷的方法是用parent.innerHTML或node.outerHTML直接清空。

或许你认为清空expando不重要,大谬!不信,你写个脚本给DOM元素上加10万个expando属性,然后按一次刷新看看。


附:DID疑难案例
<script>
x = ((window.x = 'expando'), 0)
alert('x = ' + x)
//window.x

try {
	alert('delete x -> ' + (delete x))
} catch(e) {
	alert(e.name + ': ' + e.description)
}
try {
	alert('window.x = ' + window.x)
} catch(e) {
	alert(e.name + ': ' + e.description)
}
try {
	alert('x = ' + x)
} catch(e) {
	alert(e.name + ': ' + e.description)
}
</script>
<script>
alert('x = ' + x)
var x = 'var'
</script>


在IE下输出什么?恢复被注释掉的第三行代码后呢?

答案请自己动手试验。


PS. 钻研DID多年的Dr. Hax还透露,实际上IE全局变量的DID不仅有两个变量格,实际上还有第三个变量格!你猜到了吗?欢迎留言竞猜。

20
9
分享到:
评论
20 楼 libmw 2011-11-04  
libmw 写道
呼呼。。ie8治好了

刚试了下,悲剧得还没治好
19 楼 libmw 2011-11-04  
呼呼。。ie8治好了
18 楼 bmcsy 2010-06-17  
虽然只是现在才看到,頩已经看完了,在概叹——我的神呀之余,真让人收获不少~~也知道了平时不晓得的。
17 楼 felsenlee 2009-12-22  
cuixiping 写道
分析的很全面和深入。

ie中的元素id可以直接当变量名一样使用,但是这个id变量不能被赋值.
<body id='body'>
<script type="text/javascript">
body=1;
</script>
</body>
这样就会脚本错误提示“对象不支持此属性或方法”。

所以,是定义变量,最好老老实实的var.上例中使用var body=1才可以。

“ body=1;”是个什么操作呢?比较奇怪!这肯定会报错啊,赋值也不是直接给对象赋吧。
16 楼 cuixiping 2009-12-20  
分析的很全面和深入。

我想,把window.x和var x混用本身就是个很坏的编程习惯,没有var就直接x=xxx也是很坏的编程习惯。

ie中的元素id可以直接当变量名一样使用,但是这个id变量不能被赋值.
<body id='body'>
<script type="text/javascript">
body=1;
</script>
</body>
这样就会脚本错误提示“对象不支持此属性或方法”。

所以,是定义变量,最好老老实实的var.上例中使用var body=1才可以。
15 楼 s79 2009-11-29  
似乎这个问题也能在这找到解释(IE7以后直接提供了XMLHttpRequest)。
if(typeof XMLHttpRequest=="undefined"){
alert(0);
var XMLHttpRequest={}; //省略。
}
14 楼 cuckoosnest 2009-11-15  
有没有发现用chrome运行那段性能测试代码非常慢,5,6秒的级别,opera非常快六七十ms级别。 大概是什么原因?
13 楼 achun 2009-08-11  
Dr.Hax
哈哈,太好玩了,这个可以找个声优做成有声版,小说?广播剧?
油菜呀
12 楼 Army 2009-03-26  
貌似我一猜就猜中了,别人连机会都没有,没留啥悬念下来,可惜了。
11 楼 hax 2009-03-26  
Army 写道

我还是选C,看看《ajax实战》吧~另外,签名是签Dr. hax呢,还是签真实姓名呢?我拿去炫耀一下去~

站内留言地址,我邮寄给你,呵呵。
10 楼 Army 2009-03-26  
hax 写道

Army 写道
猜一下,难道是ie里对dom节点的id直接引用?中!发奖品了。。。奖品选项如下:A. 与Dr. Hax在张江地铁站周边方圆5公里以内的食堂里共进午餐B. 与Dr. Hax在张江地铁站周边方圆5公里以内的食堂里共进晚餐C. 获得由Dr. Hax签名的《Ajax实战:实例详解》一本D. 获得没有Dr. Hax签名的《Ajax实战:实例详解》一本


吃惊,我居然猜对了!

我住在上海南站附近,接近闵行区,张江的话太远了……

我还是选C,看看《ajax实战》吧~另外,签名是签Dr. hax呢,还是签真实姓名呢?我拿去炫耀一下去~
9 楼 hax 2009-03-26  
Army 写道

猜一下,难道是ie里对dom节点的id直接引用?


中!

发奖品了。。。奖品选项如下:

A. 与Dr. Hax在张江地铁站周边方圆5公里以内的食堂里共进午餐
B. 与Dr. Hax在张江地铁站周边方圆5公里以内的食堂里共进晚餐
C. 获得由Dr. Hax签名的《Ajax实战:实例详解》一本
D. 获得没有Dr. Hax签名的《Ajax实战:实例详解》一本
8 楼 Army 2009-03-25  
猜一下,难道是ie里对dom节点的id直接引用?
7 楼 Army 2009-03-25  
前阵子在开发JAte的时候就碰到了,如果var一个object和swf的名字相同,js取得这个swf对象的时候就会取到var的那个变量上,得改个名字才行。
原理原来在这里……
6 楼 hax 2009-03-24  
beijing.josh 写道

IE的分裂症还包括:window.clearInterval能重写,clearInterval不能重写.所有以内建方式建立的window方法的引用都不能重写和删除.是否这是第三个变量格?


不是的。要构成“变量格”必须满足Dr. Hax定义的条件:拥有各自操作模式和存储。
其中的关键是一个全局变量引用的目标到底是指向哪里。第三种变量格其实(在早期脚本里)很常见的。
5 楼 hax 2009-03-24  
麦田的颜色 写道

sorry,Hax,好久没联系。

我不知道我问你要过MSN没?加我一下吧。我是小麦。

加过了,不过我99%时候不在线。。。
4 楼 beijing.josh 2009-03-23  
IE的分裂症还包括:window.clearInterval能重写,clearInterval不能重写.
所有以内建方式建立的window方法的引用都不能重写和删除.
是否这是第三个变量格?
3 楼 麦田的颜色 2009-03-23  
sorry,Hax,好久没联系。

我不知道我问你要过MSN没?加我一下吧。我是小麦。
2 楼 lifesinger 2009-03-16  
赞,Dr. Hax 太有意思啦
开诊所吧
1 楼 NOWGOO 2009-03-16  
非常棒的文章!

相关推荐

    Chemistry in Catalysis

    2.3.2 Dissociative chemisorption 37 3. Catalyst Characterization 3.1 Crystal structures 43 3.2 X-ray diffraction 51 3.3 Electron Microscopy 55 3.4 Scanning tunneling microscopy and atomic force ...

    Python课程设计 课设 手写数字识别卷积神经网络源码+文档说明.zip

    高分设计源码,详情请查看资源内容中使用说明 高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明高分设计源码,详情请查看资源内容中使用说明

    SpringBoot2.0快速开发框架权限.rar

    SpringBoot2.0快速开发框架权限.rarSpringBoot2.0快速开发框架权限.rarSpringBoot2.0快速开发框架权限.rar

    大语言模型的微调和推理baichuan7B, chatglm2-6B, Qwen-7B-chat源码.zip

    详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;详情请查看资源内容中使用说明;

    基于Qt与STM32平台开发的汽车车机系统上位机

    基于Qt开发的汽车车机系统上位机 & 常见类型汽车传感器信号模拟发生器 任务和要求: 任务: 根据发动机测控系统信号需求,设计一套发动机信号模拟器人机交互系统,能够根据需要向下位机输出控制信号,使其输出发动机测控系统需要的传感器模拟信号,给发动机测控系统的开发提供方便。 要求: 1.设计应包含上位机与下位机的交互程序及人机交互界面的设计,与下位机设计相结合,使其能够实现全部类型发动机传感器信号的模拟输出及显示。 2.设计中需要采用模块化开发程序。 3.所设计的人机交互界面简洁合理。 4.应考虑所设计系统的实用性。 具体工作内容: 1.根据设计目标,查阅相关设计标准和设计方法资料,对发动机信号模拟器设计中的关键工程原理和工程方法进行提炼,并围绕关键问题进行国内外设计现状调研,开展分析、评价与总结,确定主要研究内容,制定设计技术路线,制定设计计划(周进度),撰写开题报告,并进行开题答辩,开题报告参考文献应不少于15篇(其中外文文献不少于 4 篇,近五年文献不少于三分之一)。 2.根据设计要求和技术指标,进行满足功能原理需求的多方案拟定,考虑安全、 标准等多因素进行技术性与经济性评价

    实验-三、数据库安全性(目的、要求和模板).doc

    实验-三、数据库安全性(目的、要求和模板).doc

    毕设绝技 - 4天玩乐完成商城系统完整资料day02

    文件为第二天视频教程 在毕业设计的挑战中,有时我们需要以极短的时间完成一个相对复杂的项目,比如一个商城系统。虽然时间紧迫,但只要我们合理规划、高效执行,完全有可能在4天内完成一个基础且功能完备的商城系统。 商城系统,也被称为网上商城系统或Online Mall system,是一种功能完善的网上销售系统。该系统主要包括产品发布、在线订购、在线支付、在线客服等功能模块,旨在为企业或个人提供一个在线销售平台,实现商品的展示、交易和客户服务。 商城系统具有多种核心功能,如商品管理、订单管理、用户管理和营销管理。商品管理功能支持商品的添加、编辑、删除、分类和搜索,满足商家对商品信息的全面管理需求。订单管理功能则涵盖订单的生成、支付、发货、退款和评价等环节,确保交易流程的顺畅进行。用户管理功能包括用户的注册、登录、个人信息管理和收货地址管理等,提升用户体验。而营销管理功能则通过促销活动的设置、优惠券的发放和积分兑换等手段,帮助商家提升销售业绩。 商城系统的特点主要体现在功能性、易用性和安全性上。商城系统注重功能性的开发,每个功能都有其发挥作用的地方,满足商家的实际需求。

    忻州师范学院-论文答辩PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    小型餐饮管理系统-数据库设计报告.doc

    小型餐饮管理系统-数据库设计报告.doc

    毕业设计+Python+基于OpenCV的交通路口红绿灯控制系统设计+Sqlite +PyCharm 1.zip.zip

    本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!! 本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!! 本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!

    西南交通大学-毕业答辩PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    2024年中国中空纤维膜行业研究报告.docx

    2024年中国中空纤维膜行业研究报告

    四川师范大学-PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    实验三、数据库安全性实验报告.doc

    实验三、数据库安全性实验报告.doc

    西北农林科技大学-PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    java电子相册源码.rar

    java电子相册源码.rarjava电子相册源码.rarjava电子相册源码.rarjava电子相册源码.rar

    玉米脱粒机设计及其总装配图(论文、dwg图).rar

    玉米脱粒机设计及其总装配图(论文、dwg图)

    studyopencv2

    studyopencv2

    2024-2030全球与中国牛肉卷饼市场现状及未来发展趋势.docx

    2024-2030全球与中国牛肉卷饼市场现状及未来发展趋势

Global site tag (gtag.js) - Google Analytics