JSPatch詳解(JavaScript 模塊 基礎(chǔ)篇)
不是專業(yè)的JS人員,半吊子,主要寫給IOSer來看的。
匿名函數(shù)
打開JSPatch.js,先把所有的方法給不展開,就是鎖在一起,就看到一個(gè)不知道是什么鬼的東西,如下
(function(){...})()
好吧!這個(gè)東西叫做匿名函數(shù)“function(){...}”。一般js庫都采用這種自執(zhí)行的匿名函數(shù)來保護(hù)內(nèi)部變量
很明顯作者是害怕我們破壞了他的內(nèi)部構(gòu)造嘛~~
這東西其實(shí)跟我們所說的私有函數(shù)私有變量差不多
暴露方法
之前講到作者用一個(gè)自動(dòng)執(zhí)行的匿名函數(shù)來保護(hù)他的內(nèi)部變量和函數(shù)。那么我們外面就沒法訪問里面的那些方法了。這個(gè)坑爹的問題咋辦呢?
var global = this
(function() {
....
global.defineClass = function(....) {
}
....
})()
用上面這種形式把defineClass等一系列需要公布的function,公布出來了
作者很機(jī)智的區(qū)分了共有方法和私有方法,那就是帶_的都是私有的,不帶的都是共有的。
defineClass
這個(gè)方法基本是接觸JSPatch的起步吧,一般我們這么玩
var methodName = “name”
var method = {
handleBtn: function(sender) {
//balabala
}
}
var props = ["data":"test"]
var classMethod = {
test:function () {
//balabala
}
}
defineClass(methodName,props,method,classMethod)
也可以這么玩
defineClass(methodName,method,classMethod)
還可以這么玩
defineClass(methodName,method)
愛咋玩就咋玩,關(guān)我屁事~
就一個(gè)規(guī)則,methodName是String,props 必須是個(gè)Array,method和classMethod是個(gè)對象
那就來看看作者的defineClass的定義
global.defineClass = function(declaration, properties, instMethods, clsMethods) {...}
defineClass就是可以傳三個(gè)參數(shù)
然后他為什么支持我們的瞎折騰呢
if (!(properties instanceof Array)) {
clsMethods = instMethods
instMethods = properties
properties = null
}
在里面判斷了呀。。。如果properties不是一個(gè)array的話,他就當(dāng)做是個(gè)method了
在下面的東西各位看官可以先不關(guān)注了。
Require
在這之后就是Require,也可以作死的寫成各種各樣的
var strRequire = "UIView,UILabel"
var strRequire_die = "UIButton"
require(strRequire,strRequire_die)
那么再來看看作者這個(gè)Require是怎么玩的吧
global.require = function() {
var lastRequire
for (var i = 0; i < arguments.length; i ++) {
arguments[i].split(',').forEach(function(clsName) {
lastRequire = _require(clsName.trim())
})
}
return lastRequire
}
OK!他是檢測了所有的參數(shù),然后把所有的參數(shù)中用“,”分開,分別調(diào)用了這個(gè)_require方法
那么他的_require方法是干什么用的呢
var _require = function(clsName) {
if (!global[clsName]) {
global[clsName] = {
__clsName: clsName
}
}
return global[clsName]
}
很多小伙伴看到可能有點(diǎn)小懵逼,這也是我為什么在defineClass那邊讓大家先停一下的原因。
以上三段代碼跑完之后的global就變成這個(gè)樣子了
global = {
...
"UILabel" :{
__clsName:"UILabel"
},
"UIView":{
__clsName : "UIView"
},
"UIButton":{
__clsName : "UIButton"
}
...
}
是滴,他把這些Class都加到了Global的屬性里面了。
跑完這些你會(huì)拿到一個(gè)對象,這個(gè)對象是這樣的
{
__clsName:"UIButton"
}
這個(gè)時(shí)候的疑問就在于怎么使用,或者說怎么就能使用了?
require("UIButton").alloc().init()
//or
require("UIButton")
var button = UIButton.alloc().init()
global里面有了這個(gè)UIButton能直接調(diào)用UIButton這一點(diǎn)大家都能想明白,可是為什么就有alloc()了?各位看官不要急
這里就是需要從OC入手了
static NSString *_regexStr = @"(?<!\\\\)\\.\\s*(\\w+)\\s*\\(";
static NSString *_replaceStr = @".__c(\"$1\")(";
+ (JSValue *)_evaluateScript:(NSString *)script withSourceURL:(NSURL *)resourceURL
{
...
NSString *formatedScript = [NSString stringWithFormat:
@";(function(){try{\n%@\n}catch(e){_OC_catch(e.message, e.stack)}})();",
[_regex stringByReplacingMatchesInString:script options:0 range:
NSMakeRange(0, script.length) withTemplate:_replaceStr]];
...
}
看上面一串東西可能你覺得煩,那么我告訴你把,他的作用就是
UIView.alloc().init()
//->
UIView.__c("alloc")().__c("init")()
這時(shí)候你就要問了,那么這個(gè)__c()函數(shù)咋來的,看官別急,我們在看會(huì)js
for (var method in _customMethods) {
if (_customMethods.hasOwnProperty(method)) {
Object.defineProperty(Object.prototype, method, {value: _customMethods[method], configurable:false, enumerable: false})
}
}
這里給每個(gè)object對象都加上了_customMethods里面的所有方法,那么這個(gè)methods里面是什么鬼呢,我就不告訴你,賣個(gè)小關(guān)子,因?yàn)榭赡艽蠹液雎粤艘粋€(gè)東西,UIView.__c("alloc")()這后面還有個(gè)"()",所以呢我們這個(gè)函數(shù)返回的肯定得是個(gè)function,好了,不逗你們玩了看正題,
//我這里都用了縮寫,為了大家能集中精力先關(guān)心重點(diǎn)
//是不是很想打我,你又打不到我
var _customMethods = {
__c:func(methodName){
...
return function(...){
...
}
}
...
}
那么目前為止require的這一套邏輯在js里面是的可以跑起來了,按標(biāo)題的來,先不去關(guān)心oc里面是玩的什么鬼。
有些可能會(huì)問,require沒有調(diào)用這個(gè)_customMethods啊,為啥,提示你一下看下第一條,這是一個(gè)自動(dòng)執(zhí)行的匿名函數(shù)。
感謝 “大師”的JS支持