原型

来源:互联网 发布:oracle和mysql的优缺点 编辑:程序博客网 时间:2024/05/15 15:56
1.this:表示当前作用域下,要放在一个作用域下


2.面向对象与原型
//有大量重复的代码
var box =new Object();
box.name='gt';
box.age=18;
box.run=function(){
return this.name+this.age+"loading..."
};
var box1 =new Object();
box.name='lry';
box.age=20;
box.run=function(){
return this.name+this.age+"loading..."
};
//alert(box.run());
//工厂模式:解决了重复的实例化问题,但无法搞清是哪个对象的实例----------------------------------
function createObj(name,age){
var obj=new Object();    //创建对象
obj.name=name;           //创建属性
obj.age=age;
obj.run=function (){ //添加方法
return this.name+this.age+"loading...";
};
return obj;      //返回对象引用
}

var box=createObj("gt",18);   //创建第一个引用
var box1=createObj('lry',20); //创建第二个引用

alert(box.run());   //打印第一个实例run()方法
alert(box1.run());


//构造方法(构造函数):构造函数和普通函数的唯一区别,就是他们调用的方式不同。
    只不过,构造函数也是函数,必须用 new 运算符来调用,否则就是普通函数。----------------------------
function Obj(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+this.age+"loading...";
};
}

var box=new Obj('gt',200);
var box1=new Obj('lry',100);

alert(box.run());
alert(box1.run());

1.构造函数方法没有显示的创建对象,运行后台自动创建(new Object());
2.直接将属性和方法赋值给 this 对象;
3.没有 renturn 语句。
构造函数的方法有一些规范:
1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和
普通函数);
2.通过构造函数创建对象,必须使用 new 运算符。
既然通过构造函数可以创建对象,那么这个对象是哪里来的,new Object()在什么地方
执行了?执行的过程如下:
1.当使用了构造函数,并且 new 构造函数(),那么就后台执行了 new Object();
2.将构造函数的作用域给新对象,(即 new Object()创建出的对象),而函数体内的 this 就
代表 new Object()出来的对象。
3.执行构造函数内的代码;
4.返回新对象(后台直接返回)
///原型----------------------------------------
我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是
包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过
调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所
包含的属性和方法。
/---------------原型
function Box(){}
Box.prototype.name="lee";
Box.prototype.age="100";
Box.prototype.run=function(){
return this.name+this.age+"loading";
}
var box=new Box();
alert(box.run());
------------字面量方式:使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有一些区
别,字面量创建的方式使用 constructor 属性不会指向实例,而会指向 Object,构造函数创建
的方式则相反。----
function Box(){}
Box.prototype={
constructor : Box,//让字面量方式的 constructor 指向实例对象
name:"lee",
age:"100",
run:function(){
return this.name+this.age+"loading";
}
}
var box=new Box();
alert(box.name);
------------重写:不会保留原来的东西----
function Box(){}
Box.prototype={
name:"lee",
age:"100",
run:function(){
return this.name+this.age+"loading";
}
}

Box.prototype={
name:"gt",
}
var box=new Box();
alert(box.age);//结果为undefined
//------------扩展内置应用类型:尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种方法。因为它可能会导致命名冲突,不利于代码维护。----
1.调用内置应用类型
var box=[1,7,5,8,3,8,9,4,0];
alert(box.sort());
alert(Array.prototype.sort);//查看sort方法是否为Array对象里的方法(方法不能加‘()’);
2.扩展
>alert(String.prototype.addstring);先查看一下这个方法是否存在,结果为undefined
String.prototype.addstring=function(){
return this+'已被添加!';
};

var box="gt";
alert(box.addstring());

