Объектно-ориентированное программирование (ООП)
В последнее время я чувствую, что не знаю, чему учиться. Я всегда чувствую, что ничего не знаю, но я также чувствую, что могу чему-то научиться. Даже если я говорю «да», я также знаю объектно-ориентированное. не получил очень систематического понимания, поэтому я взглянул на точки знаний здесь.Когда я был своим собственным носильщиком, я делал вид, что публикую статью, и ждал, пока это будет удобно для меня;
создать объект
1. Фабричный шаблон: инкапсулируйте с помощью функций, создавайте детали объектов с определенными интерфейсами.
- Решена проблема создания нескольких одинаковых объектов,
- В основном он используется для создания нескольких объектов с одинаковыми свойствами и методами, чтобы избежать дублирования кода;
- Не решает проблему идентификации объекта (то есть как узнать тип объекта) (его instanceof может быть только Object)
function creatPerson(name,age,job) {
var o = new Object();
o.name= name;
o.age= age;
o.job= job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var p1 = creatPerson("hh",23,"worker");
var p2 = creatPerson("xx",26,"worker1");
p1.__proto__===p2.__proto__===Object.prototype;
对象的constructor 属性最早是用来描述队形类型的,检测对象类型还是 instanceof 更可靠
工厂模式创建的对象,constructor只有Object,这样的实例没有特定的类型;
2. Шаблон конструктора:
- Решить проблему распознавания объектов (т.е. как узнать тип объекта)
- Недостаток: каждый метод воссоздается один раз в каждом экземпляре, p1.sayName!=p2.sayName в следующем каштане.
- Решение: выдвинуть конструктор, объявить глобальную функцию записи (недостаток этого решения: глобальная функция вызывает только локальные вызовы, слишком много методов приходится создавать несколько глобальных функций, пакета вообще нет);
function Person(name,age,job){
this.age = age;
this.name = name;
this.job = job;
this.sayName = function(){
alert(this.name)
}
//this.sayName = sayName; //解决方式
}
var p1 = new Person("hh",23,"worker");
var p2 = new Person("xx",26,"worker1");
//function sayName(){alert(this.name)} //解决方式
new的执行:
{
var obj ={};
obj.__proto__ = Person.prototype;
Person.call(obj);
return obj
}
p1 instanceof Person //true;
p2 instanceof Person //true;
p1 instanceof Object //true;
p2 instanceof Object //true;
这样是得p1和p2实例有了特定的类型, Person;
3. Режим прототипа
-
Преимущества: Он опускает ссылку на параметры инициализации конструктора, все свойства в прототипе являются общими для многих экземпляров, совместное использование очень подходит для функций, и базовые свойства также в порядке. Добавляя в экземпляр свойство с тем же именем, можно скрыть соответствующее значение свойства в прототипе;
-
Недостатки: Его общие свойства не влияют на свойства, содержащие значения ссылочного типа, если экземпляр переназначается.Как и базовые типы, если это модификация операции, есть некоторые проблемы, которые сделают свойства, полученные всеми экземплярами, измененными, так что он также не используется в одиночку
function Person(){} Person.prototype={ constructor:Person, name:"ss", friends:["s1","s2"], sayName:function(){alert(this.name)} } var p1= new Person(); var p2= new Person(); p1.name = "p1" console.log(p1.name) //p1 console.log(p2.name) //ss p1.friends.push("s3"); console.log(p1.friends) //["s1","s2","s3"] console.log(p2.friends) //["s1","s2","s3"]
-
Применение:
- Общее использование:
function Person(){} Person.prototype.name="ceshi" Person.prototype.age =12; Person.prototype.sayName = function(){ alert(this.name) } //这样就是实现了代码的共享
- простое письмо
更简单的写法: Person.prototype={ //constructor:Person, name:"test", age:12, sayName:function(){alert(this.name)} } var friend = new Person(); friend instanceof Object //true friend instanceof Person //true friend.constructor==Person //false friend.constructor==Object //true 这种简单的写法constructor 属性就不在指向Person,而是指向Object构造函数; 此时可以添加一个属性constructor( 如上面注释):但是此时的constructor 变成了可枚举的属性,原生是不可枚举的,可以考虑用Object.defineProperty()
- Динамика прототипа:
var p1 = new Person(); <!-- 1 --> Person.prototype.hh="ss"; p1.hh//ss 是可以先创建实例在改边原型在访问的; <!-- 2 --> Person.prototype={ name:"ss" } p1.__proto__!=Person.prototype; p1.name // undefined
- Прототип нативного объекта:
- Вы можете добавить методы модификации к родным ссылочным типам (Object, Array, String...)
String.prototype.strarWith=function(tesx){return this.indexOf(text)==0}
- Вы можете добавить методы модификации к родным ссылочным типам (Object, Array, String...)
- Общее использование:
4. Объединение шаблона конструктора и шаблона прототипа: (Определить шаблон по умолчанию для ссылочных типов)
- Шаблон конструктора используется для определения свойств экземпляра; каждое свойство воссоздается один раз для каждого экземпляра; даже изменение ссылочных типов не влияет на другие экземпляры.
- Шаблон прототипа используется для определения методов и общих свойств;
function Person(age,name){
this.name = name;
this.age = age;
this.friends=[1,2,3]
}
Person.prototype={
constructor:Person,
sayName:function(){
alert(this.name)
}
}
var p1 = new Person("ss",12);
var p2 = new Person("ss3",123);
p1.friends.push(2);
console.log(p1.friends) // [1,2,3,2]
console.log(p2.friends)// [1,2,3]
5. Режим динамического прототипа:
- Прототип и функция папарацци независимы, что отличается от ОО в других языках.Динамический прототип должен инкапсулировать всю информацию в конструкторе;
- В конструкторе проверить, допустим ли метод, который следует использовать, подумать, инициализирован ли прототип, на самом деле это инициализировать прототип один раз
function Person(name,age){
this.name = name;
this.age = age;
if(typeof this.sayName !="function"){//sayName没初始化 这里对一个方法判断就可以,然后初始化所有的,没必要都每个方法都判断
Person.prototype.sayName=function(){alert(this.name)}
Person.prototype.sayAge=function(){alert(this.age)};
.....
}
****注意****:此处不能使用对象字面量形式重写原型, 因为这中写法是先创建的实例,然后在修改的原型,要是用对象字面量重写原型,会切断现有实例和新原型之间的联系, 导致方法实例上无此方法;
}
6. Шаблон паразитного конструктора:
- Аналогичен фабричному шаблону, но использует new для инициализации экземпляра;
- Возвращаемый объект не имеет ничего общего с конструктором и прототипом конструктора;
function Person(name,age){
var o = new Object();
o.name=name;
o.age=age;
o.sayName=function(){
alert(this.name)
};
return o;
}
var friends = new Person("xiaoming",12)
friends.asyName() // xiaoming
7. Шаблон безопасного конструктора:
Безопасный объект: объект, который не имеет общедоступных свойств и чьи методы не ссылаются на это;
function Person(name,age){
var o = new Object();
o.sayName=function(){
alert(name)
};
return o;
}
var friends = new Person("xiaoming",12)
friends.asyName() // xiaoming
Наследовать:
-
Наследование обычно включает в себя: Наследование интерфейса: наследовать методы и сигнатуры; Наследование реализации: наследуйте фактический метод; ECMAScript поддерживает только наследование реализации.
-
js в основном реализует наследование через цепочку прототипов, построение цепочки прототипов реализуется путем присвоения экземпляра одного типа прототипу другого конструктора.
Наследование
1. Цепочка-прототип (редко используется отдельно)
- Проблема: данные ссылочного типа манипулируются (переназначение не влияет на него, что эквивалентно добавлению скрытого родительского класса в подкласс), которые будут общими для всех экземпляров.
- Проблема: при создании подкласса нельзя передавать параметры в конструктор родительского класса; ? ?
Son.prototype = new Father();
//此时Son.constructor 被改写为了 Father;
Son.prototype.constructor = Son;
//给子类修改或者是添加方法的时候,要放在替换语句,改版子类原型语句之后,
//原型继承时,不能使用字面量方式创建原型方法,这样就重新写了原型链了
Son.prototype.getName=function(){alert(this.name)};
2. Привязка конструктора: вызов, применение Наследование: (редко используется отдельно)
- Проблема: Метод в прототипе родительской функции (прототип), подкласс не виден
- Проблемный кролик: атрибуты метода определены в конструкторе, каждый экземпляр и метод пересоздаются один раз, повторного использования нет z
function Son(){
Father.call(this,arguments)
}
3. Комбинированное наследование: (общий образец наследования)
- Таким образом, экземпляры могут иметь свои собственные свойства (включая ссылочные типы, дополнительные эффекты между экземплярами) и могут использовать один и тот же метод;
- Недостаток: в любом случае конструктор родительского класса будет вызываться дважды;
function Father(){
this.name ="ss";
this.friends=[1,2,3,4]
}
function Son(){
Father.call(this);
}
Son.prototype = new Father(); // Son 原型获得Father上的属性,name和friends
var son1 = new Son(); // 此时调用Son构造函数为son1 实例上添加了属性(name和friends), 这些属性就屏蔽了原型中的同名属性;
// 调用两次Father构造函数的结果就是有两组属性,一组在实例上,一组在原型上;
4. Прототипное наследование:
- В случае, когда нет необходимости создавать конструктор, а просто хочется, чтобы один объект был похож на другой объект, можно использовать его, аналогичный денежной копии;
function object(o){
function F(){};
F.prototype = o;
return new F();
}
// 和 Object.creat() 传递一个参数时候相同
5. Паразитическое наследование:
- Наследовать свойства и методы происхождения;
- Также имеет свой собственный метод;
function creat(origin){
var clone = object(origin); // 可以是任何返回新对象的函数
clone.sayName(){alert("name")}; //这里的函数每次都创建,不存在复用一说,
return clone;
}
6. Паразитическая композиция: (идеальная реализация наследования)
- Устраните дефекты комбинированного наследования, создайте два набора свойств и создайте прототипы только для экземпляров;
- Наследовать свойства через конструкторы и наследовать методы через смешанную форму цепочки прототипов (то есть назначать копию родительского класса прототипу подкласса).
function inherit(son,father){
var prototype = object(father.prototype);
// 上句话,创建父类原型的副本,prototype.__proto__ = Father.prototype;
// prototype 继承constructor prototype.constructor 取的是原型链上,原型的Father.prototype.constructor, 为 Father();即:prototype.constructor == prototype.__proto__.constructor // true
// prototype.hasOwnPrototyoe("constructor") //false
prototype.constructor = son; // 弥补重写原型造成的默认属性的修改;
//此时是给prototype 添加了constructor 属性,赋值为son, 屏蔽了原型上的constructor属性
// prototype.hasOwnPrototype("constructor") // true
// prototype.constructor = son;
// prototype.__proto__.constructor = father
son.prototype = prototype;
// 给子类原型赋值为父类原型的副本;
}
//使用:
function Father(){
this.name="11";
this.age=12;
}
Father.prototype.sayName=function(){
alert(this.name);
}
function Son(){
Father.call(this);
this.age=23;
}
inherit(Son,Father);
Son.prototype.sayAge=function(){
alert(this.age)
}