JSPatch詳解(JavaScript 模塊 基礎篇)
不是專業的JS人員,半吊子,主要寫給IOSer來看的。
匿名函數
打開JSPatch.js,先把所有的方法給不展開,就是鎖在一起,就看到一個不知道是什么鬼的東西,如下
(function(){...})()
好吧!這個東西叫做匿名函數“function(){...}”。一般js庫都采用這種自執行的匿名函數來保護內部變量
很明顯作者是害怕我們破壞了他的內部構造嘛~~
這東西其實跟我們所說的私有函數私有變量差不多
暴露方法
之前講到作者用一個自動執行的匿名函數來保護他的內部變量和函數。那么我們外面就沒法訪問里面的那些方法了。這個坑爹的問題咋辦呢?
var global = this
(function() {
....
global.defineClass = function(....) {
}
....
})()
用上面這種形式把defineClass等一系列需要公布的function,公布出來了
作者很機智的區分了共有方法和私有方法,那就是帶_的都是私有的,不帶的都是共有的。
defineClass
這個方法基本是接觸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)
愛咋玩就咋玩,關我屁事~
就一個規則,methodName是String,props 必須是個Array,method和classMethod是個對象
那就來看看作者的defineClass的定義
global.defineClass = function(declaration, properties, instMethods, clsMethods) {...}
defineClass就是可以傳三個參數
然后他為什么支持我們的瞎折騰呢
if (!(properties instanceof Array)) {
clsMethods = instMethods
instMethods = properties
properties = null
}
在里面判斷了呀。。。如果properties不是一個array的話,他就當做是個method了
在下面的東西各位看官可以先不關注了。
Require
在這之后就是Require,也可以作死的寫成各種各樣的
var strRequire = "UIView,UILabel"
var strRequire_die = "UIButton"
require(strRequire,strRequire_die)
那么再來看看作者這個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!他是檢測了所有的參數,然后把所有的參數中用“,”分開,分別調用了這個_require方法
那么他的_require方法是干什么用的呢
var _require = function(clsName) {
if (!global[clsName]) {
global[clsName] = {
__clsName: clsName
}
}
return global[clsName]
}
很多小伙伴看到可能有點小懵逼,這也是我為什么在defineClass那邊讓大家先停一下的原因。
以上三段代碼跑完之后的global就變成這個樣子了
global = {
...
"UILabel" :{
__clsName:"UILabel"
},
"UIView":{
__clsName : "UIView"
},
"UIButton":{
__clsName : "UIButton"
}
...
}
是滴,他把這些Class都加到了Global的屬性里面了。
跑完這些你會拿到一個對象,這個對象是這樣的
{
__clsName:"UIButton"
}
這個時候的疑問就在于怎么使用,或者說怎么就能使用了?
require("UIButton").alloc().init()
//or
require("UIButton")
var button = UIButton.alloc().init()
global里面有了這個UIButton能直接調用UIButton這一點大家都能想明白,可是為什么就有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")()
這時候你就要問了,那么這個__c()函數咋來的,看官別急,我們在看會js
for (var method in _customMethods) {
if (_customMethods.hasOwnProperty(method)) {
Object.defineProperty(Object.prototype, method, {value: _customMethods[method], configurable:false, enumerable: false})
}
}
這里給每個object對象都加上了_customMethods里面的所有方法,那么這個methods里面是什么鬼呢,我就不告訴你,賣個小關子,因為可能大家忽略了一個東西,UIView.__c("alloc")()這后面還有個"()",所以呢我們這個函數返回的肯定得是個function,好了,不逗你們玩了看正題,
//我這里都用了縮寫,為了大家能集中精力先關心重點
//是不是很想打我,你又打不到我
var _customMethods = {
__c:func(methodName){
...
return function(...){
...
}
}
...
}
那么目前為止require的這一套邏輯在js里面是的可以跑起來了,按標題的來,先不去關心oc里面是玩的什么鬼。
有些可能會問,require沒有調用這個_customMethods啊,為啥,提示你一下看下第一條,這是一個自動執行的匿名函數。
感謝 “大師”的JS支持