предисловие
Здравствуйте, яВакагава. Это
学习源码整体架构
первый раз. Слово «общая архитектура» кажется немного большим, скажем так, это общая структура исходного кода. В этой статье рассказывается об упакованном и интегрированном коде, а не о разделенном коде на реальном складе.
学习源码整体架构
Цикл статей следующий:
1.Изучите общую архитектуру исходного кода jQuery и создайте собственную библиотеку js.
2.Изучите общую архитектуру исходного кода подчеркивания и создайте собственную библиотеку классов функционального программирования.
3.Изучите общую архитектуру исходного кода lodash и создайте собственную библиотеку классов функционального программирования.
4.Изучите общую архитектуру исходного кода sentry и создайте собственный SDK для мониторинга исключений переднего плана.
5.Изучите общую архитектуру исходного кода vuex и создайте собственную библиотеку управления состоянием.
6.Изучите общую архитектуру исходного кода axios и создайте собственную библиотеку запросов.
7.Изучите общую архитектуру исходного кода koa, проанализируйте принцип луковой модели koa и принцип совместной работы.
8.Изучите общую архитектуру исходного кода Redux и глубоко поймите принципы Redux и его промежуточного программного обеспечения.
Заинтересованные читатели могут нажать, чтобы прочитать.
Хотя сейчас почти не используетсяjQuery
, ноjQuery
Популярность10多年
изJS库
, еще надо узнать его исходный код. Вы также можете научиться создавать свои собственныеjs
Библиотека классов, которая может многое добавить к собеседованию.
Эта статья учитv3.4.1
Версия.unpkg.com
Исходный адрес: https://unpkg.com/jquery@3.4.1/dist/jquery.js
самовыполняющаяся анонимная функция
(function(global, factory){
})(typeof window !== "underfined" ? window: this, function(window, noGlobal){
});
Внешний мир не может получить доступ к внутренним переменным и функциям, но к внешним переменным можно получить доступ изнутри, но если внутри определены его собственные переменные, то к внешним переменным не будет доступа. Анонимные функции оборачивают код внутрь, предотвращая конфликты с другим кодом и загрязняя глобальную среду. Читатели, не очень хорошо знакомые с самоисполняемыми функциями, могут обратиться к этой статье.JavaScript: немедленное выполнение функционального выражения (IIFE)
В среде браузера, наконец, поместите$
а такжеjQuery
функция монтируется наwindow
, поэтому к нему можно получить доступ извне$
а такжеjQuery
.
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
// 其中`noGlobal`参数只有在这里用到。
Поддержка использования в различных средах, таких как commonjs, спецификации amd.
поддержка спецификации commonjs
commonjs
Достичь главного представителяnodejs
// global是全局变量,factory 是函数
( function( global, factory ) {
// 使用严格模式
"use strict";
// Commonjs 或者 CommonJS-like 环境
if ( typeof module === "object" && typeof module.exports === "object" ) {
// 如果存在global.document 则返回factory(global, true);
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
// Pass this if window is not defined yet
// 第一个参数判断window,存在返回window,不存在返回this
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {});
Спецификация amd в основном представляет собой requirejs
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
Спецификация cmd в основном представляет seajs
К сожалению,jQuery
В исходном коде нет экспозицииseajs
служба поддержки. Но есть и варианты онлайн. Здесь он не будет упоминаться подробно. Ведь сейчас это в принципе бесполезноseajs
.
нет новой конструкции
На самом деле это можетnew
, потому чтоjQuery
это функция. и безnew
Эффект тот же.
new показывает возвращаемый объект, поэтому и вызывается напрямуюjQuery
Эффект от функции такой же.
если правильноnew
Я не знаю, что именно делает оператор. См. мою предыдущую статью.
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
Исходный код:
var
version = "3.4.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// 返回new之后的对象
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {
// jQuery当前版本
jquery: version,
// 修正构造器为jQuery
constructor: jQuery,
length: 0,
};
init = jQuery.fn.init = function( selector, context, root ) {
// ...
if ( !selector ) {
return this;
}
// ...
};
init.prototype = jQuery.fn;
jQuery.fn === jQuery.prototype; // true
init = jQuery.fn.init;
init.prototype = jQuery.fn;
// 也就是
jQuery.fn.init.prototype === jQuery.fn; // true
jQuery.fn.init.prototype === jQuery.prototype; // true
Об этом автор нарисовал картинуjQuery
Диаграмма-прототип, так называемая картинка, стоит тысячи слов.
<sciprt src="https://unpkg.com/jquery@3.4.1/dist/jquery.js">
</script>
console.log({jQuery});
// 在谷歌浏览器控制台,可以看到jQuery函数下挂载了很多静态属性和方法,在jQuery.fn 上也挂着很多属性和方法。
Vue
В исходном коде также следуйтеjQuery
Точно так же выполняетсяVue.prototype._init
метод.
function Vue (options) {
if (!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
initMixin(Vue);
function initMixin (Vue) {
Vue.prototype._init = function (options) {};
};
Одна из основных функций расширения
Применение:
jQuery.extend( target [, object1 ] [, objectN ] ) Returns: Object
jQuery.extend( [deep ], target, object1 [, objectN ] )
jQuery.extend API jQuery.fn.extend API
Посмотрите несколько примеров: (Пример можно разместить в коде онлайн-редактированияПример кода jQuery.extend, вы можете запустить его напрямую).
// 1. jQuery.extend( target)
var result1 = $.extend({
job: '前端开发工程师',
});
console.log(result1, 'result1', result1.job); // $函数 加了一个属性 job // 前端开发工程师
// 2. jQuery.extend( target, object1)
var result2 = $.extend({
name: '若川',
},
{
job: '前端开发工程师',
});
console.log(result2, 'result2'); // { name: '若川', job: '前端开发工程师' }
// deep 深拷贝
// 3. jQuery.extend( [deep ], target, object1 [, objectN ] )
var result3 = $.extend(true, {
name: '若川',
other: {
mac: 0,
ubuntu: 1,
windows: 1,
},
}, {
job: '前端开发工程师',
other: {
mac: 1,
linux: 1,
windows: 0,
}
});
console.log(result3, 'result3');
// deep true
// {
// "name": "若川",
// "other": {
// "mac": 1,
// "ubuntu": 1,
// "windows": 0,
// "linux": 1
// },
// "job": "前端开发工程师"
// }
// deep false
// {
// "name": "若川",
// "other": {
// "mac": 1,
// "linux": 1,
// "windows": 0
// },
// "job": "前端开发工程师"
// }
В заключение:extend
Функция может быть реализована какjQuery
Функция может реализовать поверхностную копию или глубокую копию. Вы можете добавить статические методы и свойства в jQuery или использовать их какjQuery.fn
(то есть,jQuery.prototype
) для добавления свойств и методов, благодаряthis
,jQuery.extend
когда звонятthis
указать даjQuery
,jQuery.fn.extend
когда звонятthis
указать наjQuery.fn
.
Неглубокая реализация копирования
Зная это, на самом деле относительно легко реализовать поверхностную копию:
// 浅拷贝实现
jQuery.extend = function(){
// options 是扩展的对象object1,object2...
var options,
// object对象上的键
name,
// copy object对象上的值,也就是是需要拷贝的值
copy,
// 扩展目标对象,可能不是对象,所以或空对象
target = arguments[0] || {},
// 定义i为1
i = 1,
// 定义实参个数length
length = arguments.length;
// 只有一个参数时
if(i === length){
target = this;
i--;
}
for(; i < length; i++){
// 不是underfined 也不是null
if((options = arguments[i]) != null){
for(name in options){
copy = options[name];
// 防止死循环,continue 跳出当前此次循环
if ( name === "__proto__" || target === copy ) {
continue;
}
if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// 最后返回目标对象
return target;
}
Глубокая копия в основном оценивается по следующему коду. Может быть значением массива и типом ссылки на объект, делайте выводы.
if ( copy !== undefined ) {
target[ name ] = copy;
}
Чтобы облегчить читателям отладку, код также помещен вjQuery.extend неглубокий код копирования для реализации codepen, который можно запустить онлайн.
реализация глубокого копирования
$.extend = function(){
// options 是扩展的对象object1,object2...
var options,
// object对象上的键
name,
// copy object对象上的值,也就是是需要拷贝的值
copy,
// 深拷贝新增的四个变量 deep、src、copyIsArray、clone
deep = false,
// 源目标,需要往上面赋值的
src,
// 需要拷贝的值的类型是函数
copyIsArray,
//
clone,
// 扩展目标对象,可能不是对象,所以或空对象
target = arguments[0] || {},
// 定义i为1
i = 1,
// 定义实参个数length
length = arguments.length;
// 处理深拷贝情况
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
// target目标对象开始后移
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
// target不等于对象,且target不是函数的情况下,强制将其赋值为空对象。
if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
// 只有一个参数时
if(i === length){
target = this;
i--;
}
for(; i < length; i++){
// 不是underfined 也不是null
if((options = arguments[i]) != null){
for(name in options){
copy = options[name];
// 防止死循环,continue 跳出当前此次循环
if ( name === "__proto__" || target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
// 这里deep为true,并且需要拷贝的值有值,并且是纯粹的对象
// 或者需拷贝的值是数组
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
// 源目标,需要往上面赋值的
src = target[ name ];
// Ensure proper type for the source value
// 拷贝的值,并且src不是数组,clone对象改为空数组。
if ( copyIsArray && !Array.isArray( src ) ) {
clone = [];
// 拷贝的值不是数组,对象不是纯粹的对象。
} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
// clone 赋值为空对象
clone = {};
} else {
// 否则 clone = src
clone = src;
}
// 把下一次循环时,copyIsArray 需要重新赋值为false
copyIsArray = false;
// Never move original objects, clone them
// 递归调用自己
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
}
else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// 最后返回目标对象
return target;
};
Чтобы облегчить читателям отладку, этот код также помещен вjQuery.extend код глубокого копирования для реализации codepen, который можно запустить онлайн.
производная функция глубокого копирования isFunction
Определяет, является ли параметр функцией.
var isFunction = function isFunction( obj ) {
// Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don't want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
Функция глубокого копирования, полученная из jQuery.isPlainObject
jQuery.isPlainObject(obj)
Проверяет, является ли объект чистым объектом (созданный с помощью «{}» или «новый объект»).
jQuery.isPlainObject({}) // true
jQuery.isPlainObject("test") // false
var getProto = Object.getPrototypeOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call( Object );
jQuery.extend( {
isPlainObject: function( obj ) {
var proto, Ctor;
// Detect obvious negatives
// Use toString instead of jQuery.type to catch host objects
// !obj 为true或者 不为[object Object]
// 直接返回false
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
return false;
}
proto = getProto( obj );
// Objects with no prototype (e.g., `Object.create( null )`) are plain
// 原型不存在 比如 Object.create(null) 直接返回 true;
if ( !proto ) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
// 构造器是函数,并且 fnToString.call( Ctor ) === fnToString.call( Object );
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
},
});
extend
функцию, вы также можете удалить и записать ее самостоятельно.jQuery
Одна из основных функций. И он имеет широкий спектр применений, которые можно использовать внутри или снаружи, например, в виде подключаемых модулей расширения.
цепной вызов
jQuery
Может быть сцеплен, потому что некоторые функции выполняются послеreturn this
.
НапримерjQuery
в исходном кодеaddClass
,removeClass
,toggleClass
.
jQuery.fn.extend({
addClass: function(){
// ...
return this;
},
removeClass: function(){
// ...
return this;
},
toggleClass: function(){
// ...
return this;
},
});
jQuery.noConflict
многоjs
Функция предотвращения столкновений, которую будет иметь библиотека
Применение:
<script>
var $ = '我是其他的$,jQuery不要覆盖我';
</script>
<script src="./jquery-3.4.1.js">
</script>
<script>
$.noConflict();
console.log($); // 我是其他的$,jQuery不要覆盖我
</script>
Исходный код jQuery.noConflict
var
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$;
jQuery.noConflict = function( deep ) {
// 如果已经存在$ === jQuery;
// 把已存在的_$赋值给window.$;
if ( window.$ === jQuery ) {
window.$ = _$;
}
// 如果deep为 true, 并且已经存在jQuery === jQuery;
// 把已存在的_jQuery赋值给window.jQuery;
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
// 最后返回jQuery
return jQuery;
};
Суммировать
Тезис через анализjQuery
Общая структура, самовыполняющаяся анонимная функция, нетnew
Создание, поддержка различных спецификаций (таких как commonjs, amd), основные функцииextend
цепной звонок,jQuery.noConflict
и т.п.
Реорганизуйте структуру исходного кода, описанную ниже.
// 源码结构
( function( global, factory )
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
var version = "3.4.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
};
jQuery.fn = jQuery.prototype = {
jquery: version,
constructor: jQuery,
length: 0,
// ...
};
jQuery.extend = jQuery.fn.extend = function() {};
jQuery.extend( {
// ...
isPlainObject: function( obj ) {},
// ...
});
init = jQuery.fn.init = function( selector, context, root ) {};
init.prototype = jQuery.fn;
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
jQuery.noConflict = function( deep ) {};
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
return jQuery;
});
может научитьсяjQuery
Гениальный дизайн и архитектура для вашего собственного использования, чтобы создать свой собственныйjs
Библиотека класса.
Соответствующий код и ресурсы размещены вgithub blog, читатели, которым это нужно, могут подобрать его самостоятельно.
Следующая статья, чтобы узнатьunderscorejs
Общая структура исходного кода.Изучите общую архитектуру исходного кода подчеркивания и создайте собственную библиотеку классов функционального программирования.
Читатели, которые находят что-то неправильным или могут быть улучшены, могут оставить комментарий. Кроме того, если вы считаете, что написано хорошо, вы можете поставить лайк, прокомментировать и переслать, что также является своего рода поддержкой для автора.
Предыдущие статьи автора
Интервьюер спросил: наследование JS
Интервьюер спросил: этот пункт JS
Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
Внешний интерфейс использует сканер puppeteer для создания PDF-файла «React.js Book» и его слияния.
Расширенное чтение
chokcoco: интерпретация исходного кода jQuery-v1.10.2
chokcoco: [углубленный jQuery] анализ исходного кода — общая архитектура
songjz: серия исходных кодов jQuery (1) Общая архитектура
Очередная серия автора
Интервьюер спросил: наследование JS
Интервьюер спросил: этот пункт JS
Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
о
Автор: Чанг ИВакагаваНазвание смешано в реках и озерах. По дороге на фронт | Энтузиасты РРТ | Знаю очень мало, только хорошо учусь.
Блог Вакагавы,использоватьvuepress
Рефакторинг, опыт чтения может быть лучше
Колонка самородков, добро пожаловать, обратите внимание~
segmentfault
Передняя колонка обзора, добро пожаловать, обратите внимание~
Колонна переднего обзора Yuque, новая колонка Yuque, добро пожаловать на внимание~
Знайте переднюю колонку видения, добро пожаловать, обратите внимание~
github blog, соответствующий исходный код и ресурсы размещены здесь, попросите одинstar
^_^~
Добро пожаловать, чтобы добавить общедоступную учетную запись WeChat для общения в WeChat
Может быть более интересным общедоступный аккаунт WeChat, нажмите и удерживайте, чтобы отсканировать код, чтобы следовать. Добро пожаловать, чтобы добавить автора WeChatruochuan12
(Укажите источник, в основном никто не будет отклонен), пригласите вас в [Группу обмена видением переднего плана] для долгосрочного обмена и обучения ~
В этой статье используетсяmdniceнабор текста