JavaScript基础知识(10)

来源:互联网 发布:mac没有host 编辑:程序博客网 时间:2024/05/20 19:49
 方法名后何时加圆括号?调用方法,立即执行,就加();将方法作为对象传递,不加()


 闭包:函数使用了不属于自己的局部变量


 闭包的问题:
 1.普通方法调用完,活动对象回收。但是闭包方法导致父活动对象不释放,所以闭包方法会占用更多内存空间。
 重新获得闭包,闭包内的局部变量都重置
 2.闭包中多个方法,访问的是同一个局部变量。只要变量变化,所有方法都受影响。


 将n放到参数里面可以实现获得一个随机的n值,但是n也属于局部变量,这种方法和之前的方法一样,都是闭包,区别就是之前的方法外界不能修改n值,而这种方法可以在首次赋值时设置n值,一般建议用这个方法
 function counter(n){
  function getUnique(){
   return n++;
  }
  return getUnique; 
 }
 var c=counter(10);  //获得n的值,且仅获得一次
 console.log(c());
 console.log(c());
 n=0;   
 console.log(c());
 console.log(c()); 
 c=null; 
 c=counter(101);   
 console.log(c()); 


 要想修改闭包内的变量,只能用闭包自己的方法。


 function counter(){
  var n=0;
  var getUnique=function(){return n++;}
  var reset=function(){n=o;} //reset活动对象里面什么都没有的,没有var和参数定义,这个n不属于reset里面的
  return [getUnique,reset];  //返回多个方法,可以放到数组里。方法就是对象,只要是对象都可以放到数组中
 }
 var funs=counter();  //获得多个方法的数组,等于var funs=[function(){return n++;},function(){n=o;}]
 console.log(funs[0]()); //取出第一个方法让它立即执行
 console.log(funs[0]()); //1
 console.log(funs[0]());  //2
 n=0;   
 console.log(funs[0]());
 console.log(funs[0]());
 funs[1]();   //调出reset方法,将方法重置。reset里面的n和getUnique里面的n是同一个
 c=null; 
 c=counter();   
 console.log(funs[0]()); 


 reset里面的n=0和getUnique里面的n++都没有定义n,使用的都是同一个父级counter里面的n


 function clusure(){
 var arr=[];
 for(var i=0;i<3;i++){   //i最后一次值是3,父级里存的是3
 arr[i]=function(){return i;};
 }
 return arr;
 }
 var funs=clusure();
 console.log(funs[0]());   //3  为何结果是这个?
 console.log(funs[1]());   //3  为何结果是这个?
 console.log(funs[2]());   //3  为何结果是这个?


 实现汇率换算:
 function change(){
   var h1_d=5.7;
   var h1_e=10;
   function rbmToD(rmb){
   return rmb/h1_d;
   }
   function rbmToE(rmb){
    return rmb/h1_e;
    }
 return[rbmToD,rbmToE];
 }
 var funs=change();
 console.log(funs[0](100));
 console.log(funs[1](100));


 自定义对象
 面向过程:以任务的执行步骤为编程顺序
     方法:封装并重用复杂任务的方式
     问题:功能和功能操作的数据,分离
 面向对象:在设计过程中,一切以描述一个对象为基本原则。
 什么是对象:封装现实中一个事物的属性和功能的结构
 对象中包含:属性和功能(在程序中功能就是方法)!


 js中的对象:其实就是关联数组!


 关联数组写法:使用key:value对,每个key之间用逗号分隔,属性名本身就是字符串
  var fbb={
       "姓名":"武则天",
       "数学":90,
       "语文":65,
       "英语":91,
       };
 console.log("姓名:"+fbb["姓名"]);
 console.log("姓名:"+fbb.姓名);  //两种方法结果一样


 fbb["姓名"]和fbb.姓名两种方式都可以,但是第一种方式里面要加引号的,以后推荐使用第二种方式。


 js中内置对象其实有11个:
 包装类型:String、Boolean、Number
 所有对象的父类型:Object、Function
 工具类型:Array、Date、RegExp、Math
 错误类型:Error(EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError)
 全局类型:Global(或者叫window)


 宿主对象:由浏览器厂家自定义提供实现
 分为两类:BOM对象、 DOM对象


 js中创建自定义对象方式:
 1.对象直接量方式:将属性名和属性值直接写出来的方式,也就是关联数组。属性名必须是字符串,但是属性名的引号可加可不加,一般不加引号的,但是要知道它是字符串。如果要在属性名中间加空格之类的,要加引号的。
 在js中凡是见到大括号{},就是对象!
 2.new Object方式:其实就是使用父类型Object创建对象。相当于创建一个空数组。如:
 var wzt=new Object();  //相当于创建一个空数组var wzt={};
 wzt.姓名="武则天";    //也可以使用wzt["姓名"]="武则天";但是不推荐按这种方式
 wzt.数学=90;
 console.log("姓名:"+wzt.姓名);
 console.log("数学成绩:"+wzt.数学);
 3. function对象模板




 关联数组的length属性是失效的!!


 遍历对象:
  var fbb={
       "姓名":"武则天",
       "数学":90,
       "语文":65,
       "英语":91
       };
 function getProperties(obj){
   for(var key in obj){
     console.log(key+":"+obj[key]);   
   }
 }
 getProperties(fbb);
 console.log(fbb.husband);  //访问一个不存在的属性是不会出错的,返回的是undefined
 if("husband" in fbb){
   console.log(fbb.husband);
 }else{
   console.log("未婚");
 }




 如何检测对象中是否存在指定属性:
 1.使用in关键字:console.log('ename' in emp1);
 2.使用对象的hasOwnProperty()方法:console.log(emp1.hasOwnProperty('ename'));
 3.使用undefined判断:console.log(emp1.ename===undefined);
 4.在条件语句中直接判断:if(emp1.ename){console.log('ename属性存在');}


 例:
 方法1:
 if("husband" in fbb){
   console.log(fbb.husband);
 }else{
   console.log("未婚");
 }
 方法2:这种方法最常用,可以判断任意对象的属性是否存在。
 if(fbb.hasOwnProperty("husband")){
   console.log(fbb.husband);
 }else{
   console.log("未婚");
 }
 方法3:
 if(fbb.husband!==undefined){
   console.log(fbb.husband);
 }else{
   console.log("未婚");
 }
 方法4:这种做法分不清null和undefined,如果将设置husband:null;或者0等时,会返回“未婚”。判断内置对象的属性或方法时,用这种方法,通常用它判断浏览器兼容性
 if(fbb.husband){
   console.log(fbb.husband);
 }else{
   console.log("未婚");
 }


 在访问那些极有可能不存在的属性时,要先判断再使用。


  创建自定义对象:3种
 1.直接量:var obj={属性名:属性值,...}
 访问属性?obj.属性名

 可能不存在的属性,使用之前必须先判断存在,再使用:
 判断任意对象是否包含属性:var boolean=obj.hasOwnProperty("属性名")
 如果包含返回true,否则返回false
 判断内置对象,浏览器对象兼容性:if(obj.属性名)--》
 undefined,null,0,"",NaN都是false,其余都是true

 自定义对象创建的依据?需求中的名词!就是软件要保存的数据。
 需求中的动词:对象
 的功能/方法
 对象的属性?表,证,单,据

 对象中的方法:其实指的就是对象中的功能。
 如何定义:var obj={
     方法名:function(){方法体}
 }

 方法其实就是一个对象。对象中的方法本质上就是一个特殊的属性。对象中的
 方法是操作数据的功能。

 对象自己的方法,如何访问自己的属性:this指代当前对象。
 什么是this?是js栈中一个固定的指针,永远指向当前正在操作的对象。


 //创建hmm对象,有姓名,年龄属性,还包含自我介绍功能
 var hmm={
   name:"Han Meimei",
   age:18;
   intr:function(){  //一个对象中的方法就是一个特殊的属性
       //自我介绍
   var str="my name is "+this.name+". I'm "+this.age+" years old";
    }
 };
 hmm.intr();     //this指针指向hmm


 操作任何元素之前,先找到他:document.getElementById();


 例:
 <script>
 var calc={
  n:undefined,
  m:undefined,
  add:function(){
    return this.n+this.m;
   },
   minus:function(){
    return this.n-this.m;
   }
 }
 calc.n=parseInt(prompt("第一个数"));
 calc.m=parseInt(prompt("第二个数"));
 </script>
 <button onclick="alert(calc.add())">加法</button>
 <button onclick="alert(calc.minus())">减法</button>


 面向对象的三大特点:封装、继承、多态
 封装:将数据和对数据的操作,包装为一个整体,过程就叫做封装。

 继承:使用现有类型,创建出新的类型。新类型中可以使用现有类型的属性和
 功能!并且新类型可以扩展出现有类型没有的属性和功能。


 所有对象的父类型,Object:toString()
                           hasOwnProperty()
 都可以被使用

 对象模板:又叫构造函数。专门从来反复创建相同结构的对象的专门方法。
 如何定义构造函数:function 类型名(属性值参数...){
 this.属性名=属性值;
 ......
 this.方法名=function(){
 方法体;
 }
 }

 new 构造函数():
 new:开空间
 构造函数:划分空间结构,并且初始化内部属性的值

 例:
 function Student(name,age){
  this.name=name;
  this.age=age;
  this.intr=function(){
 console.log("my name is "+this.name+" I'm "+this.age+" years old");
 }
 this.toString=function(){
 return "[name:"+this.name+",age:"+this.age+"]";
 }
 }
 var lilei=new Student("Li Lei",19); //new是创建一个obj,Student("Li
 Lei",19)调用构建函数
 var hmm=new Student("Han Meimei",18); 
 lilei.intr();
 hmm.intr();


 重写方法:如果子类型认为父类型的方法不好用,可以重新定义和父类型完全
 同名的方法,实现覆盖!

 console.log(lilei.toString()); //得到的值都是object
 console.log(hmm.toString());   //得到的值都是object

 默认toString方法如果无法打印内容,默认打印的是对象类型。
 一般自定义类型对象,都会重写toString方法。

 this.toString=function(){
 return "[name:"+this.name+",age:"+this.age+"]";
 }

 toString方法利用for in来更加灵活的实现:
 this.toString=function(){
  var str="";
  for(var key in this){
    if(typeof(this[key]!="function"){
    str+=key+":"+this[key]+",";
     }
   }
   return str;
 }

 整个案例综合如下:
 function Student(name,age){
  this.name=name;   //分配给将来的对象的
  this.age=age;
  this.intr=function(){
 console.log("my name is "+this.name+" I'm "+this.age+" years old");
 }
 this.toString=function(){
  var str="";
  for(var key in this){
    if(typeof(this[key])!="function"){
    str+=key+":"+this[key]+",";
     }
   }
   return str;
 }
 }
 var lilei=new Student("Li Lei",19);
 var hmm=new Student("Han Meimei",18); 
 lilei.intr();
 hmm.intr();
 console.log(lilei.toString()); //得到的值都是object
 console.log(hmm.toString());
 hmm.birth="1990-05-30";
 console.log(hmm.birth);    // 1990-05-30
 console.log(lilei.birth);  //undefined
 hmm.count=10;
 lilei.count=10;
 hmm.count--;
 lilei.count--;
 console.log(hmm.count);  //9
 console.log(lilei.count); //9


 原型与继承:
 原型:在JavaScript中,函数本身也是一个包含了方法和属性的对象。原型是
 已经存在的

 原型prototype:所有方法都有原型。构造函数背后,专门保存由方法创建出
 的对象共有的数据。任何对象无权修改原型中的数据。

 自有属性:只给一个对象定义的属性,仅属于当前对象。其他对象不能共享。
 如:
 hmm.birth="1990-05-30";
 console.log(hmm.birth);    // 1990-05-30
 console.log(lilei.birth);  //undefined

 定义共有属性:
 Student.prototype.count=10;
 /*lilei.count--;   //任何对象无权修改原型中的数据,如果赋值,会自动
 为*/对象创建同名自有属性
 Student.prototype.count--;
 console.log(lilei.count);
 console.log(hmm.count);


 Student.prototype.count=10;
 lilei.count--; 
 lilei.count--;
 Student.prototype.count--;
 console.log(lilei.count);   //取自己本身的值,8  只要自己已经有的,
 就不会从原型中取值
 console.log(hmm.count);    //取原型的值,9

 共有属性:保存在原型中,由所有同类型对象共享的属性。
 设置/读取:构造函数.prototype.共有属性名


 不管是否创建了一个函数,只要有方法,就有原型


 删除属性定义:delete方法,即可以删除自有属性,也可以删除共有属性。
 语法:delete 对象[.prototype].属性;  -->中括号里面可有可无

 hasOwnProperty:仅检测当前对象的自有属性!
 属性 in 对象:不但检测当前对象的自有属性,而且同时检测当前对象原型的
 共有属性!
0 0
原创粉丝点击