john's tech blog

hope is coming


  • 首页

  • 标签

  • 归档

angular源码分析之publishExternalAPI

发表于 2017-01-02 | 更新于 2019-05-07

publishExternalAPI

发布扩展API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

function publishExternalAPI(angular) {
//调用extend函数
//使得外部可以调用诸如angular.bootstrap等函数
extend(angular, {
'bootstrap': bootstrap,
'copy': copy,
'extend': extend,
'merge': merge,
'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},
'getTestability': getTestability,
'$$minErr': minErr,
'$$csp': csp,
'reloadWithDebugInfo': reloadWithDebugInfo
});

//返回angular.module方法
//传递(name, requires, configFn)
angularModule = setupModuleLoader(window);

//调用angular.module方法
//angular.module = function(name, requires, configFn)
//angular.module维护了一个 modules变量
//ng name参数
//['ngLocale'] 是 requires参数
//['$provide',function(){}] 是 configFn参数
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
// $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
$provide.provider({
$$sanitizeUri: $$SanitizeUriProvider
});
//用 injector.invoke时候放入providerCache
$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,
pattern: patternDirective,
ngPattern: patternDirective,
required: requiredDirective,
ngRequired: requiredDirective,
minlength: minlengthDirective,
ngMinlength: minlengthDirective,
maxlength: maxlengthDirective,
ngMaxlength: maxlengthDirective,
ngValue: ngValueDirective,
ngModelOptions: ngModelOptionsDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
$provide.provider({
$anchorScroll: $AnchorScrollProvider,
$animate: $AnimateProvider,
$animateCss: $CoreAnimateCssProvider,
$$animateJs: $$CoreAnimateJsProvider,
$$animateQueue: $$CoreAnimateQueueProvider,
$$AnimateRunner: $$AnimateRunnerFactoryProvider,
$$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$document: $DocumentProvider,
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$$forceReflow: $$ForceReflowProvider,
$interpolate: $InterpolateProvider,
$interval: $IntervalProvider,
$http: $HttpProvider,
$httpParamSerializer: $HttpParamSerializerProvider,
$httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
$httpBackend: $HttpBackendProvider,
$xhrFactory: $xhrFactoryProvider,
$jsonpCallbacks: $jsonpCallbacksProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
$$q: $$QProvider,
$sce: $SceProvider,
$sceDelegate: $SceDelegateProvider,
$sniffer: $SnifferProvider,
$templateCache: $TemplateCacheProvider,
$templateRequest: $TemplateRequestProvider,
$$testability: $$TestabilityProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider,
$$rAF: $$RAFProvider,
$$jqLite: $$jqLiteProvider,
$$HashMap: $$HashMapProvider,
$$cookieReader: $$CookieReaderProvider
});
}
]);

angular变量

publishExternalAPI中使用到了angular变量,我们看看它在哪定义的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var
msie, // holds major version number for IE, or NaN if UA is not IE.
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
splice = [].splice,
push = [].push,
toString = Object.prototype.toString,
getPrototypeOf = Object.getPrototypeOf,
ngMinErr = minErr('ng'),

/** @name angular */
//默认在window变量下
angular = window.angular || (window.angular = {}),
angularModule,
uid = 0;

extend扩展函数

publishExternalAPI中使用到了extend函数,我们看看它在哪定义的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

//内部调用baseExtend函数
function extend(dst) {
//slice函数
//一个新的字符串。包括字符串 stringObject 从 start 开始(包括 start)到 end 结束(不包括 end)为止的所有字符。
return baseExtend(dst, slice.call(arguments, 1), false);
}
//扩展dst对象
//deep是否深度拷贝
//默认false
function baseExtend(dst, objs, deep) {
var h = dst.$$hashKey;

for (var i = 0, ii = objs.length; i < ii; ++i) {
var obj = objs[i];
if (!isObject(obj) && !isFunction(obj)) continue;
var keys = Object.keys(obj);
for (var j = 0, jj = keys.length; j < jj; j++) {
var key = keys[j];
var src = obj[key];

if (deep && isObject(src)) {
if (isDate(src)) {
dst[key] = new Date(src.valueOf());
} else if (isRegExp(src)) {
dst[key] = new RegExp(src);
} else if (src.nodeName) {
dst[key] = src.cloneNode(true);
} else if (isElement(src)) {
dst[key] = src.clone();
} else {
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
baseExtend(dst[key], [src], true);
}
} else {
dst[key] = src;
}
}
}

setHashKey(dst, h);
return dst;
}

