Резюме и адрес Cipian «Шаблоны проектирования JavaScript» на githubYOU-SHOULD-KNOW-JS
упаковка
создать класс
Создать объект в JavaScript легко, сначала объявив функцию для сохранения в переменной. Как правило, первая буква имени переменной пишется с заглавной буквы в соответствии с практикой программирования. Затем добавьте свойства или методы внутри через переменную this, чтобы добавить свойства и поведение в класс.
var Book = function(id,bookname,price) {
this.id = id;
this.bookename = bookname;
this.price = price;
}
Конечно, мы также можем добавить свойства и методы к прототипу класса. Есть два способа:
Book.prototype.display = function() {
//展示展示这本书
}
//或者
Book.prototype = {
display:function() {
//展示这本书
}
}
Таким образом, мы инкапсулируем нужные нам методы и свойства в наш инкапсулированный класс Book.При использовании этих функций и методов мы не можем использовать эти классы напрямую, но должны использовать ключевое слово new для создания экземпляра нового объекта.
var book = new Book(10,'JavaScript设计模式',20);
console.log(book.bookname);
Обратите внимание, что свойства и методы, добавляемые через this, добавляются к текущему объекту, но JavaScript — это язык, основанный на прототипах, поэтому каждый раз, когда создается объект, у него есть прототип, который указывает на его унаследованные свойства и методы. Таким образом, методы, унаследованные от прототипа, не относятся к самому объекту, поэтому при использовании этих методов вам необходимо просматривать прототип слой за слоем.
Проще говоря, через атрибуты и методы этого объекта сам принадлежит этому объекту, поэтому каждое из свойств и методов, выполняемых к этому времени, атрибуты и методы, выполняемые этим, будут созданы соответственно, а свойства, унаследованные Prototype и The метод заключается в том, что доступ к каждому объекту осуществляется по прототипу. Таким образом, каждый раз, когда мы создаем новый объект по классу, эти свойства и методы не будут создаваться снова.
Как показано выше, свойство __proto__ экземпляра выполняет прототип. Свойство конструктора прототипа указывает на конструктор. Когда создается функция или объект, для него создается прототип объекта-прототипа.В объекте-прототипе создается свойство конструктора, как это создается в функции.Это свойство указывает на функцию или объект, которому принадлежит весь объект-прототип.Инкапсуляция свойств и методов
Поскольку JavaScript является областью видимости на уровне функции, к переменным или методам, объявленным внутри функции, нельзя получить доступ извне.Благодаря этой функции можно создавать частные переменные и частные методы класса. Однако для свойств и методов, созданных этим внутри функции, когда объект создается классом, каждый объект имеет копию самого себя и может быть доступен извне. Следовательно, свойства, созданные с помощью this, можно рассматривать как общие свойства и общие методы объекта. Метод, созданный этим, может не только обращаться к общим свойствам и общим методам этих объектов, но также обращаться к частным свойствам и частным методам самого класса.Это право относительно велико, поэтому мы называем его привилегированным методом. При создании объекта мы можем использовать эти привилегированные методы для инициализации некоторых свойств объекта-экземпляра, поэтому эти привилегированные методы, вызываемые при создании объекта, можно рассматривать как конструктор класса
var Book = function(id,name,price) {
//私有属性
var num = 1;
//私有方法
function checkId() {
}
//特权方法
this.getName = function() {}
this.getPrice = function() {}
this.setName = function() {}
this.setPrice = function() {}
//对象共有属性
this.id = id;
//对象共有方法
this.copy = function() {
}
//构造器
this.setName(name);
this.setPrice(price);
}
При создании нового объекта через ключевое слово new, поскольку свойства и методы, добавленные через точечный синтаксис вне класса, не выполняются, они не могут быть получены из вновь созданного объекта и могут использоваться через класс в это время. Поэтому мы называем их статическими общедоступными свойствами и статическими общедоступными методами. Доступ к свойствам и методам, созданным прототипом класса, можно получить через this в экземпляре класса (__ptoto__ вновь созданного объекта указывает на объект, на который указывает прототип класса), поэтому мы вызываем свойства и методы в прототипе по общим свойствам и методам
//静态的共有属性和方法,对象不能访问
Book.isChinese = true;
Book.setTime = function() {
console.log('new time');
}
Book.prototype = function() {
//共有属性和方法
isBook:true;
display = function() {
}
}
Объект, созданный с помощью нового ключевого слова, на самом деле является постоянным присвоением новому объекту this, а прототип указывает на объект, на который указывает прототип класса, а свойства и методы добавляются с помощью точечного синтаксиса вне конструктора класса. не будет добавлен в список Вновь созданный объект поднимается вверх.
Внедрение замыканий
Иногда мы часто реализуем статические переменные классов через замыкания
var Book = (function() {
//静态私有变量、静态私有方法
var bookNum = 0;
function checkBook(name) {
}
//返回构造函数
return function(newId,newName,newPrice) {
//私有变量、方法
var name,price;
function checkId(id) {
}
//特权方法
this.getName = function(){};
this.getPrice = function(){};
this.setName = function(){};
this.setPrice = function(){};
//公有属性、公有方法
this.id = newId;
this.copy = function(){};
bookNum++;
if(bookNum>100){
throw new Error('我们仅出版了100本书');
}
//构造器
this.setNmae(name);
this.setPrice(price)
}
})()
Book.prototype = {
//静态共有属性、静态公有方法
isJsBook:false,
display:function() {
}
}
Замыкание — это функция, которая имеет доступ к переменным в области действия другой функции, т. е. создает другую функцию внутри функции. Мы используем это замыкание в качестве конструктора, создающего объект, так что оно является и замыканием, и функцией инстанцируемого объекта с доступом к переменным в области видимости класса. Но добавление свойств и методов прототипа за пределами замыкания, похоже, выходит за рамки класса замыкания, поэтому мы можем сделать это следующим образом.
var Book = (function() {
//静态私有变量
var bookNum = 0;
//静态私有方法
function checkBook(name) {
console.log(name);
}
function _book(newId,newName,newPrice) {
//私有变量
var name,price;
//私有方法
function checkId(id) {
console.log(id)
}
//特权方法
this.getName = function(){};
this.getPrice = function(){};
this.setName = function(){};
this.setPrice = function(){};
//公有属性
this.id = newId;
//公有方法
this.copy = function(){};
bookNum++;
if(bookNum>100)
throw new Error('我们仅仅出版了100本书');
//构造器
this.setName(name);
this.setPrice(price)
}
_book.prototype = {
//静态共有属性、方法
isJSBook:false,
display:function() {
console.log('display')
}
}
return _book;
})()
наследовать
наследование классов
function SuperClass() {
this.superValue = true;
}
SuperClass.prototype.getSuperValue = function() {
return this.superValue;
}
function SubClass() {
this.subValue = false;
}
SubClass.prototype = new SubClass();
SubClass.prototype.getSubValue = function() {
return this.subValue;
}
Наследование очень простое, достаточно объявить два класса, но для наследования классов необходимо присвоить экземпляр первого класса прототипу второго класса, поскольку роль объекта-прототипа класса заключается в добавлении общих методов к прототипу класса. класс, но класс не может получить прямой доступ к этим свойствам и методам, доступ к которым должен осуществляться через прототип-прототип. Когда мы создаем экземпляр родительского класса, вновь созданный объект копирует свойства и методы конструктора родительского класса и указывает прототип __proto__ на объект-прототип родительского класса, таким образом, имея свойства и методы объекта-прототипа родительского класса. объект может напрямую обращаться к свойствам и методам объекта-прототипа родительского класса. А вновь созданный объект может обращаться не только к свойствам и методам прототипа родительского класса, но и к свойствам и методам, скопированным в конструкторе родительского класса. Назначьте этот объект прототипу подкласса, тогда прототип подкласса также сможет получить доступ к свойствам и методам прототипа родительского класса, а также к свойствам и методам, скопированным из конструктора родительского класса.
Кроме того, мы можем использовать instanceof, чтобы определить, является ли объект экземпляром класса.
var instance = new SubClass();
console.log(instance instanceof SuperClass)
console.log(instance instanceof SubClass)
console.log(SubClass instanceof SuperClass)
Вы можете попробовать это сами о результатах. Обратите внимание, что instanceof предназначен для определения того, является ли объект экземпляром следующего класса, он не указывает на наследование двух.
console.log(SubClass.prototype instanceof SuperClass);
Однако этот вид наследования классов имеет два недостатка: во-первых, поскольку подкласс создает экземпляр родительского класса через свой прототип-прототип и наследует родительский класс, если общее свойство в родительском классе является ссылочным типом, оно будет вызываться в подклассе. Все экземпляры являются общими, поэтому экземпляр подкласса изменяет общие свойства прототипа подкласса, унаследованные от конструктора родительского класса, что будет непосредственно влиять на другие подклассы.
function SuperClass() {
this.books = ['js','css'];
}
function SubClass() {}
SubClass.prototype = new SuperClass();
var instance1 = new SubClass();
var instance2 = new SubClass();
console.log(instance2.books);
instance1.books.push('html');
console.log(instance1.books,instance2.books)
Во-вторых, поскольку наследование, реализованное подклассом, реализуется путем создания экземпляра родительского класса его прототипом-прототипом, невозможно передать параметры родительскому классу при создании родительского класса. Поэтому свойства в конструкторе родительского класса не могут быть инициализированы при создании экземпляра родительского класса.
Наследование конструктора
смотри прямо на код
function SuperClass(id) {
this.books = ['js','css'];
this.id = id;
}
SuperClass.prototype.showBooks = function() {
console.log(this.books);
}
function SubClass(id) {
//继承父类
SuperClass.call(this,id);
}
//创建第一个子类实例
var instance1 = new SubClass(10);
//创建第二个子类实例
var instance2 = new SubClass(11);
instance1.books.push('html');
console.log(instance1)
console.log(instance2)
instance1.showBooks();//TypeError
Как и выше, SuperClass.call(this, id), конечно же, является основным оператором наследования конструктора.Поскольку метод вызова может изменить функциональную среду функции, в подклассе вызов этого метода в суперклассе должен поместить переменные в подкласс в Execute один раз в родительском классе. Поскольку родительский класс привязывает свойства к этому, дочерний класс естественным образом наследует общие свойства родительского класса. Поскольку этот тип наследования не задействует прототип-прототип, метод-прототип родительского класса не будет унаследован подклассом, но если он хочет быть унаследован подклассом, его необходимо поместить в конструктор, чтобы каждый экземпляр созданный будет отдельным. Владеть одной копией, но не делиться ею, нарушает принцип повторного использования кода, поэтому, объединяя два вышеуказанных метода, мы предлагаем комбинированный метод наследования.
наследование композиции
Наследование классов реализуется путем создания экземпляра родительского класса через прототип подкласса, а наследование конструкторов реализуется путем однократного выполнения конструктора родительского класса в среде функции-конструктора подкласса.
function SuperClass(name) {
this.name = name;
this.books = ['Js','CSS'];
}
SuperClass.prototype.getBooks = function() {
console.log(this.books);
}
function SubClass(name,time) {
SuperClass.call(this,name);
this.time = time;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getTime = function() {
console.log(this.time);
}
Как указано выше, мы решаем некоторые проблемы, которые ранее сказали, но это из кода, все еще каким-то неудобным? По крайней мере, этот конструктор Superclass очень ненадлежащим, чем два раза.
прототипное наследование
Общая реализация прототипного наследования такова
function inheritObject(o) {
//申明一个过渡对象
function F() { }
//过渡对象的原型继承父对象
F.prototype = o;
//返回过渡对象的实例,该对象的原型继承了父对象
return new F();
}
По сути, этот метод очень похож на наследование классов, это всего лишь инкапсуляция наследования классов, объект перехода в нем эквивалентен подклассу наследования классов, но он существует как обычный объект перехода в прототипном наследовании. для создания нового экземпляра объекта, который будет возвращен.
var book = {
name:'js book',
likeBook:['css Book','html book']
}
var newBook = inheritObject(book);
newBook.name = 'ajax book';
newBook.likeBook.push('react book');
var otherBook = inheritObject(book);
otherBook.name = 'canvas book';
otherBook.likeBook.push('node book');
console.log(newBook,otherBook);
Как мы видим из приведенного выше кода, прототипное наследование такое же, как и наследование класса.Для переменных ссылочного типа все еще существует ситуация, когда экземпляры подкласса являются общими.
Итак, мы также имеем следующее паразитическое наследование
паразитарное наследование
смотри прямо на код
var book = {
name:'js book',
likeBook:['html book','css book']
}
function createBook(obj) {
//通过原型方式创建新的对象
var o = new inheritObject(obj);
// 拓展新对象
o.getName = function(name) {
console.log(name)
}
// 返回拓展后的新对象
return o;
}
По сути, паразитическое наследование — это расширение прототипного наследования, процесс вторичной инкапсуляции, так что вновь создаваемый объект не только имеет атрибуты и методы родительского класса, но и добавляет другие атрибуты и методы.
Паразитическая композиционная наследственность
Возвращаясь к предыдущему комбинированному наследованию, в то время мы использовали комбинацию наследования классов и наследования конструкторов, но проблема была в том, что подкласс не был экземпляром родительского класса, а прототип подкласса был экземпляром родительского class, поэтому имело место паразитное наследование композиции.
Паразитическое наследование композиции представляет собой комбинацию паразитного наследования и наследования конструктора. Но паразитное наследование здесь немного особенное, где он имеет дело не с объектами, а с прототипами классов.
function inheritPrototype(subClass,superClass) {
// 复制一份父类的原型副本到变量中
var p = inheritObject(superClass.prototype);
// 修正因为重写子类的原型导致子类的constructor属性被修改
p.constructor = subClass;
// 设置子类原型
subClass.prototype = p;
}
В составном наследовании нет проблем со свойствами и методами, унаследованными через конструкторы, поэтому здесь мы в основном исследуем повторное наследование прототипа родительского класса посредством паразитного наследования. Нам нужно наследовать только прототип родительского класса, без вызова конструктора родительского класса. Другими словами, при наследовании конструктора мы вызвали конструктор родительского класса. Следовательно, нам нужна копия объекта-прототипа родительского класса, и эта копия может быть получена путем прототипного наследования, но есть проблема в присвоении ее непосредственно подклассу, т.к. объект родительского класса Атрибут конструктора не указывает на объект подкласса подкласса, поэтому при паразитном наследовании объект копии p необходимо улучшить, чтобы исправить проблему, заключающуюся в том, что атрибут конструктора имеет неправильную направленность, и, наконец, полученный объект копии p присваивается прототипу подкласса, так что прототип дочернего класса наследует прототип родительского класса и не выполняет конструктор родительского класса.
function inheritPrototype(subClass,superClass) {
// 复制一份父类的原型副本到变量中
var p = inheritObject(superClass.prototype);
// 修正因为重写子类的原型导致子类的constructor属性被修改
p.constructor = subClass;
// 设置子类原型
subClass.prototype = p;
}
function inheritObject(o) {
//申明一个过渡对象
function F() { }
//过渡对象的原型继承父对象
F.prototype = o;
//返回过渡对象的实例,该对象的原型继承了父对象
return new F();
}
function SuperClass(name) {
this.name = name;
this.books=['js book','css book'];
}
SuperClass.prototype.getName = function() {
console.log(this.name);
}
function SubClass(name,time) {
SuperClass.call(this,name);
this.time = time;
}
inheritPrototype(SubClass,SuperClass);
SubClass.prototype.getTime = function() {
console.log(this.time);
}
var instance1 = new SubClass('React','2017/11/11')
var instance2 = new SubClass('Js','2018/22/33');
instance1.books.push('test book');
console.log(instance1.books,instance2.books);
instance2.getName();
instance2.getTime();
Наследование таким образом на самом деле показано на рисунке выше.Самое большое изменение - это обработка в прототипе подкласса, на который дается ссылка в прототипе родительского класса.Это объект, поэтому вам нужно заплатить одну вещь Обратите внимание на то, что подкласс хочет добавить методы прототипа, которые должны быть добавлены через прототип. В противном случае прямое присвоение объекту перезапишет объект, унаследованный от прототипа родительского класса.
множественное наследование
Поскольку наследование в JavaScript осуществляется через цепочку прототипов для достижения только одной цепочки прототипов, теоретически невозможно добиться наследования более чем одного родительского класса. Но мы можем с помощью некоторых советов добиться аналогичного множественного наследования
var extend = function(target,source) {
// 遍历源对象中的属性
for(var property in source){
//将源对象中的属性复制到目标对象中
target[property] = source[property];
}
//返回目标对象
return target;
}
Конечно, то, что мы здесь реализуем, — поверхностная копия, и она ничего не может сделать со ссылочными типами. Глубокое копирование реализовано в jquery, что достигается повторным выполнением метода extend для атрибутов ссылочного типа в исходном объекте. То, чего мы достигли здесь, относительно просто.
var book = {
name:'javascript 设计模式',
alike:['css','html']
}
var another = {
color:'blue'
};
extend(another,book);
console.log(another.name);
console.log(another.alike);
another.alike.push('React');
another.name = '设计模式';
console.log(another,book);
Вышеупомянутое предназначено для реализации присваивания объекта.Конечно, множественное наследование, которое заключается в установке цикла во внешнем слое, здесь не повторится.
полиморфизм
На самом деле полиморфизм — это множество методов вызова одного и того же метода, и на самом деле существует множество способов его реализации в JavaScript. Ему просто нужно оценить входящие параметры, чтобы реализовать различные методы вызова.
Операция относительно обычная и здесь повторяться не будет. Вы можете обратиться к моей другой статьеРабота функции уровня ниндзя