ECMAScript有两种开发模式:1、函数式(过程化),面向对象(oop)【好处:有了引用类型的对象可直接调用这个对象对应的方法】
任何一个事物都可以看成是一个对象
1、创建对象
var stu1 = new Object(); //小丽 等于 新 老婆();
stu1.name="小丽";//属性name就是一个变量
stu1.study =function(){
alert("我叫"+this.name+"爱学习");
}; //实现学习这个功能,行为 定义为函数
alert.name;
alert.study();
这种方式创建了多个学生对象,重复性代码很多
2、使用工厂模式创建对象:解决实例化对象产生大量重复的问题(属性和行为时一样的)
function createObj(name,age){
var obj = new Object();
obj.names =name;
obj.ages = age;
obj.study = function(){
alert("我叫"+this.names+"今年"+this.ages+"爱学习");
};
return obj;//返回的是对象的引用
}
var stu3 =createObj("张三",23);//var stu3 = obj;
//解释一下子: return obj 最后把obj这个对象返回了,返回的是个引用(var obj = new Object();),stu3接收到了obj这个引用,引用里存放的是new Object()这个对象的内存地址,所以stu3接收到的是这个对象的地址,stu3也就指向了张三这个对象
var stu4 =createObj("李四",22);
工厂模式存在的问题:不能确定对象具体的类型
3、使用构造函数(方法)创建特定的对象:
//根据创建对象来起名字
function Student (name,age){
this.name = name; //后台自动创建了 new Object()
this.age = age; //this就指向了这个对象
this.study=function(){
alert(this.name+","+this.age);
}; //后台返回了该对象
}
var stu1 = new Student("zhang",23);
alert(stu1.name);
alert(stu1.age);
stu1.study();
var stu2 = new Student("李斯",20);alert(stu2.name);alert(stu2.age);stu2.study();
//注意:构造函数和工厂模式的区别:
1、构造函数中直接给name、age赋值,没有显示的创建对象(new object());
2、直接将属性和方法赋值给this对象;
3、没有使用return返回;
构造函数的特点:
(1)、定义构造函数是 构造函数的函数名首字母大写,为了和普通函数区分
(2)、使用构造函数时必须使用new(这样才能生成一个新的对象)例如:var stu1 = new Student("zhang",23);
把构造函数当成普通函数调用:Student(“张三”,40);没有任何意义(X)因为这个函数没有返回值,得不到对象,只有new之后,后台才能返回对象。
(3)、alert(stu1 instanceof Student); //判断stu1具体什么类型的实力,判断stu1是不是Student这种类型的,显示true 或 flase
(4)、构造函数中的函数study 是一个引用类型变量 存放的是函数的地址(函数的引用)每new一个对象中的函数study的地址是不同的
4、使用原型
原型的好处:实现了数据的共享。
引用类型中都含有prototype(原型)属性,该属性指向对象
var obj = {
country:"中国";
};//定义一个对象,给对象定义一个country属性值为中国
function Student (name,age){ this.name = name; this.age = age; this.study=function(){ alert(this.name+","+this.age); }; }
Student.prototype =obj;//把Student的原型设置为obj对象(把Student引用类型的这种函数的prototype属性指向obj这个对象)
var stu1 = new Student("zhang",23);var stu2 = new Student("li",20);
alert(stu1.country);//显示中国
alert(stu2.country);//显示中国
注意:是给创建对象的这个构造函数定义原型,从而使用Student创建的对象中都具备了原型对象obj中的这个内容。
prototype写成 _ _proto_ _
如果是一个对象,看他的原型对象:obj.__proto__(用__proto__)
stu1._ _proto_ _ 得到stu1的原型对象
stu1._ _proto_ _._ _proto_ _ 得到的是obj的原型对象
obj._ _proto_ _ 得到的是obj的原型对象
显示的也是一个object类型的一个对象
obj._ _proto_ _ ._ _proto_ _ //显示的是空 最基本的object类型中就没有原型对象了 得到的是obj的原型对象的原型对象
//判断一个对象是否指向了构造函数的原型对象
alert(Student.prototype.isPrototypeOf(stu1));//返回的是true 或是flase
解释一下:判断stu1是不是指向了构造函数Student的原型对象 比较谁isPrototypeOf(***) ***就写谁
stu1.name 指的是stu1对象中的属性name值
如果原型对象中也有个name
var obj = { country:"中国"; name:"tom";};stu1.name 还是指的是stu1对象中的属性name值
说明:对象中含有name属性则优先使用对象中的属性,如果对象中没有的属性再到原型中查找有没有需要的属性 (构造方法中自己有的属性就用自己的,没有的再用原型中的)
①hasOwnProperty()方法:判断是否自己含有的属性
alert(stu1.hasOwnProperty('name')); //显示true 对象stu1中本身就有name属性
②'name' in stu1 这种方法是看一下stu1中(无论是自身还是原型中)是否含有name属性
Student中如果不设置prototype属性的值,他也含有默认的object对象(Student本身就含有prototype原型对象)
Student.prototype =obj;覆盖了Student的原有的原型对象
obj的原型对象是object
obj具备object里面的属性和方法
Student具备obj里面的属性和方法也具备object里面的属性和方法
默认原型和设置的原型的区别:
var stu = new Student("zhang",22);
构造 constructor属性 stu .constructor表示stu这个对象的构造方法是什么
如果使用的是默认原型object时, stu .constructor使用的构造函数是 function Student(name,age){}
如果使用的是obj这个原型时 ,stu .constructor使用的构造函数是obj 的构造方法 就是 functionObject(){}这个构造方法
如果我们用的是Student.prototype = obj;这个原型时,但是我们想用的是Student这个构造方法所以在原型对象要这样写:
var obj ={
constructor:Student, //要加上这句,意思是强制创建的stu对象时使用的构造方法为Student方法
country:"中国"
};
或者不覆盖原型,向原型对象中添加一个新属性(在Student原有的原型对象中添加一个country属性,使用的是本来的默认原型对象)
Student.prototype.country = "中国"
这两种方式,建议使用第一种方式
function Student (){ }Student.prototype = { name:"xin", age:22, family:['妈妈','爸爸'], fun:function(){ return this.name; }};这样是有问题的, 创建的任何一个对象的姓名和年龄都相同了,对于引用类型放到原型中,若一个对象进行其修改,其他对象都变化了。(对特有的属性应定义在构造函数中,而共享的定义在原型当中) 解决这个问题利用构造函数+原型 这种模式 如下:
5、使用构造函数+原型
function Student (name,age){ //每个对象特有的数据使用构造函数
this.name = name; this.age = age; this.family =['妈妈','爸爸'];
}
Student.prototype = { //所有对象共享的内容定义在原型对象中
fun:function(){
return this.name + this.age+ this.family;
}
}
var stu1 = new Student("liso",20);
stu1.family.push("姐姐");//给stu1的family中添个姐姐
alert(stu1.family);//显示的是 妈妈 爸爸 姐姐
var stu2 = new Student("zhao",21);
alert(stu2.family);//显示的是 妈妈 爸爸
这样就互不影响了
6、使用动态原型
动态原型模式:将两部分写在一起
function Student (name,age){ this.name = name; this.age = age; this.family =['妈妈','爸爸'];
//原型直接写在构造函数当中 alert("原型被初始化开始");Student.prototype.fun = function(){ return this.name + this.age+ this.family; } alert("原型被初始化结束");
}
var stu1 = new Student("liso",20);alert(stu1.fun());//显示liso,20,妈妈 爸爸
var stu2 = new Student("zhang",24);alert(stu2.fun());//显示zhang24妈妈 ,爸爸
这样存在一个问题:每次创建对象时都会把原型代码初始化一次,应该第一次初始化一次,之后就不用初始化了,所以在外面加一个判断:
function Student (name,age){ this.name = name; this.age = age; this.family =['妈妈','爸爸']; if(typeof this.fun! = 'function'){ alert("原型被初始化开始");Student.prototype.fun = function(){ return this.name + this.age+ this.family; } //注:动态原型模式只能这样写,不能 Student.prototype={} 这样直接给prototype赋值对象 alert("原型被初始化结束");
} }
var stu1 = new Student("liso",20);alert(stu1.fun());
var stu2 = new Student("zhang",24);alert(stu2.fun());
7、使用寄生构造函数:工厂模式+构造函数
function Student (name,age){
var obj = new Object(); obj.name=name; obj.age = age; obj.fun= function(){ return this.name+this.age); };return obj;
}
var stu = new Student("zhang",23);
alert(stu.fun);
这种模式不能实现共享,不建议使用
8、使用稳妥构造函数:在一些安全的环境中,比如禁止使用this 和 new,这里的this是构造函数里不能使用this,这里的new是在外部实例化构造函数时不能使用new
function Person(name,age){
var obj = new Object();
boj.fun = function(){
return name +age;//直接使用参数的值
}
rerun obj;
}
var person = Person("lisi",24);//不能使用new创建对象
alert(person.fun());//显示lisi24
了解这种模式就行
alert(Array.prototype.sort);//显示function sort(){} 说明sort是原型对象中的一个方法
String.prototype.substr // 如上sort
js内部定义的引用类型也都是含有原型的,并可以添加方法,但不建议这样使用,因为容易发生命名冲突
String.prototype.myStr = function(){
---- 功能----
} //给string的原型对象中添加一个方法