publishExternalAPI最终在源码最后调用,到这时才定义了angular.module方法。

angular_源码分析之初始变量

发表于 2016-12-30 | 更新于 2019-05-07

变量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  //String正则
//. 正则表示 除\n外的任意字符
// + 表示 1 到无穷
var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;

// The name of a form control's ValidityState property.
// This is used so that it's possible for internal tests to create mock ValidityStates.
var VALIDITY_STATE_PROPERTY = 'validity';

var hasOwnProperty = Object.prototype.hasOwnProperty;

var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};


var manualLowercase = function(s) {
/* jshint bitwise: false */
//根据charCodeAt来区分

//charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
return isString(s)
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
: s;
};
var manualUppercase = function(s) {
/* jshint bitwise: false */

//位运算符由否定好(~)表示,它是ECMAScript中为数不多的与二进制算术有关的运算符之一。位运算符NOT是三步的处理过程:
//把运算数转为32位二进制数字
//再转为它的二进制反码
//把二进制反码转为浮点数
//参考 https://my.oschina.net/luozt/blog/302294
//http://www.cnblogs.com/oneword/archive/2009/12/23/1631039.html
//10 = 1010
// 反码 0101
//http://blog.sina.com.cn/s/blog_77abbf390100qwss.html

//负数的二进制表示方法
//http://www.360doc.com/content/12/0801/17/6828497_227700914.shtml

return isString(s)
? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
: s;
};

//Turkish 是啥玩意
// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
if ('i' !== 'I'.toLowerCase()) {
lowercase = manualLowercase;
uppercase = manualUppercase;
}


var
msie, // holds major version number for IE, or NaN if UA is not IE.
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
splice = [].splice,
push = [].push,
toString = Object.prototype.toString,
getPrototypeOf = Object.getPrototypeOf,
ngMinErr = minErr('ng'),

/** @name angular */
angular = window.angular || (window.angular = {}),
angularModule,
uid = 0;

/**
*documentMode 是IE独有的属性
* documentMode is an IE-only property
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
*/

msie = window.document.documentMode;

REGEX_STRING_REGEXP用法

REGEX_STRING_REGEXP 在源码22232行使用:

里面涉及到了forEach函数还有ngAttributeAliasDirectives

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//别名属性对象
var ALIASED_ATTR = {
'ngMinlength': 'minlength',
'ngMaxlength': 'maxlength',
'ngMin': 'min',
'ngMax': 'max',
'ngPattern': 'pattern'
};
// aliased input attrs are evaluated
//别名属性被求值
//遍历
//定义ngAttributeAliasDirectives
forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
ngAttributeAliasDirectives[ngAttr] = function() {
return {
priority: 100,
link: function(scope, element, attr) {
//ngPattern的特殊例子
//当一个字面意义的正则被用作表达式时
//这种我们就不必watch任何东西了。
//比如ng-pattern="/[a-zA-Z]/"
//special case ngPattern when a literal regular expression value
//is used as the expression (this way we don't have to watch anything).
if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
if (match) {
attr.$set("ngPattern", new RegExp(match[1], match[2]));
return;
}
}

scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
attr.$set(ngAttr, value);
});
}
};
};
});

foreach函数

foreach第一个参数为值,第二个参数为键,源码分析可以看我的另一篇博客
angular1.5.8 foreach 源码分析

1
2
3
4
5
for (key in obj) {
if (hasOwnProperty.call(obj, key)) {
iterator.call(context, obj[key], key, obj);
}
}

ngAttributeAliasDirectives

ngAttributeAliasDirectives在publishExternalAPI函数中使用到了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$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,
pattern: patternDirective,
ngPattern: patternDirective,
required: requiredDirective,
ngRequired: requiredDirective,
minlength: minlengthDirective,
ngMinlength: minlengthDirective,
maxlength: maxlengthDirective,
ngMaxlength: maxlengthDirective,
ngValue: ngValueDirective,
ngModelOptions: ngModelOptionsDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);

参考资料:
AngularJS使用ngMessages进行表单验证
AngularJS 最常用的八种功能

jquery_attr

发表于 2016-12-30 | 更新于 2019-05-07

