艾伦说啊,学习javascript,必须要学会看源码,通过高手的源码,你可以从中吸取很多书本上难以看到的技巧。

看源码就好像喝鸡汤,所有的营养都在这汤里了。这汤就是源码,高手写的源码,就是最好的鸡汤。

这也是他短短两年时间,快速在前端界崭头露角,成为一名新星的原因。一般人,他不会说的,但是我觉得,好东西就要分享。

这样才能让前端界有更多新星出现,为推进整个前端的健康发展做出贡献。

他的这些源码经验,不知道会不会在他的新书里出现。如果有,算是提前爆料了。

下面就是我这些天,一边实践,一边总结的一些方法。

我以艾伦的一个模块类require.js为例。

require.js的源码:

/****************************************************************
* 支持AMD,CMD模块加载方式
* @by Aaron
* github:https://github.com/JsAaron/aaronRequire
* blog:http://www.cnblogs.com/aaronjs/
*****************************************************************/
;(function(r) {
if (typeof module === "object" && typeof require === "function") {
module.exports.require = r.require;
module.exports.define = r.define;
} else {
require = r.require;
define = r.define;
}
})(function() {
var objproto = Object.prototype,
objtoString = objproto.toString,
arrproto = Array.prototype,
nativeForEach = arrproto.forEach,
modules = {},
pushStack = {}; function each(obj, callback, context) {
if (obj == null) return;
//如果支持本地forEach方法,并且是函数
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(callback, context);
} else if (obj.length === +obj.length) {
//for循环迭代
for (var i = 0, l = obj.length; i < l; i++) {
if (callback.call(context, obj[i], i, obj) === breaker) return;
}
}
}; function isFunction(it) {
return objtoString.call(it) === '[object Function]';
} function isArray(it) {
return objtoString.call(it) === '[object Array]';
} //解析依赖关系
function parseDeps(module) {
var deps = module['deps'],
temp = [];
each(deps, function(id, index) {
temp.push(build(modules[id]))
}) return temp;
} function build(module) {
var depsList,existMod,
factory = module.factory,
id = module.id; if (existMod = pushStack[id]) { //去重复执行
return existMod;
} //接口点,将数据或方法定义在其上则将其暴露给外部调用。
module.exports = {}; //去重
delete module.factory; if (module.deps) {
//依赖数组列表
depsList = parseDeps(module);
module.exports = factory.apply(module, depsList);
} else {
// exports 支持直接 return 或 modulejs.exports 方式
module.exports = factory(require, module.exports, module) || module.exports;
} pushStack[id] = module.exports; return module.exports;
} //解析require模块
function makeRequire(ids, callback) {
var r = ids.length,
shim = [];
while (r--) {
shim.unshift(build(modules[ids[r]]));
}
if (callback) {
callback.apply(null, shim);
} else {
shim = null;
}
} return {
//引入模块
require: function(id, callback) {
//数组形式
//require(['domReady', 'App'], function(domReady, app) {});
if (isArray(id)) {
if (id.length > 1) {
return makeRequire(id, callback);
}
id = id[0];
} if (!modules[id]) {
throw "module " + id + " not found";
} if (callback) {
var module = build(modules[id]);
callback(module)
return module;
} else {
if (modules[id].factory) {
return build(modules[id]);
}
return modules[id].exports;
}
},
//定义模块
define: function(id, deps, factory) { //模块名,依赖列表,模块本身
if (modules[id]) {
throw "module " + id + " 模块已存在!";
}
//存在依赖导入
if (arguments.length === 3) {
modules[id] = {
id : id,
deps : deps,
factory : factory
};
} else {
modules[id] = {
id : id,
factory : deps
};
}
}
} }());
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>changsha,Aaron</title> <!-- 引用自Aaron私有框架Xut -->
<script type="text/javascript" src="require.js"></script> </head>
<body> </body>
<script type="text/javascript">
//定义模块a
define('a',function(){
function a(){
console.log('a is fine')
//your code
}
return a
});
//定义模块b
define('b',function(){
function b(){
console.log('b is fine')
//your code
}
return b
}); //定义模块c,依赖模块a 和 b
define('c',['a','b'],function(a,b){
function c(){
a();
b();
console.log('c is fine')
//your code
}
return c
}); //引入模块c
// require('c',function(c){
// c()
// }) // //引入模块a b c
// require(['a','b','c'],function(c){
// // c()
// }) // 引入模块a,并执行
require('a')()
</script>
</html>

我推荐用谷歌浏览器调式,很方便。

学源码的第一条法则,是从函数调用处开始看。

我的demo是从define('a')开始的。这是最简单的一种情况。

打开浏览器看下

谷歌的控制台很棒,我常用有,Console用来输出日志,Resources用来查看数据

elements查看结构,样式。Sourcese用来断点调式。

今天想重点记录一下这个断点调式。

从哪里开始断,这个直接影响到调式的效果。自己摸索着体会吧。

按F11看光标经过的地方,停留在变量名上,会显示出变量存放的值。这比打一堆的console.log或者alert要方便很多

而且也不用看这个函数在哪里定义的,按F11,自动带你去。你只要在脑子里预先猜想一下,你的心中的流程和实际的是否一

样。在一些具体的方法体内,初步调式的时候,你大可跳过。先理清流程,整出大至的思路。然后看实现的细节就比较有体会了。

在明白这些实现之后,在自己重新默写一遍,看能不能实现。最后试着简化,用自己的代码去实现它。

