<!DOCTYPE html>
<html>
<head>
<meta charset="GB2312">
<title></title>
</head>
<body>
<script>
/*var box=new Object();
box.name='Brozer';
box.age=100;
box.run=function(){
return this.name+this.age+"运行中...";
};
alert(box.run());*/
/*上面创建了一个对象,并且创建属性和方法,
在 run()方法里的 this,就是代表 box 对象 本身。
这种是 JavaScript 创建对象最基本的方法,
但有个缺点,想创建一个类似的对象,就 会产生大量的代码。*/
// 为了解决多个类似对象声明的问题,
// 我们可以使用一种叫做工厂模式的方法,
// 这种方法 就是为了解决实例化对象产生大量重复的问题。
/* function createObject(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return this.name+this.age+'运行中...';
};
return obj;
}
var box1=createObject('Brozer',21);
var box2=createObject('Brozer\'s Wife',19);
alert(box1.run());
alert(box2.run());
// 工厂模式解决了重复实例化的问题,但还有一个问题,
// 那就是识别问题,因为根本无法 搞清楚他们到底是哪个对象的实例。
*/
//JavaScript 中可以采用构造函数(构造方法)可用来创建特定的对象。类型于 Object 对 象。
/*function Box(name,age){
this.name=name;
this.age=age;
this.run=run;
}
function run(){
return this.name+this.age+'运行中...';
}
var box1=new Box('Brozer',21);
var box2=new Box('Brozer',21);
alert(box1.run());
alert(box2.run());
alert(box1.run==box2.run);//true //方法其实也是一种引用地址,通过外面调用,保证引用地址一致
alert(box1.run()==box2.run());//true 方法的值相等,因为传参一致*/
// alert(typeof box1);
// alert(box1 instanceof Box);
/*使用构造函数的方法,即解决了重复实例化的问题,
* 又解决了对象识别的问题,但问题 是,这里并没有 newObject(),
* 为什么可以实例化 Box(),这个是哪里来的呢?
* 使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
* 1.构造函数方法没有显示的创建对象(newObject());
* 2.直接将属性和方法赋值给 this 对象;
* 3.没有 renturn 语句。
构造函数的方法有一些规范:
1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和 普通函数);
2.通过构造函数创建对象,必须使用 new 运算符。
既然通过构造函数可以创建对象,那么这个对象是哪里来的,
newObject()在什么地方 执行了?执行的过程如下:
1.当使用了构造函数,并且 new 构造函数(),那么就后台执行了 newObject();
2.将构造函数的作用域给新对象,(即 newObject()创建出的对象),
而函数体内的 this 就 代表 newObject()出来的对象。
3.执行构造函数内的代码;
4.返回新对象(后台直接返回)。
关于 this 的使用,this 其实就是代表当前作用域对象的引用。
如果在全局范围 this 就代 表 window 对象,
如果在构造函数体内,就代表当前的构造函数所声明的对象。*/
/*var name='Windows10';
var age=100;
alert(box1.run());
Box.call(window,'AAA',10);
alert(name);
alert(age);
*/
/*function Box(name,age){
this.name=name;
this.age=age;
this.run=run;
}
function run(){
return this.name+this.age+'运行中...';
}
var x=new Box('Brozer',21);
alert(x.run());*/
// 原型
// 我们创建的每个函数都有一个 prototype(原型)属性,
// 这个属性是一个对象,它的用途是 包含可以由特定类型的所有实例共享的属性和方法。
// 逻辑上可以这么理解:prototype 通过 调用构造函数而创建的那个对象的原型对象。
// 使用原型的好处可以让所有对象实例共享它所 包含的属性和方法。
// 也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息 添加到原型中。
/*function Box(){
Box.prototype.name='Brozer';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
};
}
var box1=new Box();
var box2=new Box();*/
// alert(box1.run==box2.run);// true 比较一下原型内的方法地址是否一致
// //判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试
// alert(Box.prototype.isPrototypeOf(box1));
// alert(box1.name);
// box1.name='Json';
// alert(box1.name);
// alert(box2.name);
//
// delete box1.name;//把构造函数里的属性删除即可
// alert(box1.name);
// 如何判断属性是在构造函数的实例里,还是在原型里?
// 可以使用 hasOwnProperty()函数 来验证:
// alert(box1.hasOwnProperty('name'));//实例里有返回true,否则返回false
/*in操作符会在通过对象能够访问给定属性时返回 true,
无论该属性存在于实例中还是原 型中。*/
//alert('name' in box1);
/*我们可以通过 hasOwnProperty()方法检测属性是否存在实例中,
也可以通过 in 来判断 实例或原型中是否存在属性。
那么结合这两种方法,可以判断原型中是否存在属性*/
/*function isProperty(object,property){
return !object.hasOwnProperty(property)&&(property in object);
}
var box=new Box();
alert(isProperty(box,'name'));
*/
/*为了让属性和方法更好的体现封装的效果,
并且减少不必要的输入,原型的创建可以使 用字面量的方式*/
// function Box(){};
// Box.prototype={
// constructor:Box,
// name:'Brozer',
// age:100,
// run:function(){
// return this.name+this.age+'运行中....';
// }
// };
/*使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,
但还是有一些区 别,字面量创建的方式使用 constructor 属性不会指向实例,
而会指向 Object,构造函数创建 的方式则相反。*/
//
// var box=new Box();
// alert(box instanceof Box);
// alert(box instanceof Object);
// alert(typeof box.constructor);
// alert(box.constructor==Box);//true
// alert(box.constructor==Object);//false
// 如果想让字面量方式的 constructor 指向实例对象,那么可以这么做:
/*Box.prototype={
constructor:Box
};
*/
// PS:字面量方式为什么 constructor 会指向 Object?
// 因为 Box.prototype={};这种写法其实 就是创建了一个新对象。
// 而每创建一个函数,就会同时创建它 prototype,这个对象也会自 动获取 constructor 属性。
// 所以,新对象的 constructor 重写了 Box 原来的 constructor,因此会 指向新对象
// ,那个新对象没有指定构造函数,那么就默认为 Object。
//原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型。
// 原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型。
/* function Box(){};
Box.prototype={
constructor:Box,//原型被重写了
name:'Brozer',
age:21,
run:function(){
return this.name+this.age+'运行中...';
}
};
*/
/*Box.prototype={
age:200
};
*/
// var box=new Box();
// alert(box.run());
// alert(Array.prototype.sort);
// alert(String.prototype.substring);
// String.prototype.addstring=function(){
// return this+',被添加了!';
// };
//
// alert('Brozer'.addstring());
/*function Box(){};
Box.prototype={
constructor:Box,
name:'Brozer',
age:100,
family:['父亲','母亲','妹妹'],
run:function(){
return this.name+this.age+this.family;
}
};
var box1=new Box();
box1.family.push('哥哥');
alert(box1.run());
var box2=new Box();
alert(box2.run());
*/
//为了解决构造传参和共享问题,可以组合构造函数+ + + +原型模式:
/*function Box(name,age){
this.name=name;
this.age=age;
this.family=['父亲','母亲','姐姐'];
};
Box.prototype={
constructor:Box,
run:function(){
return this.name+this.age+this.family;
}
};
var box1=new Box('Brozer',21);
alert(box1.run());
box1.family.push('二姐');
alert(box1.run());
var box2=new Box('Girl',19);
alert(box2.run());*/
// 原型模式,不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,
// 并且在 声明一个对象时,构造函数+原型部分让人感觉又很怪异,
// 最好就是把构造函数和原型封装 到一起。为了解决这个问题,我们可以使用动态原型模式。
// function Box(name,age){
// this.name=name;
// this.age=age;
// if(typeof this.run!='function'){ //仅在第一次调用的初始化
// alert('第一次初始化');
// Box.prototype.run=function(){
// return this.name+this.age+'运行中...';
// };
// }
// }
// var box=new Box('Brozer',100);
// alert(box.run());
// alert(box.run());
//
// var box2=new Box('Jack',19);
// alert(box2.run());
// alert(box2.run());
/*当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。
当第二次调用,就 不会初始化,并且第二次创建新对象,原型也不会再初始化了。
这样及得到了封装,又实现 了原型方法共享,并且属性都保持独立。*/
/*以上讲解了各种方式对象创建的方法,如果这几种方式都不能满足需求,
可以使用一开 始那种模式:寄生构造函数。*/
// 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('Brozer');
// 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('Brozer',21);
// alert(box.run());
/*四.继承 继承是面向对象中一个比较核心的概念。
其他正统面向对象语言都会用两种方式实现继 承:一个是接口实现,一个是继承。
而 ECMAScript 只支持继承,不支持接口实现,而实现 继承的方式依靠原型链完成。*/
// function Box(){ //Box构造
// this.name='Brozer';
// }
//
// function Desk(){ //Desk构造
// this.age=100;
// }
//
// Desk.prototype=new Box(); //Desk继承了Box,通过原型,形成链条
// var desk=new Desk();
// alert(desk.age);
// alert(desk.name);
//
// function Table(){
// this.level='AAAAAAA';
// }
// Table.prototype=new Desk();//继续原型链继承
//
// var table=new Table();
// alert(table.name);
//
// function Box(age){
// this.name=['Java','C#','C','C++','Android'];
// this.age=age;
// }
// Box.prototype.run=function(){
// return this.name+this.age;
// };
//
// function Desk(age){
// Box.call(this,age);
// }
//
// Desk.prototype=new Box();
// var desk=new Desk(100);
// alert(desk.run());
//
/*function obj(o){
function F(){}
F.prototype=o;
return new F();
}
var box={
name:'Brozer',
arr:['brother','sister']
};
var box1=obj(box);
alert(box1.name);
box1.name='Jack';
alert(box1.name);
alert(box1.arr);
box1.arr.push('parent');
alert(box1.arr);
var box2=obj(box);
alert(box2.name);
alert(box2.arr);*/
</script>
</body>
</html>
Javascript——面向对象与原型(操作指南)
最新推荐文章于 2020-06-22 16:21:05 发布