一、面向对象:
具有特征和行为的,可以创建自定义类型,很好的支持继承和多态,特征:封装,继承,多态,世间接可用对象来描述
而基于对象:无法创建自定义的类型,不能很好的支持继承和多态
二、JavaScript中常见的对象
2.1 无需属性的集合 其属性可以包含基本值,对象或函数
对象就是一组没有排序的值
我们可以把js想象成键值对其中值可以是数据、函数
2.2 对象行为和特征 特征----属性
行为----方法
<script type="text/javascript"> var p={ //属性 name:"张三", age:19, friends:["李四","王五"], //方法 sayhi:function(){ console.log("hi"); }, run:function(){ console.log("跑"); } }; console.log(typeof p); console.log(p); p.name="赵六"//这个传完值后就改变对象中的值 console.log(p.name); console.log(p); p.run();//调用方法 </script>
2.3 字面量对象:用于数据与数据之间的交互
2.4 json:数据交换的格式常用的有两种:
1、xml: (常用与配置文件):xml是html前身。
优点:格式清晰,但是体积太大
//xml <xml> <name>张三</name> <age>19</age> </xml>
2、json:(常用与数据交换):JavaScript对象表现形式
JavaScript的子集
3、json和对象字面量的区别
json属性必须用双引号“”引用,对象字面量可以省略
json本质是一种数据交换格式,json有两种结构:对象和数组,两种结构相互组合从而形成各种复杂的数据结构
{ //属性 "name":"张三", "age":19, "friends":["李四","王五"], //方法 "sayhi":{ "name":"张三", "age":19, "friends":["李四","王五"]} }
2.5 遍历对象的属性:for-in遍历对象的属性或者方法:
<script type="text/javascript"> var p={ //属性 name:"张三", age:19, friends:["李四","王五"], //方法 sayhi:function(){ console.log("hi"); }, run:function(){ console.log("跑"); } }; for(var key in p){ console.log(key); console.log(p[key]); } </script>
2.6 this:this所在函数中的对象中,this就代表这个对象,谁调用this就是谁,
构造函数中的this始终是new的当前对象
2.7 构造函数:new Object()
1、new后面调用函数,我们称之为构造函数,本质就是一个函数,只不过构造函数的目的为了创建新对象,为新对象创建初始化
通过函数来创建对象(不推荐使用)
<script type="text/javascript"> //构造函数中增加属性和方法 function person(){ var obj=new Object(); //属性 obj.name=null; obj.age=null; obj.sex=null; //方法 obj.study=function (){ //this是一个指针代表的是obj console.log(this.name+"在学习"); } obj.sleep=function (){ //this是一个指针代表的是obj console.log(this.name+"在睡觉"); } return obj;//返回obj } //凡是对象都有属性和方法 //定义一个变量接收这个函数 var p=person(); //用这个变量就可以调用构造函数中的属性,并且可以赋值给他 p.name="张三"; p.age=18; p.sex="女"; //输出这个变量 console.log(p); p.study(); p.sleep(); //假如定义另一个变量接收这个函数和上面的是否一样 var p1=person(); p1.name="李四"; console.log(p1); console.log(p===p1);//false 说明通过构造函数产生的对象是不同的 </script>
推荐使用这样的构造函数
<script type="text/javascript"> //1、构造函数 function dog(name,age,friends){ //2、属性 this.name=name; this.age=age; this.friends=friends; //3、方法 this.eat=function(food){ console.log(this.name+"在吃"+food); } this.run=function(running){ console.log(this.name+"在"+running); } } var dog1=new dog("旺财",2); dog1.age=5; console.log(dog1); console.log(dog1.name,dog1.age); dog1.eat("肉"); dog1.run("跑"); var dog2=new dog("来福",10,["一一","尔尔"]); console.log(dog2); console.log(dog2===dog1);//false </script>
如果上面的属性和方法多的情况下,我们就需要进行优化了
例子:通过传入字面量对象进行整体的传值与接收
<script type="text/javascript"> //1、构造函数 function dog(option){//这个地方通过传入字面量对象) //2、属性 this.name=option.name;//这样的话下面要用到传入的值就要字面量名.属性 this.age=option.age; //好处在于传值与接收都能接收到整体 this.friends=option.friends; //3、方法 this.eat=function(food){ console.log(this.name+"在吃"+food); }; this.run=function(running){ console.log(this.name+"在"+running); } } var dog1=new dog({name:"旺财",age:2});//这个位置将上面修改的字面量传入属性和值 dog1.age=5; console.log(dog1); console.log(dog1.name,dog1.age); dog1.eat("肉"); dog1.run("跑"); var dog2=new dog({name:"来福",age:10,friends:["一一","尔尔"]}); //注意传入的值都是键值对方式 console.log(dog2); console.log(dog2===dog1);//false </script>
2.8 构造器(construtor)和原型属性(prototype)
在任何一个对象中都有构造器和原型属性,包括原生的对象,比如:Data,Array等
constructor 返回创建此对象的构造函数(找到产生它的构造函数)
<script type="text/javascript"> //当我们想要添加一个方法并且构造函数中的方法可以调用时,就要用到prototype方法创建方法到函数内部 Array.prototype.name="张三"; Array.prototype.eat=function(){ alert("吃吧"); } var arr =new Array(); arr.eat(); console.log("arr的"+arr.name); var arr1 =new Array(); arr1.eat(); console.log("arr1的"+arr1.name); console.log(arr.constructor); console.log(arr1.constructor); console.log(arr1.constructor===arr.constructor); console.log(Array.constructor); </script>
prototype让我们有能力动态给对象添加属性和方法
<script type="text/javascript"> var arr=[];//字面量创建数组 var obj=={};//字面量创建对象 var arr1= new Array();//所有数组对象的构造函数 var obj= new Object();//所有对象的构造函数 </script>
<script type="text/javascript"> var obj={ name : "张三", eat:function(){ alert("ci"); } }; //当我们在外界对象添加定义一个属性时它会动态的在构造函数内部添加 obj.age=18; //如果我们上一行的赋值输出的age就为undefined,所以当构造函数中没有属性的话就直接输出undefined console.log(obj.age ); //外面可以通过对象调用属性并且改变他的值 obj.name="李四"; console.log(obj.name); console.log(obj); obj.eat=function(){ alert("吃"); } obj.eat(); //如果我们在外面通过对象添加方法时下一行的调用就会执行 obj.run=function(){ alert("pao"); } //在没有上面一行时,当在外部调用一个构造函数内部没有的方法时就会报错 obj.run(); </script>
了解了上面的对象的调用属性和方法后我们了解一下prototype:这个对象属性是将方法动态的添加的构造函数的内部,也就是放在了Array中,当添加属性后,我们在调用时可以找到,当你创建出新的构造函数调用都可以。
<script type="text/javascript"> Array.prototype.eat=function(){ alert("chi"); } var arr=new Array(); arr.eat(); var arr1=new Array(); arr1.eat(); </script>
这个代码当arr1调用eat()方法时会报错原因在于eat()方法只在arr中创建出来的,对象可以调用,而我们新建立的arr1只能调用函数内部的方法。
<script type="text/javascript"> var arr=new Array(); //给数组添加一个方法 arr.eat=function(){ alert("chi"); } arr.eat(); var arr1=new Array(); arr1.eat();//这个会报错 //报错的原因在于eat()方法只在arr中创建出来的,对象可以调用,而我们新建立的arr1只能调用函数内部的 </script>当我们想要添加一个属性并且构造函数中可以调用时,就要用到prototype方法创建属性到函数内部
<script type="text/javascript"> //当我们想要添加一个方法并且构造函数中的方法可以调用时,就要用到prototype方法创建方法到函数内部 Array.prototype.name="张三"; Array.prototype.eat=function(){ alert("吃吧"); } var arr =new Array(); arr.eat(); console.log(arr.name); var arr1 =new Array(); arr1.eat(); console.log(arr1.name); </script>prototype属性就相当于一个共享的库,我们可以创建多个构造函数实例出的对象都可以调用库中的属性和方法
下面我们将上面的标绿的代码优化
<script type="text/javascript"> //1、构造函数 function dog(option){//这个地方通过传入字面量对象) //2、属性 this.name=option.name;//这样的话下面要用到传入的值就要字面量名.属性 this.age=option.age; //好处在于传值与接收都能接收到整体 this.friends=option.friends; //3、方法将这个地方的方法改成下面共享的库形式 // this.eat=function(food){ // console.log(this.name+"在吃"+food); // }; // this.run=function(running){ // console.log(this.name+"在"+running); // } } dog.prototype.eat=function(food){//将上面的改成这样共享形式的 console.log(this.name+"在吃"+food); }; dog.prototype.run=function(running){ console.log(this.name+"在"+running); }; var dog1=new dog({name:"旺财",age:2});//这个位置将上面修改的字面量传入属性和值 dog1.age=5; console.log(dog1); console.log(dog1.name,dog1.age); dog1.eat("肉"); dog1.run("跑"); var dog2=new dog({name:"来福",age:10,friends:["一一","尔尔"]}); //注意传入的值都是键值对方式 console.log(dog2); console.log(dog2===dog1);//false console.log(dog1.eat===dog2.eat);//验证他的类型是一样的 输出true </script>
这个是优化后的最终版这两个输出的结果是一样的但是这个更加的精简,但是弊端就是这样添加会把原来的所有都覆盖掉,而上面的那个是动态的添加
<script type="text/javascript"> //1、构造函数 function dog(option){//这个地方通过传入字面量对象) //2、属性 this.name=option.name;//这样的话下面要用到传入的值就要字面量名.属性 this.age=option.age; //好处在于传值与接收都能接收到整体 this.friends=option.friends; } // // dog.prototype.eat=function(food){ // console.log(this.name+"在吃"+food); // }; // dog.prototype.run=function(running){ // console.log(this.name+"在"+running); // }; //将上面的构造函数改成字面量形式,相比较上面的一个一个的构造函数这样写更精简 dog.prototype={ eat:function(food){ console.log(this.name+"在吃"+food); }, run:function(running){ console.log(this.name+"在"+running); } }; var dog1=new dog({name:"旺财",age:2});//这个位置将上面修改的字面量传入属性和值 dog1.age=5; console.log(dog1); console.log(dog1.name,dog1.age); dog1.eat("肉"); dog1.run("跑"); var dog2=new dog({name:"来福",age:10,friends:["一一","尔尔"]}); //注意传入的值都是键值对方式 console.log(dog2); console.log(dog2===dog1);//false console.log(dog1.eat===dog2.eat); </script>
到这里的时候我就会想那属性可不可以也放入到共享中,这样就实现了代码真正的简化,如下的代码和上面修改的代码实行的结果是完全一样的
<script type="text/javascript"> //1、构造函数 function dog(option){//这个地方通过传入字面量对象) //2、调用prototype中的属性 this._init(option); } //将上面的属性放入到prototype中新建一个构造函数,里面放入属性 dog.prototype={ _init:function(option){ //2、属性 this.name=option.name;//这样的话下面要用到传入的值就要字面量名.属性 this.age=option.age; //好处在于传值与接收都能接收到整体 this.friends=option.friends; }, eat:function(food){ console.log(this.name+"在吃"+food); }, run:function(running){ console.log(this.name+"在"+running); } }; var dog1=new dog({name:"旺财",age:2});//这个位置将上面修改的字面量传入属性和值 dog1.age=5; console.log(dog1); console.log(dog1.name,dog1.age); dog1.eat("肉"); dog1.run("跑"); var dog2=new dog({name:"来福",age:10,friends:["一一","尔尔"]}); //注意传入的值都是键值对方式 console.log(dog2); console.log(dog2===dog1);//false console.log(dog1.eat===dog2.eat); </script>