jquery1.0 attr 函数分析

先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

attr: function( key, value, type ) {
// Check to see if we're setting style values
//检查是否是设置属性
return key.constructor != String || value != undefined ?
this.each(function(){
// See if we're setting a hash of styles
//key是一个对象
//例如 { "width":“15px”}
if ( value == undefined )
// Set all the styles
for ( var prop in key )
jQuery.attr(
type ? this.style : this,
prop, key[prop]
);

// See if we're setting a single key/value style
else
jQuery.attr(
type ? this.style : this,//这边的this已经是dom对象
key, value
);
}) :

// Look for the case where we're accessing a style value
//读取属性值 css ->调用静态方法jQuery.curCSS
jQuery[ type || "attr" ]( this[0], key );
}

jquery1.0 静态 attr函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
attr: function(elem, name, value){
var fix = {
"for": "htmlFor",
"class": "className",
"float": "cssFloat",
innerHTML: "innerHTML",
className: "className"
};

if ( fix[name] ) {
if ( value != undefined ) elem[fix[name]] = value;
return elem[fix[name]];
} else if ( elem.getAttribute ) {
if ( value != undefined ) elem.setAttribute( name, value );
return elem.getAttribute( name, 2 );
} else {
name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});
if ( value != undefined ) elem[name] = value;
return elem[name];
}
}

从中我们可以学到如下几点:

jquery.each方法

jquery静态方法的调用

dom是如何给元素设置属性的

一个函数中既包含设置又包含读取的功能

jquery_wrap

发表于 2016-12-30 | 更新于 2019-05-07

jquery1.0 wrap函数分析

先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
wrap: function() {
// The elements to wrap the target around
//包装目标元素的元素
var a = jQuery.clean(arguments);

// Wrap each of the matched elements individually
return this.each(function(){
// Clone the structure that we're using to wrap
var b = a[0].cloneNode(true);//选择a[0]元素

// Insert it before the element to be wrapped
//在当前元素之前插入包装节点
this.parentNode.insertBefore( b, this );

// Find he deepest point in the wrap structure
//找出最深的第一个包装的元素
while ( b.firstChild )
b = b.firstChild;

// Move the matched element to within the wrap structure
//把匹配的当前元素移动到包装元素内
b.appendChild( this );
});
}

从中我们可以学到以下几点:

dom元素的操作

jquery.clean方法的应用

关于jquery.clean方法我们已经在之前这篇博客中分析过

slf4j_MDC

发表于 2016-12-29 | 更新于 2019-05-09

slf4j MDC

A lighter technique consists of uniquely stamping each log request servicing a given client. Neil Harrison described this method in the book Patterns for Logging Diagnostic Messages in Pattern Languages of Program Design 3, edited by R. Martin, D. Riehle, and F. Buschmann (Addison-Wesley, 1997).

Logback leverages a variant of this technique included in the SLF4J API: Mapped Diagnostic Contexts (MDC).

在分布式系统中,各种无关日志穿行其中,导致我们可能无法直接定位整个操作流程。因此,我们可能需要对一个用户的操作流程进行归类标记,比如使用线程+时间戳,或者用户身份标识等;如此,我们可以从大量日志信息中grep出某个用户的操作流程,或者某个时间的流转记录。

因此,这就有了 Slf4j MDC 方法

转载自Slf4j MDC 使用和 基于 Logback 的实现分析

LogBack sl4j 通过MDC实现日志记录区分用户Session

slf4j-api MDC类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

/**
*内部静态类
* An adapter to remove the key when done.
*/

public static class MDCCloseable implements Closeable {
private final String key;

private MDCCloseable(String key) {
this.key = key;
}

public void close() {
MDC.remove(this.key);
}
}

Java中的类可以是static吗?答案是可以。在java中我们可以有静态实例变量、静态方法、静态块。类也可以是静态的

静态内部类只能访问外部类的静态成员

静态内部类和非静态内部类之间到底有什么不同呢?下面是两者间主要的不同。

内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。

非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。

一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

参考资料:
java中的Static class

1…323334…47

John

232 日志
43 标签
GitHub Twitter
欢迎关注我的公众号:沉迷Spring
© 2023 johnwonder
由 Hexo 强力驱动 v3.2.0
|
主题 – NexT.Pisces v7.1.1
|
0%