Интервьюер очень занят, но я не просто растираю горячие точки.Тема сегодняшнего обсуждения, безусловно, является точкой знаний с высоким процентом попаданий в интервью. Когда я просматривал знания функций javascript, я заметил интересный момент, что конструктор явно возвращает, и это вызвало волну мозгового штурма...
Мы знаем, что если не выполнять никаких специальных действий, при появлении нового конструктора будут выполняться следующие шаги.
- Сначала создайте новый объект, новый объект
__proto__свойство указывает на конструкторprototypeАтрибуты - На данный момент среда выполнения конструктора
thisуказывает на этот новый объект - Выполните код в конструкторе, обычно
thisДобавляйте новые свойства или методы членов к новым объектам. - Наконец, этот новый объект возвращается.
Давайте проверим это:
function Test() {
console.log(JSON.stringify(this));
console.log(this.__proto__.constructor === Test);
this.name = 'jack';
this.age = 18;
console.log(JSON.stringify(this));
}
var a = new Test();
// Chrome控制台会输出以下内容
// {}
// true
// {"name":"jack","age":18}
Это полностью соответствует нашему восприятию, никаких проблем.
внедрить новый
Затем, узнав несколько ключевых шагов в процессе реализации нового, мы также можем ответить на распространенный во время интервью вопрос: как внедрить новое?
Реализация new также означает, что ключевое слово new нельзя использовать, поэтому для выполнения такой последовательности шагов, конечно же, реализуется через функции.
// func是构造函数,...args是需要传给构造函数的参数
function myNew(func, ...args) {
// 创建一个空对象,并且指定原型为func.prototype
var obj = Object.create(func.prototype);
// new构造函数时要执行函数,同时指定this
func.call(obj, ...args);
// 最后return这个对象
return obj;
}
Используя эти четыре ключевых шага в качестве руководства, мы быстро написали реализацию кода. С этого момента я также могу осознать важность мышления: не будь инструментом, код — это инструмент!
С логикой реализации проблем нет, давайте проверим.
function Test(name, age) {
this.name = name;
this.age = age;
}
myNew(Test, '小明', 18);
// Chrome控制台会输出以下内容
// Test {name: "小明", age: 18}
Конструктор явно возвращает
Так называемый явный возврат — это активный возврат объекта в конструкторе.Упомянутый здесь объект включает не толькоObject, также содержитArray,DateО, подожди.
Мы можем попробовать:
function Test() {
this.name = 'jack';
this.age = 18;
return {
content: '我有freestyle'
}
}
new Test();
// Chrome控制台会输出以下内容
// {content: "我有freestyle"}
Затем вернуть общий тип данных, нет ли в нем смысла? Например, строки, числа? Попробуйте поесть.
function Test() {
this.name = 'jack';
this.age = 18;
return '我有freestyle'
}
new Test();
// Chrome控制台会输出以下内容
// Test {name: "jack", age: 18}
Видно, что когда мы возвращаем общий тип данных, это не повлияет на результат, и новый объект из нового все равно будет возвращен.
Мы также должны знать, что новый конструктор предназначен для создания объекта, и для вас нет смысла возвращать обычный тип данных, такой как строка, поэтому мы должны сосредоточиться на возврате специального объекта. Пожалуйста, читайте дальше.
Нет нового экземпляра
Так называемое «отсутствие новой инстанциации» относится к инстанцированию объектов без ключевого слова new (конечно, new здесь не упоминается, но только на вызывающем уровне, а нижний слой по-прежнему использует new). Мы уже сталкивались с этим при использовании jQuery.
// 实例化了一个jQuery对象,但是没有用到new
var ele = jQuery('<div>freestyle</div>');
Так как же достигается эта черная технология?
Как упоминалось ранее, мы можем вернуть пользовательский объект, явно возвращая его в конструкторе, так что здесь есть место для игры. Давайте почувствуем это на простом примере:
function Shadow() {
this.name = 'jack';
this.age = 18;
}
function jQuery() {
return new Shadow();
}
var obj1 = jQuery();
console.log(obj1)
// Chrome控制台会输出以下内容
// Shadow {name: "jack", age: 18}
jQuery()Инстанцирование объекта завершается слепым методом перемещения цветов и соединения деревьев, а скрытые объекты скрываются одной рукой.new Shadow()Будем ошибочно думать, что нам не нужноnewЭкземпляры также можно создавать, вызывая функции напрямую.
Давай еще раз попробуемnew jQuery(), вы найдете: «Бля, как я могу следоватьjQuery()Результат выполнения точно такой же! "
var obj2 = new jQuery();
console.log(obj2)
// Chrome控制台会输出以下内容
// Shadow {name: "jack", age: 18}
Это связано с тем, что новый конструктор явно возвращаетnew Shadow(), возвращаемый результатnew Shadow()экземпляры объектов без использованияnewпозвонить напрямуюjQuery(), просто поставьjQuery()При выполнении как обычной функции результат очевиденnew Shadow()Создаваемый объект.
Так вотnew jQuery()а такжеjQuery()эквивалентны.
Хотя jQuery используется все меньше и меньше, идеи его дизайна заслуживают изучения. Так что же такого замечательного в jQuery? Можно сказать, что есть много знакомых нам функций, таких как работа в цепочке и система подключаемых модулей. Не заходя слишком далеко, давайте кратко проанализируем процесс создания экземпляра jQuery.
Я получил версию кода jQuery v1.12.4 здесь, около 1W строк, очень удобно.
Поворачиваюсь, поворачиваюсь, поворачиваюсь к строке 71 и вижу такую цепочку кодов:
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
}
Разве это не та техника, с которой мы знакомы?jQuery.fn.initКажется, в приведенном выше примереShadow. Он выглядит немного похожим, но мне все еще нужно внимательно его изучить.
Зачем делать jQuery.fn?
jQuery.fn — это псевдоним jQuery.prototype для краткости кода. Вы можете узнать это, обратившись к строке 91 исходного кода.
jQuery.fn = jQuery.prototype = {
// ......
Как убедиться, что прототип указывает?
Мы знаем, что если толькоnew jQuery.fn.init(selector, context)Есть проблема, проблема в том, что полученный экземпляр неjQueryпример, ноjQuery.fn.initпример. Итак, как справиться с этой проблемой?
Переходим к строке 2866 исходного кода и видим:
init = jQuery.fn.init = function( selector, context, root ) {
// 创建实例的具体逻辑
}
специфическийinitКак метод создает объект jQuery и какую логику оценки он выполняет, не является предметом рассмотрения в этой статье. На что нам нужно обратить внимание, так это на то, как jQuery гарантирует, что прототип экземпляра объекта указывает на правильный? В противном случае, как использовать созданный объектjQuery.prototypeКак насчет многих методов, установленных выше, таких какthis.show(),this.hide()?
Сразу после обращения к строке 2982 у меня есть ответ:
init.prototype = jQuery.fn;
Замечательно, эта операция по изменению точки прототипа одной рукой прекрасно решает эту проблему. Таким образом,new init()Полученный экземпляр естественноjQueryпример.
jQuery.prototype.init.prototype === jQuery.prototype; // true
var a = $('<div>123</div>')
a instanceof jQuery // true
a instanceof jQuery.fn.init // true
Таким образом, мы можем получить основную идею дизайна:
function myModule(params) {
return new myModule.fn.init(params);
}
myModule.fn = myModule.prototype = {
constructor: myModule
}
myModule.fn.init = function(params) {
// 可以对实例对象进行各种操作
}
myModule.fn.init.prototype = myModule.prototype;
На этой основе мы можем расширять статические методы и методы-прототипы, и этот модуль myModule становится все более и более богатым.
наконец
Замечательно, конструктор, который заставил меня задуматься ... Помоги мне, я все еще могу учиться!
В этой статье используетсяmdnice умная синяя теманабор текста