面向对象的Javascript和原型
创建一个对象
1。共同创作的对象
创建一个对象,然后创建新的对象属性和方法;
var =新的(对象);创建对象对象;
box.name = 'lee '; / /创建一个名称属性和分配;
box.age = 100;
(box.run =功能){ / /创建一个运行()方法返回值;
退货。姓名+年龄+手术,…;
}
Console.log((盒。运行)); / /输入属性和方法的价值;
缺点:想要创建类似的对象,可以生成大量的代码;
2。工厂模式创建对象
这种方法是为了解决/实例化对象产生大量重复的代码;
函数CreateObject(姓名,年龄){ / /创造功能;
var obj =新对象; / /体内创建一个对象的功能;
obj.name =名称;
obj.age =年龄;
obj.run =函数(){
返回这个名字+这个;
};
返回对象;
}
无功1 = CreateObject(李,100); / /实例化调用函数和参数;
VaR Box2 = CreateObject(杰克,200); / /实例;
console.log(1。运行)(+ box2.run()); / /保持相对独立的例子;
缺点:对象识别问题和示例;找出它们是否是该对象的示例;
console.log(类型1); / /对象;
三.构造函数创建对象
构造函数( / / ECMAscript方法)可以用来创建一个对象;
函数框(名称,年龄){构造函数模式;
this.name = / /这个名字;代表对象框;
this.age =年龄;
this.run =函数(){
返回这个名字+这个;
};
}
无功1 =新箱(李
VaR Box2 =新箱(杰克
console.log(1建议箱); / /真的;从1清晰识别属于盒;
使用构造函数解决了重复问题的实例化,解决了对象识别问题;
构造函数的使用与工厂模式不同:
(1)。构造函数方法未显示的创建对象(新对象);
(2)。直接将属性和方法分配给该对象;
(3)。不返回语句;1:
(1)。函数名(函数框)和实例化的结构名(新框)是相同的,并且大写;
(2)。构造函数必须使用新操作符来创建实例对象。
构造函数和普通函数之间的区别:
VaR箱=新箱('lee ',100); / /呼叫模型;
箱('lee ',200); / /普通模式调用,无效;
新对象();
box.call(O,杰克,200); / /假装打电话;
将对象的范围扩展到对象O(box)方法;操作环境已经成为O对象;
构造函数问题:
当每个实例用构造函数创建时,构造函数的方法在每个实例上都会重新创建。
因为ECMAscript的函数是一个对象,每个定义一个函数是一个对象被实例化。
以这种方式创建函数会导致不同的域链和标识符解析。
两个原型
我们创建的每个函数都有一个原型(原型)属性,这个属性是一个对象;
用法:包含与特定类型的所有实例共享的属性和方法;
理解:原型是调用构造函数创建的对象的原型对象;
使用原型的优点是所有对象实例属性和方法都包括共享;
也就是说,没有必要在构造函数(属性/方法)中定义对象信息,但是可以直接将信息添加到原型中;
1。原型模式(原型添加属性和方法)
1。原型模型
函数(box){构造函数声明;
box.prototype.name = 'lee '; / /添加原型属性和方法;
box.prototype.age = 100;
box.prototype.run =函数(){
退货。姓名+年龄+手术,…;
};
无功1 =新箱();
VaR Box2 =新箱();
console.log(1。跑= = Box2。运行); / / = >真;参考地址一致的方法;
原型中的两个/多个属性,当对象时自动创建这两个原型属性;
1。__proto__: / /构造函数是一个指向原型对象;它的作用:是指属性构造函数构造函数的原型;
14 / / IE浏览器不能在脚本访问__proto__鉴定;15
/ /判断对象的一个实例是指原型对象的构造函数,您可以使用isprototypeof()方法来测试;
console.log(Box.prototype.isPrototypeOf(箱)); / / = >真;只要实例化对象,将点;
实施过程的原型模型:
属性或方法1。示例,首先在构造函数中找到对象,如果立即返回;
2。如果没有对象的实例构造函数,找到原型对象,如果有的话,将返回;
尽管我们可以通过存储在原型值中的对象实例来访问,但是不能访问对象实例来重写原型中的值;
无功1 =新箱();
console.log(1名); / /李;原型的价值;
bo1.name =杰克;
console.log(1名); / /杰克;其指定的值的例子;
VaR Box2 =新箱();
console.log(Box2。名称); / /李;原型的价值;通过1不改;
如果你想继续获得价值1 / /原型,可以把属性的构造函数可以被删除;
删除box1.name; / /删除自己的属性实例;
console.log(1名); / /李;在原型的原始值;
2。原型与算子
如何判断属性在构造函数的实例或原型可以通过hasownproperty验证()函数;
console.log(box.hasownproperty('name') / /);如果返回true,否则返回false;
当一个给定的属性可以被一个对象访问时,不管它是否存在于实例中或者原型中,操作符都返回true;
console.log('name'in箱); / / = >真的,有例子和原型;3。更简单的语法原型(原型+文字模式)
三.简单的原型语法(原型+文字模式)
函数(方框){ };
box.prototype = { / /创建新对象包含的属性和方法以文字的形式;
名称:'lee,
年龄:100岁,
运行:函数(){
退货。姓名+年龄+手术,…;
}
};
使用构造函数创建原型对象,使用原型对象的文字创建与使用基本相同;
但是,原型对象是使用字面构造函数属性创建的,不指向实例,但是对原型对象构造函数是对对象;
var框=新框();
console.log(箱中箱);
console.log(盒实例对象);
console.log(box.constructor = =箱); / /文字的方式,返回false;
console.log(box.constructor = =对象); / /文字的方式,返回true;
如果您想将文本方式构造函数添加到实例对象中:
box.prototype = { {
构造函数:直接向;
}
ps:为什么构造函数会指向对象
因为该框是创建一个新对象的;
在同一时间创建一个函数,它将创建原型,这个对象将自动获得构造函数属性;
因此,新对象重写原始构造函数构造函数框,从而指向新对象,
新对象没有指定构造函数,默认值是对象;
4者的动态。原型(重写将覆盖前面的内容)
语句的原型是命令,因此原型的重写将在原型之前被截断;
函数(方框){ };
box.prototype = { {
构造函数:框,
名称:'lee,
年龄:100岁,
运行:函数(){
退货。年龄+手术…;
}
};
box.prototype = { / /原型的改写,覆盖之前的原型;
年龄:200岁,
运行:函数(){
退货。年龄+手术…;
}
}
var框=新框();
Console.log((盒。运行)); / / = > 200操作…;
原型对象在原型和任何先前存在的对象实例之间存在着重写;对象实例引用仍然是初始原型;
5。本地对象的原型
/ /原型对象不仅可以用于自定义对象,但是ECMAscript内置引用类型可以采用这种方法,
和自身构建的引用类型是原型;
Console.log (Array.prototype.sort); / / =>function sort ({native) {code}};
console.log(字符串。原型。串); / / = >功能的子串({本地){代码} };
6。原型对象问题
对象创建的原型模型:缺点:构造函数初始化的过程参数被省略,缺点是初始值是相同的;
原型是最大的共享,属性共享;
但是,如果原型包含一个引用类型(对象),那么将共享一些问题;
函数(方框){ };
box.prototype = { {
构造函数:框,
名称:'lee,
年龄:100岁,
家庭:{爸爸',妈妈},
运行:函数(){
退货。姓名+年龄+ this.family本;
}
};
无功1 =新箱();
box1.family.push(妹妹'); / /添加为1家庭财产的妹妹;这个属性是由原型共享;
Console.log((1。运行)); / / = > lee100father,母亲,姐姐;
VaR Box2 =新箱();
Console.log((Box2。运行)); / / = > lee100father,母亲,姐姐;
数据共享导致实例化数据不能保存它们自己的特性;
7。使用构造函数模式(对象不共享的数据)和原型模式(对象共享的数据)的组合
为了解决结构参数和构造函数共享问题,组合+原型模型:
函数框(名称,年龄){不使用构造函数共享;
this.name =名称;
this.age =年龄;
this.family = {爸爸','moter};
};
对共享box.prototype = { / /原型模型的使用;
构造函数:框,
运行:函数(){
退货。姓名+年龄+ this.family本;
}
};
这个混合模型是解决参数和引用共享问题的好方法,是一种很好的创建对象的方法;
8。动态原型模式(将原型封装到构造函数中)
原型,无论调用共享方法原型,它都将是原型的初始化方法;
并且在语句/对象中,构造函数+原型让人感到陌生;最好的构造函数和原型包在一起;
函数框(名称,年龄)到构造函数体的所有信息包;
this.name =名称;
this.age =年龄;
当第一个调用构造函数时,run()方法不存在,然后执行初始原型;
当第二个调用未初始化时,第二次创建新对象时,原型将不加载初始化;
这是一个包,实现了一个共享的原型方法,并且属性保持独立;
如果(typeof this.run!= 'function){ / /只在第一次调用初始化;
box.prototype.run =函数(){
退货。姓名+年龄+手术,…;
};
}
};
VaR箱=新箱('lee ',10);
console.log(box.run());
使用动态原型模型,稍微注意一下,就不能用文字的方式重写原型,因为它会切断实例与新原型之间的联系;
9。寄生构造函数
寄生构造函数,实际上是工厂模型+结构模型,这个模型比较一般,但不能确定对象关系;
函数框(名称,年龄){
var obj =新的对象();
obj.name =名称;
obj.age =年龄;
obj.run =函数(){
退货。姓名+年龄+手术,…;
};
返回对象;
}
三继承
1。原型链
继承是面向对象的核心概念;
其他正统的面向对象语言将通过两种方式继承:一种是接口,一种是继承的;
/ /在ECMAscript只支持继承,不支持在原型链接口的实现和实现继承;
本质:使用引用类型的原型继承另一种类型的属性引用和方法;
原型继承链;
函数(方框){方框结构;
this.name = 'lee;
}
功能(桌面){桌面结构;
this.age = 100;
}
desk.prototype =新(箱); / /创建一个框实例,并分配给desk.prototype;原型,形成一个链;
本质是:重写原型对象表,它是一种新类型的实例;
也就是说 /属性和方法中存在的框实例,现在有Desk.prototype;
新办公桌();
console.log(桌子。年龄); / / 100;
console.log(桌子。名称); / / = >李;
函数表(){
this.level = 'AAA';
}
table.prototype =新(台); / /原型链继承;继承了桌桌;
var表=新表();
console.log(表名); / /李;
2。原型与实例的关系;
在原型链继承之上缺少一个环,即对象,所有构造函数都是从对象继承的;
对象继承和继承是自动完成的,不需要人工继承;
console.log(表实例对象); / / = >真的;
console.log(桌子是表); / / = >假;桌台超类;
console.log(表是书桌); / / = >真的;
console.log(表建议箱); / / = >真的;
在JS调用超类(父类继承,基类);
继承函数称为子类型(子类,派生类);
继承:
字面重写原型将中断关系;
子类型不属于超类型传输参数;
三.使用构造函数(对象冒充)
为了解决共享和引用的超类型不能传递参数;
子类型构造函数/内部调用构造函数中的超级类型;
函数框(年龄){
this.name = { 'lee,杰克,你好};
this.age =年龄;
}
功能台(年龄){
继承框也传递参数;
以这种方式,将在新的桌面对象(对象)中实现Box在初始化代码中定义的所有函数;
box.call(这个年龄); / /台继承了盒子,冒充的对象,可以给一个超类型参数;
为了确保框的属性/构造函数不会重写子类型,在类型构造函数中,Add属性应该在子类型中定义;
this.height = 175;
}
var桌面=新的桌面(200);函数的参数,通过函数框()函数使用参数;
console.log(桌子。年龄); / / = > 200;
console.log(桌子。名称); / / = > { 'lee,杰克,你好};
Desk.name.push('AAA'); / / = >添加新的数据,增加了办公桌;
console.log(桌子。名称); / / = > { 'lee,杰克,你好,'AAA' };
4。组合继承(原型链+借用构造函数)
虽然解决方案引用/借用构造函数共享和超级类型不能传递参数,但不能使用原型,所以重用的需求是不可能的;组合继承模式;
使用原型实现继承链/原型属性和方法;
通过使用构造函数来实现实例属性的继承;
这是定义在原型中的方法,实现了函数的重用,可以确保每个实例都有自己的属性;
函数框(年龄);
this.name = { 'lee,杰克,你好};
this.age =年龄;
}
(box.prototype.run =功能){ / /原型;
这名+ this.age返回;
}
功能台(年龄){
box.call(这个年龄); / /继承财产;伪装;盒子的对象范围扩大到办公桌,在桌箱的属性和方法的继承;
}
desk.prototype =新(箱); / /继承法;原型继承链;
新办公桌(100);
Console.log((桌子。运行)); / / = >李,杰克,hello100
最常见的继承模式;
5。原型继承
这是原型的继承,基于现有对象创建对象,因此不需要创建自定义类型;
函数对象(O){ / /文字传递函数;
函数(f){ };创建构造函数;
f.prototype = O; / /分配到原型的构造函数的文字功能;
返回新(f);返回实例构造函数;
}
var对象;
名称:'lee,
Arr:{哥,'sisiter}
};
var obj 1 =(箱);
console.log(1名); / / = >李;
box1.name =杰克;
console.log(1名); / / = >杰克;
console.log(1。ARR); / / = >哥哥,姐姐;
box1.arr.push(上帝的); / /
console.log(1。ARR); / / = >的哥哥,姐姐,爸爸;
var obj箱(盒)=;
console.log(Box2。名称); / / = >李;
console.log(Box2。ARR); / / = >的哥哥,姐姐,爸爸;共享引用类型;
6。寄生继承
原型工厂模式组合,目的是创建对象封装过程;
创建一个仅用于封装过程的函数,
函数创建(o)包创建过程;
var = obj(O);
f.run =函数(){
返回this.arr; / /也将分享参考;
};
返回F;
}
7。寄生组合继承
在以前,组合继承JS是最常用的继承方式;
但是,存在着一些问题,例如,继承:
超级类型在使用过程中将被调用两次:一个是创建子类型,另一个在子类型构造函数中;
函数框(名称){
this.name =名称;
This.arr = {'brother','sister'};
}
box.prototype.run =函数(){
返回this.name;
}
功能台(姓名,年龄){
box.call(这名字); / /第二电话盒;
this.age =年龄;
}
desk.prototype =新(箱); / /调用第一个盒子;
寄生 /组合遗传:
通过借用属性继承属性的构造函数,
原型链形式/混合继承法;
解决两个电话问题;
函数对象(O){
函数(f){ };
f.prototype = O;
返回新的f();
}
函数创建(方框,桌面){
var = obj(盒。原型);
f.constructor =桌子;
desk.prototype = F;
}
函数框(名称){
this.name =名称;
this.arr = {妹妹}哥',';
}
box.prototype.run =函数(){
返回this.name;
}
功能台(姓名,年龄){
box.call(这名字);
this.age =年龄;
}
InheritPrototype(箱、台); / /实现继承通过这里;
VaR桌=新桌子('lee ',100);
Desk.arr.push(上帝的);
console.log(桌子。ARR);
console.log(desk.run());
无功desk2 =新桌子(杰克',200);
console.log(桌子上2. ARR); / /两参考解决问题;
四总结
1。创建对象
可以在代码执行期间创建和增强对象,因此具有动态而非严格定义的实体;
在没有类的情况下,可以使用以下模式创建对象;
(1)。工厂模式:使用简单的函数创建对象,为对象添加属性和方法,然后返回对象;
后来这个模式被构造函数模式取代了。
(2)。构造函数模式:您可以自定义引用类型,并且在创建内置对象实例时可以使用一个眼睛中的新操作符;
缺点:每个成员不能重复使用,包括函数,因为函数不能限于任何对象,因此没有理由不在多个对象之间共享函数。
(3)。原型模式:使用函数的原型属性指定应该共享的属性和方法;
在构造函数模式和原型模式相结合时,构造函数使用构造函数定义实例属性,并使用原型定义共享属性和方法。
2。原型链
原型链的构造是通过将一个类型的实例分配给另一个构造函数的原型来实现的;
类型可以访问超类的所有属性和方法;
原型链的问题是对象实例共享所有继承的属性和方法,因此不适合单独使用。
解决方案:使用构造函数,即超类构造函数是在亚型函数;
这允许每个实例都有自己的属性,同时也确保只使用构造函数来定义类型。
最常用的继承模式是组合继承;它继承了使用原型链的共享属性和方法,并通过借用构造函数继承实例属性;
三.遗传模型
(1)。原型继承:它可以继承,而不必预先定义一个构造函数;其本质是执行给定对象的浅拷贝;
副本的副本可以进一步转换。
(2)。寄生继承:根据对象或某个信息创建对象,然后增强对象,最后返回对象;
为了解决由构造函数调用超多导致效率低的问题,这一模式可以组合继承一起使用。
(3)。寄生组合继承:寄生继承和组合继承的集合是一对一的,是实现类型继承的最有效的方法。