摘要:既然小匹夫說(shuō)不是,但的確有好幾種腳本語(yǔ)言啊,那和相比,我們應(yīng)該如何抉擇呢所以最后小匹夫會(huì)分析一下。因?yàn)樽詈笮∑シ蛞庾R(shí)到了和是兩種差別很大的語(yǔ)言。
前言
又來(lái)到了周末,小匹夫也終于有了喘口氣寫寫博客的時(shí)間和精力。話說(shuō)周五的下午,小匹夫偶然間晃了一眼游戲蠻牛Unity3D的QQ群,又看到了一個(gè)Unity3D開發(fā)中老生長(zhǎng)談的問(wèn)題,“我的開發(fā)語(yǔ)言究竟是選擇JavaScript呢?還是C#呢?”。對(duì)這個(gè)問(wèn)題,小匹夫也覺(jué)得的確該認(rèn)真的梳理一下了。那么為何說(shuō)JavaScript和C#的爭(zhēng)論根本就不存在呢?首先,我們要知道Unity3D中的Js腳本究竟是什么?最準(zhǔn)確的學(xué)名,我想應(yīng)該叫做UnityScript (因?yàn)閁nity-Technologies在github上托管的代碼就叫這個(gè)名字。。。)。那為何UnityScript不是JavaScript呢?我們就繼續(xù)分析一下UnityScript vs JavaScript好了。既然小匹夫說(shuō)UnityScript不是JavaScript,但Unity3D的確有好幾種腳本語(yǔ)言啊(C#,UnityScript, Boo),那和C#相比,我們應(yīng)該如何抉擇呢?所以最后小匹夫會(huì)分析一下C# vs UnityScript。
最熟悉的陌生人 - UnityScript小匹夫的上一篇文章《Mono為何能跨平臺(tái)?聊聊CIL(MSIL)》中介紹了一下Unity3D跨平臺(tái)的基礎(chǔ)。那就是借助了CIL,首先將源代碼(例如C#)編譯成CIL(其實(shí)是CIL assembly),之后再通過(guò)JIT或者是FULL-AOT將CIL編譯成目標(biāo)平臺(tái)的原生代碼,進(jìn)而實(shí)現(xiàn)了一套代碼,多個(gè)平臺(tái)使用的跨平臺(tái)功能。所以可以想見,作為Unity3D中的“JS"(之后我將使用UnityScript來(lái)稱呼)同樣也會(huì)先被編譯成CIL代碼,之后再編譯成對(duì)應(yīng)平臺(tái)的原生代碼。換言之,Unity3D實(shí)現(xiàn)了一套在.NET平臺(tái)上和C#處于”相同層面“的語(yǔ)言UnityScript。開發(fā)了一套自己的語(yǔ)言,這聽上去簡(jiǎn)直太瘋狂了是嗎?其實(shí)一點(diǎn)也不。剛才說(shuō)了,源代碼都要先編譯成CIL,所以只要能有一套編譯器能夠把UnityScript的語(yǔ)法分析識(shí)別并編譯成CIL,那問(wèn)題不就解決了嗎?當(dāng)然,如果有現(xiàn)成的,能符合以下三條的語(yǔ)言作為參考,那UnityScirpt的開發(fā)者應(yīng)該是感激不盡了吧。哪三點(diǎn)呢?
是.Net層面的語(yǔ)言。
像腳本語(yǔ)言
有編譯器能把它編譯成CIL
沒(méi)錯(cuò),聰明的看官你一定想到了,那位一直隱藏的很深的幕后人物,Unity3D腳本三巨頭之一的Boo了吧。都說(shuō)Boo是Unity3D得腳本語(yǔ)言之一,可是為啥就沒(méi)見有什么人用過(guò)呢?原因之一可能就是Unity3D最初之所以要引入Boo,純粹是為了UnityScript服務(wù)的。Boo作為一個(gè).NET平臺(tái)的第三方語(yǔ)言,寫起來(lái)也很像腳本語(yǔ)言,并且有對(duì)應(yīng)的編譯器能夠?qū)崿F(xiàn)從Boo到CIL的過(guò)程。Boo寫起來(lái)是像這個(gè)樣子的:(更多關(guān)于Boo的內(nèi)容請(qǐng)參見概覽CLI之上的新語(yǔ)言——Boo)
import System import System.Net import System.Threading url, local = argv client = WebClient() call = client.DownloadFile.BeginInvoke(url, local) while not call.IsCompleted: Console.Write(".") Thread.Sleep(50ms) Console.WriteLine()
簡(jiǎn)而言之,UnityScript是脫胎于Boo的。雖然看上去UnityScirpt和Boo長(zhǎng)的不像,但要明白語(yǔ)法不是問(wèn)題,語(yǔ)義才是。只要能把UnityScript的語(yǔ)法解析成Boo的編譯器能認(rèn)識(shí)的,那么UnityScript的編譯器的大部分工作就可以交給Boo的編譯器來(lái)實(shí)現(xiàn)了。所以,基于現(xiàn)成的Boo語(yǔ)言,開發(fā)UnityScript編譯器的工作就只剩下語(yǔ)法解析而已了,事實(shí)上他們也的確是這樣做的。
而當(dāng)我們來(lái)到UnityScript在github的托管頁(yè)面,發(fā)現(xiàn)竟然是Boo的開發(fā)者在維護(hù),而UnityScript的編譯處理邏輯所在的文件是一個(gè)boo文件--UnityScriptCompiler.boo。
雖然不懂boo語(yǔ)言,但是還是可以看到會(huì)引入boo的編譯器:
import Boo.Lang.Compiler
也會(huì)有針對(duì)UnityScript的語(yǔ)法進(jìn)行解析以供Boo的編譯器識(shí)別的過(guò)程:
pipeline.Insert(0, UnityScript.Steps.PreProcess()) pipeline.Replace(Boo.Lang.Compiler.Steps.Parsing, UnityScript.Steps.Parse()) pipeline.Replace(Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces, UnityScript.Steps.IntroduceUnityGlobalNamespaces()) pipeline.InsertAfter(Boo.Lang.Compiler.Steps.PreErrorChecking, UnityScript.Steps.ApplySemantics()) pipeline.InsertAfter(UnityScript.Steps.ApplySemantics, UnityScript.Steps.ApplyDefaultVisibility()) pipeline.InsertBefore(Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions, UnityScript.Steps.ProcessAssignmentToDuckMembers()) pipeline.Replace(Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping, UnityScript.Steps.ProcessUnityScriptMethods())
好吧,我才不會(huì)告訴你在同一個(gè)github頁(yè)面關(guān)于UnityScript的介紹是:
A JavaScript implementation based on the Boo programming language.
那么UnityScript的編譯器到底放在哪里呢?(從UnityScript到CIL)請(qǐng)看下圖:
Mac版的路徑:/Applications/Unity/Unity.app/Contents/Frameworks/Mono/lib/mono/unity/us.exe
Win版的路徑:U3D路徑/Editor/Data/Mono/lib/mono/unity/us.exe
說(shuō)了這么多,還是需要為我們這篇文章的主角UnityScript正個(gè)名:是靜態(tài)語(yǔ)言且需要編譯,脫胎于Boo語(yǔ)言,和JavaScript除了后綴之外沒(méi)有關(guān)系。所以與其糾結(jié)“U3D的javascript到底和javascript有多形似”,倒不如考慮下UnityScript和Boo有多么神似。
UnityScript vs JavaScript很多提出小匹夫在前言中提到的那個(gè)老生常談問(wèn)題的盆油,往往認(rèn)為UnityScript和我們平時(shí)所說(shuō)的JavaScript是一樣的,即使有人意識(shí)到有所區(qū)別,但是認(rèn)為本質(zhì)上也還是和JavaScript屬于同一范疇。期初小匹夫也是這樣認(rèn)為的,因?yàn)樵?jīng)使用過(guò)cocos2d-js開發(fā)游戲的緣故,所以當(dāng)聽說(shuō)Unity3D他喵的竟然支持JS腳本,那叫一個(gè)開心啊。可是最初的開心往往也暗示著最后的失望。
因?yàn)樽詈笮∑シ蛞庾R(shí)到了UnityScript和JavaScript是兩種差別很大的語(yǔ)言。
其實(shí)所謂的JavaScript是一個(gè)很泛泛的名字,可以用來(lái)指任何實(shí)現(xiàn)了ECMAScript標(biāo)準(zhǔn)的語(yǔ)言(求JS大神輕噴。。。),而UnityScript主觀上根本就沒(méi)有試圖去實(shí)現(xiàn)甚至是接近該標(biāo)準(zhǔn)。所以很多JavaScript的庫(kù)如果只是單純的拷貝粘貼,在Unity3D中并不會(huì)運(yùn)行的特別”順利“(之所以加引號(hào)是因?yàn)楹芏喽歼\(yùn)行不起來(lái)吧)。
那么兩者究竟有多大的差別呢?最主要和本質(zhì)的區(qū)別前文小匹夫已經(jīng)說(shuō)過(guò)了,它倆除了長(zhǎng)相差不多,壓根就沒(méi)啥聯(lián)系。但是還是需要有個(gè)更直觀的認(rèn)識(shí)。那么小匹夫就簡(jiǎn)單總結(jié)一下,JavaScript和UnityScrip的差別吧。
JavaScript沒(méi)有類的概念JavaScript沒(méi)有類的概念。因?yàn)樗且环N基于原型的語(yǔ)言,繼承發(fā)生在對(duì)象和對(duì)象之間(更靈活,換言之,更動(dòng)態(tài)),而非類和類之間。
舉個(gè)例子:
function Person() { this.name = ["chenjiadong"]; } var c = new Person(); console.log(typeof c.introduce); Person.prototype.introduce = function() { console.log("I am "+this.name+"."); }; console.log(typeof c.introduce); c.introduce();
如你所見,在匹夫有限的js知識(shí)中,同樣存在著對(duì)象和原型的概念。通過(guò)關(guān)鍵字new,我們可以用方法Person創(chuàng)建出一個(gè)對(duì)象c,此時(shí)的小c還是很單純的,不會(huì)introduce自己。但是如果Person經(jīng)過(guò)進(jìn)化,學(xué)會(huì)了介紹自己introduce,那么之前創(chuàng)建的小c也同樣學(xué)會(huì)了介紹自己introduce。
但是在UnityScript中可不能這樣,因?yàn)樗蓄惖母拍?。你一旦定義了你的類,那么在程序運(yùn)行時(shí)這個(gè)類也就不能改動(dòng)了。
文件名的講究不知道各位盆油有木有發(fā)現(xiàn),一個(gè)新建的UnityScript文件中好像并沒(méi)有聲明一個(gè)類。相反,看上去很像一般的javascript的寫法。比如這樣Test.js:
#pragma strict function Start () { } function Update () { }
其實(shí)原因就在于文件名了。U3D中大多數(shù).js文件都代表一個(gè)類,所以自然而然的,文件的名字就被用來(lái)稱呼這個(gè)類了。(當(dāng)然說(shuō)大多數(shù)文件都是這樣的含義就是,你也可以在一個(gè)文件中定義多個(gè)類,比如不繼承自MonoBehav的類)。
所以上面的代碼就等效于這樣的C#代碼:
using UnityEngine; public class Test : MonoBehaviour { void Start () { } // Update is called once per frame void Update () { } }
反觀JavaScript,則僅僅是執(zhí)行文件中的代碼,而和文件名無(wú)關(guān)。
除了這兩條比較“宏觀”的差別之外,語(yǔ)法上是否還有什么不同呢?有啊~看官,您繼續(xù)瞧好兒咯~
語(yǔ)法差異之一次能聲明幾個(gè)變量在javascript中,經(jīng)??梢赃@么干:
var x = 1, y = 2;
但在UnityScript中這樣寫,U3D通常會(huì)這么說(shuō)
語(yǔ)法差異之分號(hào)的必要性以前記得在微博上看到過(guò)一個(gè)大學(xué)教授吐槽過(guò)一個(gè)javascript的“bug”,如圖:(小匹夫竟然憑借記憶力找到那條去年的微博...求贊)
所以,讓大V掉坑里的,javascript的特性之一,就是程序在執(zhí)行時(shí)會(huì)默認(rèn)在行尾加“;”,換句話說(shuō),作為人類或者猿類的我們可以不在行尾寫分號(hào)。
而UnityScript為了避免這種很可能造成bug的寫法,對(duì)分號(hào)做出了要求。接下來(lái)不用我多說(shuō)了吧。
反正你不寫分號(hào),U3D大概會(huì)這么說(shuō):
語(yǔ)法差異之“賦值表達(dá)式”能否作為表達(dá)式賦值?實(shí)話實(shí)說(shuō),小匹夫也不知道怎么想的這么一繞口的小標(biāo)題。但是小匹夫記得在javascript中可以這么寫:
var x = 3; // x is 3 var y = (x=x+2); // x is 5, y is 5
所以這里,x=x+2 這個(gè)賦值表達(dá)式作為一個(gè)表達(dá)式給y賦值。
但是在UnityScript中同樣是不支持這種寫法的。這次U3D會(huì)和你嘰歪很多話。
語(yǔ)法差異之var和類型那點(diǎn)事聊javascript終究繞不過(guò)去的一個(gè)話題,那就是聲明變量時(shí)的var。假設(shè)你聲明變量時(shí),不帶var,則該變量會(huì)默認(rèn)成為全局變量。但是聲明變量不帶個(gè)var,在UnityScript中可行不通。
好吧,那妥協(xié)之,在UnityScript中我?guī)ar還不行嘛?那是不是就可以像JavaScript一樣,在類型上無(wú)拘無(wú)束任我飛了?
比如下面的代碼,我在javascript上和unityscript上都運(yùn)行的很完美啊。
//UnityScript 和 JavaScript都能運(yùn)行哎~ var x; x = 3; x = new Array();
這樣看起來(lái),貌似UnityScript是動(dòng)態(tài)語(yǔ)言?。『?jiǎn)直是視類型如無(wú)物啊。好多盆油到這里就迷糊了,接著就產(chǎn)生了那樣的錯(cuò)覺(jué)。
其實(shí)作為靜態(tài)語(yǔ)言,在編譯器進(jìn)行編譯時(shí),變量到底是什么類型它可得門清,所以在UnityScript中,上面代碼里的x到底是什么類型可是確定好的。 覺(jué)得奇怪是嗎?那我們把等效的代碼寫一下各位看官就明白了。
//在unityscript中等效于下面 Object x; x = 3; x = new Array();
對(duì),原來(lái)x是Object類型。所有的類型都派生自它,換言之,所有的類型都能轉(zhuǎn)化成它。所以3能轉(zhuǎn)化為Object,Array也能轉(zhuǎn)化成Object。這也就是UnityScript看起來(lái)是動(dòng)態(tài)類型的原因。(頻繁裝箱,肯定會(huì)影響效率)
所以你如果調(diào)用一個(gè)Object沒(méi)有的方法,可能會(huì)有這樣的提示:
當(dāng)然,關(guān)于var的話題還有很多,比如C#也有,但是和這里并非完全相同。同樣,javascript和unityscript可以聊的話題也還有很多,但是受限于篇幅,這里點(diǎn)到即止。
C# vs UnityScript終于來(lái)到咱們經(jīng)常爭(zhēng)論的火藥桶話題了,到底C#和Unity3D里的JS誰(shuí)好呢?
最常見的問(wèn)題無(wú)非是:_用js寫的u3d游戲和用c#寫的u3d游戲,到底誰(shuí)的運(yùn)行效率高啊?_
最常見的回答為非是:_肯定是C#啊,因?yàn)閖s是動(dòng)態(tài)的??隙ú蝗缇幾g的語(yǔ)言好。_
第二常見的問(wèn)題無(wú)非是:_用js開發(fā)和用c#開發(fā),哪個(gè)更快更適合我?。?/strong>_
第二常見的回答無(wú)非是:_js適合個(gè)人開發(fā),敏捷快速。c#適合公司開發(fā),規(guī)范嚴(yán)謹(jǐn)。_
咱們還是用和剛才討論與javascript的區(qū)別時(shí)一樣的思路來(lái)整理C#和UnityScript的不同,也就是按照先本質(zhì),再表現(xiàn)的順序。同時(shí)兼顧回答一下上面的兩個(gè)問(wèn)題。
本質(zhì)求同存異開篇就說(shuō)了,UnityScript是和C#同一個(gè)層面的語(yǔ)言,也需要經(jīng)歷從源代碼到CIL中間語(yǔ)言過(guò)渡,最終到編譯成原生語(yǔ)言的過(guò)程。所以本質(zhì)上,最終運(yùn)行的都是從CIL編譯而來(lái)的原生機(jī)器語(yǔ)言。但的確會(huì)有C#比較快的現(xiàn)象,那么問(wèn)題出在哪呢?
一個(gè)可能但不是唯一的答案就是UnityScript和C#生成CIL中間語(yǔ)言不同。
這一點(diǎn)想想也很簡(jiǎn)單,就像上文提到的var的問(wèn)題,如果使用Object來(lái)處理var的問(wèn)題,則不可避免的是頻繁的裝箱拆箱的操作,這對(duì)效率的影響是很大的。
所以的確,C#的速度更快,但原因是UnityScript會(huì)涉及到頻繁的裝箱拆箱操作,進(jìn)而生成的CIL代碼與C#有差異,而并非UnityScript是動(dòng)態(tài)語(yǔ)言且沒(méi)有經(jīng)過(guò)編譯。
現(xiàn)實(shí)很單純開發(fā)到底是使用C#還是UnityScript呢?如果不考慮運(yùn)行的效率,僅僅考慮開發(fā)時(shí)候的感受,小匹夫就談?wù)勛约旱目捶ê美病蔷褪钦湎r(shí)間,遠(yuǎn)離UnityScript。
首先有幾個(gè)事實(shí)我們要清楚:
UnityScript是脫胎于.NET平臺(tái)的第三方語(yǔ)言Boo的。所謂的第三方語(yǔ)言和C#的區(qū)別,就跟自己到底是不是親生的,爹到底是不是隔壁老王是一樣的。差距可能是全方位,立體式的。社區(qū)支持,代碼維護(hù),甚至是編譯出來(lái)的CIL代碼質(zhì)量都可能有很大的差距。選擇UnityScript之前,問(wèn)問(wèn)自己之前聽說(shuō)過(guò)Boo嗎?別忘了UnityScript和Boo的淵源。
UnityScript和JavaScript除了長(zhǎng)得像之外,根本就沒(méi)有什么關(guān)系。你在JavaScript里如魚得水,在UnityScript中如果不小心就可能埋下隱患,而一些隱患可能藏得很深。而且UnityScript也是靜態(tài)語(yǔ)言,也需要編譯,所以看不出來(lái)選擇它作為開發(fā)語(yǔ)言為什么會(huì)有人覺(jué)得快。
插件的支持。貌似大多數(shù)都是C#寫的吧。
好吧,如果上面的3點(diǎn)都不能說(shuō)動(dòng)你,那就看看官方的態(tài)度好了。
U3D官方團(tuán)隊(duì)基于數(shù)據(jù)分析做出的一個(gè)語(yǔ)言被使用的百分比圖。
由于Boo語(yǔ)言的使用量基本可以忽略,所以從Unity5.0版本開始就會(huì)停止對(duì)Boo的文檔支持。同時(shí)消失的還有從菜單創(chuàng)建Boo腳本的選項(xiàng)“Create Boo Script”。從U3D團(tuán)隊(duì)對(duì)Boo的態(tài)度,也可以窺見和Boo聯(lián)系密切的UnityScript未來(lái)的走勢(shì)。
同時(shí)U3D團(tuán)隊(duì)也會(huì)把支持的重心轉(zhuǎn)移到C#,也就是說(shuō)文檔和示例以及社區(qū)支持的重心都在C#,C#的文檔會(huì)是最完善的,C#的代碼實(shí)例會(huì)是最詳細(xì)的,社區(qū)內(nèi)用C#討論的人數(shù)會(huì)是最多的。
所以到底如何選擇,各位盆友也都應(yīng)該有了自己的認(rèn)識(shí)咯。
天色已晚,匹夫睡覺(jué)去也~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/78343.html
摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...
摘要:概述在真實(shí)的數(shù)據(jù)科學(xué)世界里,我們會(huì)有兩個(gè)極端,一個(gè)是業(yè)務(wù),一個(gè)是工程。偏向業(yè)務(wù)的數(shù)據(jù)科學(xué)被稱為數(shù)據(jù)分析,也就是型數(shù)據(jù)科學(xué)。所以說(shuō),同時(shí)學(xué)會(huì)和這兩把刷子才是數(shù)據(jù)科學(xué)的王道。 showImg(https://segmentfault.com/img/bVAgki?w=980&h=596); 概述 在真實(shí)的數(shù)據(jù)科學(xué)世界里,我們會(huì)有兩個(gè)極端,一個(gè)是業(yè)務(wù),一個(gè)是工程。偏向業(yè)務(wù)的數(shù)據(jù)科學(xué)被稱為數(shù)據(jù)...
摘要:大學(xué),光學(xué)工程研究生畢業(yè),和程序猿完全不搭邊。那怎么辦,試著學(xué)一學(xué)唄,學(xué)習(xí)才是程序猿的天性。所以我在想程序猿是不是都需要新知識(shí)刺激一下,才能保持興奮的頭腦。有句話說(shuō)的很對(duì)程序猿就像好奇的貓,追著毛球的線頭玩,最后一個(gè)毛球在腦袋里攪漿糊。 說(shuō)說(shuō)我自己的經(jīng)歷。211大學(xué),光學(xué)工程研究生畢業(yè),和程序猿完全不搭邊。 畢業(yè)后進(jìn)了成都某國(guó)字頭研究所,在行業(yè)里摸爬滾打了四年,2018年機(jī)緣巧合在家養(yǎng)...
閱讀 2428·2021-09-28 09:45
閱讀 3670·2021-09-24 09:48
閱讀 2355·2021-09-22 15:49
閱讀 3240·2021-09-08 16:10
閱讀 1740·2019-08-30 15:54
閱讀 2417·2019-08-30 15:53
閱讀 3147·2019-08-29 18:42
閱讀 2943·2019-08-29 16:19