alert("gt".addstring());
//------------原型的缺点:
1.原型模式创建对象也有自己的缺点,它省略了构造函数传参初始化这一过程,带来的缺点就是初始化的值都是一致的。
2.而原型最大的缺点就是它最大的优点,那就是共享。
原型中所有属性是被很多实例共享的,共享对于函数非常合适,对于包含基本值的属性
也还可以。但如果属性包含引用类型,就存在一定的问题:
----------
function Box(){}
Box.prototype={
constructor:Box,
name:"lee",
age:100,
family:['哥哥','姐姐','妹妹'],//(数组)引用类型原型
run:function(){
return this.name+this.age+'loading...'
}
}
var box=new Box();
alert(box.family);  //结果:哥哥,姐姐,妹妹
box.family.push('弟弟');
alert(box.family); //结果:哥哥,姐姐,妹妹,弟弟

var box1=new Box();
alert(box1.family);//结果:哥哥,姐姐,妹妹,弟弟(虽然重新实例化了box1,但其共享了box中添加后的引用类型原型)


为了解决构造传参和共享问题,可以---组合构造函数+原型模式----:即需要独立的写在构造函数里,共享使用原型
---组合构造函数+原型模式---
function Box(name,age){//保持独立的
this.name=name;
this.age=age;
this.family=['1','2','3'];
}
Box.prototype={//保持共享的
constructor:Box,
run:function(){
return this.name+this.age+this.family+"loading...";
}
}

var box=new Box('gt',20);
alert(box.run());//gt201,2,3loading...
alert(box.family);//1,2,3
box.family.push("4");
alert(box.family);//1,2,3,4

var box1=new Box('lry',50);
alert(box1.run());//lry501,2,3loading...
alert(box1.family);//1,2,3//引用类型没有使用原型,所以没有共享


不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,并且在声明一个对象时,
构造函数+原型部分让人感觉又很怪异,最好就是把构造函数和原型封装到一起。为了解决这个问题,我们可以使用
---动态原型模式-----
1.可以将原型封装到构造函数里,但原型的语句会被初始化两次:原型的初始化只要第一次就可以了,没必要每次构造函数实例化时都初始化
function Box(name,age){
this.name=name;
this.age=age;
this.family=['1','2','3'];
alert('1');
Box.prototype.run=function(){
return this.name+this.age+this.family+"loading...";
}
alert('2');//会打印两次1 2
}

var box=new Box('gt',20);
alert(box.run());//gt201,2,3loading...

var box1=new Box('lry',50);
alert(box1.run());//lry501,2,3loading...



2.解决初始化两次的方法:
function Box(name,age){
this.name=name;
this.age=age;
this.family=['1','2','3'];
if(typeof this.run!='function'){
alert('1');//测试执行几次
Box.prototype.run=function(){
return this.name+this.age+this.family+"loading...";
}
alert("2");
}
}

var box=new Box('gt',20);

var box1=new Box('lry',50);

//以上讲解了各种方式对象创建的方法,如果这几种方式都不能满足需求,可以使用一开
始那种模式:寄生构造函数。
function Box(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}

寄生构造函数,其实就是工厂模式+构造函数模式。这种模式比较通用,但不能确定对
象关系,所以,在可以使用之前所说的模式时,不建议使用此模式。
在什么情况下使用寄生构造函数比较合适呢?假设要创建一个具有额外方法的引用类
型。由于之前说明不建议直接 String.prototype.addstring,可以通过寄生构造的方式添加。

function myString(string) {
var str = new String(string);
str.addstring = function () {
return this + ',被添加了!';
};
return str;
}
var box = new myString('Lee'); //比直接在引用原型添加要繁琐好多
alert(box.addstring());

在一些安全的环境中,比如禁止使用 this 和 new,这里的 this 是构造函数里不使用 this,
这里的 new 是在外部实例化构造函数时不使用 new。这种创建方式叫做稳妥构造函数。
function Box(name , age) {
var obj = new Object();
obj.run = function () {
return name + age + '运行中...'; //直接打印参数即可
};
return obj;
}
var box = Box('Lee', 100); //直接调用函数
alert(box.run());
PS:稳妥构造函数和寄生类似。
原创粉丝点击