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支持
网友评论