AngularJS 源码分析1
2020-12-13 05:18
标签:style blog class code c tar angularjs
是google出品的一款MVVM前端框架,包含一个精简的类jquery库,创新的开发了以指令的方式来组件化前端开发,可以去它的官网看看,请戳这里 再贴上一个本文源码分析对应的angularjs源码合并版本1.2.4,精简版的,除掉了所有的注释, 请戳这里 定位到4939行,这里是angularjs开始执行初始化的地方,见代码
bindJQuery方法是检查是否引用jquery,没有的话jqlite就用本身自带的,否则切换到jquery中去.这个好理解 publishExternalAPI这个方法是绑定一些公共的方法到angular下面,这些是可以在网站中访问到的,像forEach,copy等公共方法,还有一个重要的任务就是初始化angular核心的模块,publishExternalAPI在465行,现在我们来分析里面的一些重要的代码
方法体中的setupModuleLoader方法是一个模块加载器,这也是一个关键方法, 主要作用是创建和获取模块,代码见417行.
上面publishExternalAPI 方法中的angularModule =
setupModuleLoader(window);是在window下面创建全局的angular对象,并且返回一个高阶函数,赋值给了angular.module属性,所以一般我们创建模块都是用angular.module方法.这里的angularModule其实就是相当于angular.module angular.module在创建模块的时候,传递一个参数的时候,是获取模块;传递一个以上的是创建新模块;该方法返回的是一个moduleInstance对象,它的任务就是来创建控制器,服务,指令,以及配置方法,全局运行方法,而且是链式调用,因为每个方法都会返回moduleInstance,看这里
此处的return invokeQueue[insertMethod || "push"]([provider, method, arguments]),
moduleInstance,逗号表达式是返回最后一个值 再来一个angular.module在项目中运用的代码
接下来再看publishExternalAPI的代码,因为ngLocale默认没有创建,所以angularModule("ngLocale")这个直接异常,跳到catch里执行angularModule("ngLocale",
[]).provider("$locale",
$LocaleProvider),记住这里的provider方法,默认是把它的参数都存到invokeQueue数组中,以便在后面用到. 接下来开始创建ng模块,它依赖上面的ngLocale模块,注意创建模块的时候传了第三个参数,当创建模块的时候传了三个参数,默认第三参数会执行config(configFn),这个方法也是把相应的参数放入invokeQueue数组中,只不过前两参数是$injector,invoke,这里先透露一下,其实所有invokeQueue数组项中,三个参数的意思:第一个参数调用第二个参数,然后传递第三个参数,这个后面会讲到. 这里说下ng模块中第三个参数里的函数体,这里主要做了两件事,初始了$compile服务,并且利用compile服务的directive方法,把一些常用的指令都保存到compile服务中的一个内部数组中. 这里先说下$provide.provider,这个在angular里用的比较多,其实就是提前把定义的provider放入DI函数内的providerCache内,看如下代码,在740行
AngularJS简介
从启动开始说起
bindJQuery(), publishExternalAPI(angular), jqLite(document).ready(function() {
angularInit(document, bootstrap)
})
function publishExternalAPI(angular) {
extend(angular, {
bootstrap: bootstrap,
copy: copy,
extend: extend,
equals: equals,
element: jqLite,
forEach: forEach,
injector: createInjector,
noop: noop,
bind: bind,
toJson: toJson,
fromJson: fromJson,
identity: identity,
isUndefined: isUndefined,
isDefined: isDefined,
isString: isString,
isFunction: isFunction,
isObject: isObject,
isNumber: isNumber,
isElement: isElement,
isArray: isArray,
version: version,
isDate: isDate,
lowercase: lowercase,
uppercase: uppercase,
callbacks: {
counter: 0
},
$$minErr: minErr,
$$csp: csp
}), angularModule = setupModuleLoader(window);
try
{
angularModule("ngLocale")
} catch
(e) {
angularModule("ngLocale", []).provider("$locale", $LocaleProvider)
}
angularModule("ng", ["ngLocale"], ["$provide",
function($provide) {
$provide.provider("$compile", $CompileProvider).directive({
a: htmlAnchorDirective,
input: inputDirective,
textarea: inputDirective,
form: formDirective,
script: scriptDirective,
select: selectDirective,
style: styleDirective,
option: optionDirective,
ngBind: ngBindDirective,
ngBindHtml: ngBindHtmlDirective,
ngBindTemplate: ngBindTemplateDirective,
ngClass: ngClassDirective,
ngClassEven: ngClassEvenDirective,
ngClassOdd: ngClassOddDirective,
ngCloak: ngCloakDirective,
ngController: ngControllerDirective,
ngForm: ngFormDirective,
ngHide: ngHideDirective,
ngIf: ngIfDirective,
ngInclude: ngIncludeDirective,
ngInit: ngInitDirective,
ngNonBindable: ngNonBindableDirective,
ngPluralize: ngPluralizeDirective,
ngRepeat: ngRepeatDirective,
ngShow: ngShowDirective,
ngStyle: ngStyleDirective,
ngSwitch: ngSwitchDirective,
ngSwitchWhen: ngSwitchWhenDirective,
ngSwitchDefault: ngSwitchDefaultDirective,
ngOptions: ngOptionsDirective,
ngTransclude: ngTranscludeDirective,
ngModel: ngModelDirective,
ngList: ngListDirective,
ngChange: ngChangeDirective,
required: requiredDirective,
ngRequired: requiredDirective,
ngValue: ngValueDirective
}).directive(ngAttributeAliasDirectives).directive(ngEventDirectives), $provide.provider({
$anchorScroll: $AnchorScrollProvider,
$animate: $AnimateProvider,
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$document: $DocumentProvider,
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$interpolate: $InterpolateProvider,
$interval: $IntervalProvider,
$http: $HttpProvider,
$httpBackend: $HttpBackendProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
$sce: $SceProvider,
$sceDelegate: $SceDelegateProvider,
$sniffer: $SnifferProvider,
$templateCache: $TemplateCacheProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider
})
}
])
}
function setupModuleLoader(window) {
function
ensure(obj, name, factory) {
return
obj[name] || (obj[name] = factory())
}
var
$injectorMinErr = minErr("$injector"),
ngMinErr = minErr("ng");
return
ensure(ensure(window, "angular", Object), "module", function() {
var
modules = {};
return
function(name, requires, configFn) {
var
assertNotHasOwnProperty = function(name, context) {
if
("hasOwnProperty"
=== name) throw
ngMinErr("badname", "hasOwnProperty is not a valid {0} name", context)
};
return
assertNotHasOwnProperty(name, "module"), requires && modules.hasOwnProperty(name) && (modules[name] = null), ensure(modules, name, function() {
function
invokeLater(provider, method, insertMethod) {
return
function() {
return
invokeQueue[insertMethod || "push"]([provider, method, arguments]), moduleInstance
}
}
if
(!requires) throw
$injectorMinErr("nomod", "Module ‘{0}‘ is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.", name);
var
invokeQueue = [],
runBlocks = [],
config = invokeLater("$injector", "invoke"),
moduleInstance = {
_invokeQueue: invokeQueue,
_runBlocks: runBlocks,
requires: requires,
name: name,
provider: invokeLater("$provide", "provider"),
factory: invokeLater("$provide", "factory"),
service: invokeLater("$provide", "service"),
value: invokeLater("$provide", "value"),
constant: invokeLater("$provide", "constant", "unshift"),
animation: invokeLater("$animateProvider", "register"),
filter: invokeLater("$filterProvider", "register"),
controller: invokeLater("$controllerProvider", "register"),
directive: invokeLater("$compileProvider", "directive"),
config: config,
run: function(block) {
return
runBlocks.push(block), this
}
};
return
configFn && config(configFn), moduleInstance
})
}
})
}
function invokeLater(provider, method, insertMethod) {
return
function() {
return
invokeQueue[insertMethod || "push"]([provider, method, arguments]), moduleInstance
}
}
angular.module(‘demoApp‘, [])
.factory().controller().directive().config().run();
function createInjector(modulesToLoad) {
function
supportObject(delegate) {
return
function(key, value) {
return
isObject(key) ? (forEach(key, reverseParams(delegate)), void 0) : delegate(key, value)
}
}
function
provider(name, provider_) {
if
(assertNotHasOwnProperty(name, "service"), (isFunction(provider_) || isArray(provider_)) && (provider_ = providerInjector.instantiate(provider_)), !provider_.$get) throw
$injectorMinErr("pget", "Provider ‘{0}‘ must define $get factory method.", name);
return
providerCache[name + providerSuffix] = provider_
}
function
factory(name, factoryFn) {
return
provider(name, {
$get: factoryFn
})
}
function
service(name, constructor) {
return
factory(name, ["$injector",
function($injector) {
return
$injector.instantiate(constructor)
}
])
}
function
value(name, val) {
return
factory(name, valueFn(val))
}
function
constant(name, value) {
assertNotHasOwnProperty(name, "constant"), providerCache[name] = value, instanceCache[name] = value
}
function
decorator(serviceName, decorFn) {
var
origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;
origProvider.$get = function() {
var
origInstance = instanceInjector.invoke(orig$get, origProvider);
return
instanceInjector.invoke(decorFn, null, {
$delegate: origInstance
})
}
}
function
loadModules(modulesToLoad) {
var
moduleFn, invokeQueue, i, ii, runBlocks = [];
return
forEach(modulesToLoad, function(module) {
if
(!loadedModules.get(module)) {
loadedModules.put(module, !0);
try
{
if
(isString(module))
for
(moduleFn = angularModule(module), runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks), invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; ii > i; i++) {
var
invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2])
} else
isFunction(module) ? runBlocks.push(providerInjector.invoke(module)) : isArray(module) ? runBlocks.push(providerInjector.invoke(module)) : assertArgFn(module, "module")
} catch
(e) {
throw
isArray(module) && (module = module[module.length - 1]), e.message && e.stack && -1 == e.stack.indexOf(e.message) && (e = e.message + "\n"
+ e.stack), $injectorMinErr("modulerr", "Failed to instantiate module {0} due to:\n{1}", module, e.stack || e.message || e)
}
}
}),runBlocks
}
function
createInternalInjector(cache, factory) {
function
getService(serviceName) {
if
(cache.hasOwnProperty(serviceName)) {
if
(cache[serviceName] === INSTANTIATING) throw
$injectorMinErr("cdep", "Circular dependency found: {0}", path.join("
)); return
cache[serviceName]
}
try
{
return
path.unshift(serviceName), cache[serviceName] = INSTANTIATING, cache[serviceName] = factory(serviceName)
} finally {
path.shift()
}
}
function
invoke(fn, self, locals) {
var
length, i, key, args = [],
$inject = annotate(fn);
for
(i = 0, length = $inject.length; length > i; i++) {
if
(key = $inject[i], "string"
!= typeof key) throw $injectorMinErr("itkn", "Incorrect injection token! Expected service name as string, got {0}", key);
args.push(locals && locals.hasOwnProperty(key) ? locals[key] : getService(key))
}
switch
(fn.$inject || (fn = fn[length]), self ? -1 : args.length) {
case
0:
return
fn();
case
1:
return
fn(args[0]);
case
2:
return
fn(args[0], args[1]);
case
3:
return
fn(args[0], args[1], args[2]);
case
4:
return
fn(args[0], args[1], args[2], args[3]);
case
5:
return
fn(args[0], args[1], args[2], args[3], args[4]);
case
6:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5]);
case
7:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case
8:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case
9:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
case
10:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
default:
return
fn.apply(self, args)
}
}
function
instantiate(Type, locals) {
var
instance, returnedValue, Constructor = function() {};
return
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype, instance = new
Constructor, returnedValue = invoke(Type, instance, locals), isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance
}
return
{
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: annotate,
has: function(name) {
return
providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name)
}
}
}
>
上一篇:C++--同名覆盖、多态