这一路下来,你会收很多收获的。

如何从源码中学习javascript的更多相关文章

  1. Jquery源码中的Javascript基础知识(三)

    这篇主要说一下在源码中jquery对象是怎样设计实现的,下面是相关代码的简化版本: (function( window, undefined ) { // code 定义变量 jQuery = fun ...

  2. Jquery源码中的Javascript基础知识(一)

    jquery源码中涉及了大量原生js中的知识和概念,文章是我在学习两者的过程中进行的整理和总结,有不对的地方欢迎大家指正. 本文使用的jq版本为2.0.3,附上压缩和未压缩版本地址: http://a ...

  3. MVVM架构~knockoutjs系列之从Knockout.Validation.js源码中学习它的用法

    返回目录 说在前 有时,我们在使用一个插件时,在网上即找不到它的相关API,这时,我们会很抓狂的,与其抓狂,还不如踏下心来,分析一下它的源码,事实上,对于JS这种开发语言来说,它开发的插件的使用方法都 ...

  4. Jquery源码中的Javascript基础知识(二)

    接上一篇,jquery源码的这种写法叫做匿名函数自执行 (function( window, undefined ) { // code })( window ); 函数定义了两个参数window和u ...

  5. 快来!我从源码中学习到了一招Dubbo的骚操作!

    荒腔走板 大家好,我是 why,欢迎来到我连续周更优质原创文章的第 55 篇. 老规矩,先来一个简短的荒腔走板,给冰冷的技术文注入一丝色彩. 魔幻的 2020 年的上半年过去了,很多人都在朋友圈和上半 ...

  6. Jquery源码中的Javascript基础知识(四)— jQuery.fn.init方法

    $() 即调用了jQuery.fn.init方法 jQuery = function( selector, context ) { return new jQuery.fn.init( selecto ...

  7. Spring源码学习:第1步--在Spring源码中添加最简单的Demo代码

    为了最大程度地贴近Spring源码并进行学习,一种比较直接的做法是:直接在Spring源码中加入Demo代码,并进行调试. 参照以前使用Spring的经验,Spring最简单的使用方法是:一个实体类. ...

  8. Android 网络框架之Retrofit2使用详解及从源码中解析原理

    就目前来说Retrofit2使用的已相当的广泛,那么我们先来了解下两个问题: 1 . 什么是Retrofit? Retrofit是针对于Android/Java的.基于okHttp的.一种轻量级且安全 ...

  9. 访何红辉:谈谈Android源码中的设计模式

    最近Android 6.0版本的源代码开放下载,刚好分析Android源码的技术书籍<Android源码设计模式解析与实战>上市,我们邀请到它的作者何红辉,来谈谈Android源码中的设计 ...

随机推荐

  1. 使用poco 的NetSSL_OpenSSL 搭建https 服务端,使用C++客户端,java 客户端访问,python访问(python还没找到带证书访问的代码.)

    V20161028 由于项目原因,需要用到https去做一些事情. 这儿做了一些相应的研究. 这个https 用起来也是折腾人,还是研究了一周多+之前的一些积累. 目录 1,java client 通 ...

  2. dictionary 应用(绑定dgv)

    dictionary的用法://初始化添加所有车位进这队列 Utility.Effectlist.Add(); //每触发一次,用这个增加数量 Utility.Effectlist["Car ...

  3. Ubuntu14.04或16.04下Hadoop及Spark的开发配置

    对于Hadoop和Spark的开发,最常用的还是Eclipse以及Intellij IDEA. 其中,Eclipse是免费开源的,基于Eclipse集成更多框架配置的还有MyEclipse.Intel ...

  4. Xamarin的不归路-使用Gorilla Player实时预览XAML

    搞了一天,才安装好,记录一下遇到的坑,为大家节约些时间. 一.下载软件 软件下载地址:http://gorillaplayer.com/ 没有FQ前用360极速浏览器和迅雷下载了好多次都失败了.用了蓝 ...

  5. C++哈夫曼树编码和译码的实现

    一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的 ...

  6. $.load()的用法

    jquery load 事件用法 jquery load 事件用法 如果绑定给window对象,则会在所有内容加载后触发,包括窗口,框架,对象和图像.如果绑定在元素上,则当元素的内容加载完毕后触发. ...

  7. 字典NSDictionary以及NSMutableDictionary的用法总结

    做过Java语言 或者 C语言 开发的朋友应该很清楚 关键字map 吧,它可以将数据以键值对儿的形式储存起来,取值的时候通过KEY就可以直接拿到对应的值,非常方便.在Objective-C语言中 词典 ...

  8. TCPView for Windows

    TCPView是一个用来显示系统中所有的TCP和UDP端点(endpoint)列表的Windows程序,包括本地和远程的网络地址,以及TCP连接的状态.在Windows Server 2008.Vis ...

  9. 又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)

    之前在将 Memcached 客户端 EnyimMemcached 迁移 .NET Core 时被这个“坑”坑的刻骨铭心(详见以下链接),当时以为只是在构造函数中调用异步方法(注:这里的异步方法都是指 ...

  10. Mina入门实例(一)

    mina现在用的很多了,之前也有用到,但是毕竟不熟悉,于是查了一些资料,做了一些总结.看代码是最直观的,比什么长篇大论都要好.不过其中重要的理论,也要理解下. 首先是环境,程序运行需要几个包,这里用m ...