JavaScript面向对象编程学习总结

JavaScript面向对象编程

JavaScript所有属性和方法全部封装在对象中

  • 说明:对比C++,JavaScript的对象相当于C++的类

    ​ JavaScript对象的实例化相当于C++的对象

1、JavaScript创建对象

/*
	方法一:直接创建对象
*/

var myBook=new Object();
//一个一个添加属性和方法
myBook.name='计算机网络';
myBook.author='谢希仁';
myBook.info=function(){console.log('my book info!')}

//直接赋予方法,默认就是创建了一个Funciton函数对象
//由于在js中函数也是一个对象,因此也能够添加属性和方法
//每个函数对象都会有一个 prototype 的属性(箭头函数除外)
//一个一个添加属性和方法
var myiPad=function(){
    var privateName='private name';//添加一个私有属性,只有公有方法才能访问
    this.info='this info'; //添加一个公有属性,必须实例化对象才可访问
    console.log('myiPad!')
}
myiPad.Show = function(){
        console.log("Show Message");
    };//添加一个静态方法,只能直接对象名调用,同时无法通过this访问其他属性
myiPad.prototype.Display = function(){
        console.log("Property Message");
    };//添加一个一个继承方法,必须实例化对象才能调用,但可以通过this访问其他公有属性,私有无法访问!!
myiPad.Show()
myiPad.Display()//error

var myipad=new myiPad();
myipad.Show()//error
myipad.Display()

/*
	方法二:使用构造函数创建多个实例
*/
function Car(color,year,make){
    this.color=color;
    this.year=year;
    this.make=make;//添加公有属性
    
    var info="car info";//添加私有属性
    this.Show=function(){console.log(info);}//添加公有方法
    
}
//创建实例及使用函数
var car=Car('red','2018','China');
car.Show();
console.log(car.make);

/*
	方法三:使用JavaScript新特性:语法糖
*/
	//使用js语法糖创建的是一个test对象,而不是一个对象函数,不能被实例化!!
	var test = {
        Name:'test is a Object',
        Success:function(){
            this.Say = function(){
                    console.log("Hello,world");//Success函数下的添加公有方法
            };
             console.log("create Obj Success!!");
        }
    };
	//等价于如下写法:
/*
	var test = new Object();
    test.Name = 'test is a Object';
    test.Success = function(){
            this.Say = function(){
                    console.log("Hello,world");
            };
            console.log("create Obj Success");
*/
	//直接使用
	console.log(test.Name);
	test.Success();
	//不能被实例化
//	var a=test()//error
	//访问内部函数的方法
	var s = new test.Success();//此处会再次执行Success函数,同时创建一个实例
	s.Say();

2、JavaScript继承对象

使用prototype关键字

//假设Pet为一个定义好的宠物对象
//Dog为一个需要继承Pet的狗对象
//继承方式如下
Dog.prototype = new Pet();

3、从外部访问内部函数的属性及方法

使用this关键字

4、JavaScript的闭包函数

4.1闭包函数的定义:

JavaScript函数允许使用内部函数,即函数定义和函数表达式位于另一个函数的函数体内。

其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包

// 方法一:直接创建函数对象
var Circle = function() {  
   var obj = new Object();  
   obj.PI = 3.14159;  
     
   obj.area = function( r ) {  
       return this.PI * r * r;  
   }  
   return obj;  
}  
  
var c = new Circle();  
console.log( c.area( 1.0 ) );//在函数外调用area闭包函数

//方法二:使用语法糖  
var Circle={  
   PI:3.14159,  
   area:function(r){  
          return this.PI * r * r;  
        }  
};  
console.log( Circle.area(1.0) );
4.2闭包函数的特性:
  • 能够通过this访问所在函数的所有局部变量,参数和其他方法

  • 执行方式是异步的,不同于所在函数,执行方式是同步

    var outter = [];  
    function clousetest () {  
        var array = ["one", "two", "three", "four"];  
        for(var i = 0; i < array.length;i++){  
           var x = {};  
           x.no = i;  
           x.text = array[i];  
           x.invoke = function(){  
               print(i);  
           }  
           outter.push(x);  
        }  
    }  
    //调用这个函数  
    clousetest();  
       
    console.log(outter[0].invoke());  
    console.log(outter[1].invoke());  
    console.log(outter[2].invoke());  
    console.log(outter[3].invoke()); 
    //由于闭包函数为异步执行方式,在函数迭代完成后,外部函数才开始执行x.invoke(),此时i已经为4,故上述结果均为4
    
    //解决方法将闭包函数改为自执行函数
    function clousetest2(){  
        var array = ["one", "two", "three", "four"];  
        for(var i = 0; i < array.length;i++){  
           var x = {};  
           x.no = i;  
           x.text = array[i];  
           x.invoke = function(no){  
               return function(){  
                  print(no);  
               }  
           }(i);  
           outter.push(x);  
        }    
    } 
    
4.3闭包函数的强大用途:
4.3.1自执行函数

优点:

  • 有的函数只需要执行一次,其内部变量无需维护
  • 函数立即执行,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象。
var data= {    
    table : [],    
    tree : {}    
};         
(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }           
})(data);//创建一个匿名的自执行函数,并将外部数据传入,函数立即执行,立刻释放资源!!
4.3.2闭包缓存结果
  • 不会释放外部的引用,从而函数内部的值可以得以保留。

参考博文链接:http://www.makaidong.com/博客园牛/13582.shtml

4.3.3使用闭包访问函数内部变量
var person = function(){  
    //变量作用域为函数内部,外部无法访问  
    var name = "default";     
     
    return {  
       getname : function(){  
           return name;  
       },  
       setname : function(newname){  
           name = newname;  
       }  
    }  
}();  
   
console.log(person.name);//直接访问,结果为undefined  
console.log(person.getname());  
person.setname("abruzzi");  
console.log(person.getname());  
4.3.4使用闭包函数千万小心 this对象引用的错误
$(function(){  
    var con = $("#p1");  
    this.id = "content";  
    con.click(function(){  
       console.log(this.id);// 一般的闭包函数可以通过this访问外部的变量和方法
    });//但是此函数为匿名函数,默认注册在Windows对象中,所以打印的this.id为标签#p1的id值而非content
}); 

//非常简单的解决办法:使用一个代理变量self或者that代理当前函数对象
$(function(){  
    var con = $("#p1");  
    this.id = "content"; 
    var self=this; 
    con.click(function(){  
       console.log(self.id);
    });
}); 

注意this的使用:this表示拥有该方法的所在对象

//比如
function foo(){
   this.id=10;
    setTimeout(function(){
        console.log(this.id);
    },1000)
}
var id=21;
foo();
	//输出21
//由于foo()方法没有绑定对象,则默认在Windows对象下注册,所以this指向Windows对象

//解决方法一:
	//自己绑定一个对象
var  foo=function(){
    	this.id=10;
   		setTimeout(function(){
        console.log(this.id);
    },1000)
}
var id=21;
foo();
	//输出10

//解决方法二:使用箭头函数,this为固定绑定在定义时的函数对象,而非运行时注册的对象
function foo(){
    this.id=10;
    setTimeout(()=>{
        console.log(this.id);
    },1000);
}
var id=21;
foo();
	//输出10

//解决方法三:使用一个代理变量self或者that代理当前函数对象
function foo(){
   	this.id=10;
    var self=this;
    setTimeout(function(){
        console.log(self.id);
    },1000)
}
var id=21;
foo();
	//输出10

5、强大而又烦恼的回调函数

5.1回调函数的定义:

​ 函数A作为参数传递至另一个函数B,并有函数B执行A,则A称为一个回调函数,如果函数没有名称,则就叫匿名回调函数,简单来说,回调函数是作为一个参数传递执行

//无参数的回调函数
function Buy(name,goods1,callback) {
    alert(name+' buy '+goods1);
    if(callback&&typeof(callback)==="function")
        callback();//此API表示如果传入一个回调函数,则执行此函数
}
Buy('xiaoming','apple',function(){
    alert("shopping finish");
});
	//自定义一个使用回调的API函数,并进行调用

//有参数的回调函数
	//定义使用回调的API函数
function getRecommnedMusic(callback){
    var data ={
    g_tk:5381,
    uin:0,
    format:'json',
    inCharset:'utf-8',
    notice:0,
    platform:'h5',
    needNewCode:1,
    _:Date.now()
    };
    
    wx.request({
    url: 'http://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg',
    data:data,
    header:{
      'Content-Type':'application/json'
    },
    success:function(res){
      if(res.statusCode==200){
        console.log(res.data)
        callback(res.data) //表示将res.data传入回调函数之中
      	} else{
        console.log(res.data)
      }
    }
  })
}	
	//调用API函数
getRecommendMusic(
	function(data){
        var self=this;
        if(data.code==0){
            self.setData({
            slider:data.data.slider,
            radioList:data.data.radioList, //这里回调函数直接拿到res.data数据,并将其作为data参数提供给回调函数使用
      })
    }
  }
)
5.2回调函数的特性:
  • 回调函数同步执行,在调用函数代码执行完之后,才开始回调
  • 异步执行,回调函数不一定执行
5.3回调函数的强大作用
5.3.1通过传参给回调函数直接拿到调用函数的传入数据

可以在调用函数定义时将数据传给回调函数,从而使用回调函数直接拿到调用函数的内部操作数据

//拿jQuery请求数据距离
$.Ajax({
    url:'https://www.baidu.com',
    data:'void',
    success:function(res){
        if(res.statusCode==200){
            console.log(res.data)
            callback(res.data) //表示将res.data传入回调函数之中
        } else{
            console.log(res.data)
        }//这里success就是一个回调函数,res就是已经拿到调用函数所响应的数据
    }
})
/*解释:
	一般封装API,JavaScript允许传入一个回调函数,定义API时将内部数据作为参数传给回调函数
	那么,那么,那么,你在调用这个API时,就可以使用回调函数直接拿到API内部的局部数据,之后就可以使用回调函数进行为所欲为的操作,非常强大,对比闭包函数,要想拿到内部数据,必须返回一个公有方法,并且还需要调用这个公有方法,才能访问
*/
	//使用闭包函数获取函数API中的局部数据
var person = function(){  
    //变量作用域为函数内部,外部无法访问  
    var name = "default";     
     
    return {  
       getname : function(){  
           return name;  
       },  
       setname : function(newname){  
           name = newname;  
       }  
    }  
}();
console.log(person.getname());  
person.setname("abruzzi");  
console.log(person.getname()); 
			//打印default
			//打印abruzzi
	//使用回调函数拿到函数内部数据
var person=function(callback){
    var name='default';
    callback(name);
}
person(function(name){
    console.log(name);
})
			//打印default
5.3.2封装调用API的两种书写形式:
	//方法一:直接balabala一大堆的参数传入
var person=function(setname,url,callback){
    var name='default';
    callback(setname,name,url);
}
person('myname','baidu.com',function(setname,name,url){
    console.log(name+' '+setname+' '+url);
})	

	//方法二:使用对象语法糖
//定义一个person封装的API
var person=function(options){//传入一个options对象,形式为{}里面可以传入各种参数,如											setname,url,callback
    var name='default';
    options.callback(options.setname,name,options.url);
}
//调用一个封装好的person()方法,并使用语法糖传入对象参数
person({
    setname:'myname',
    url:'baidu.com',
    callback:function(setname,name,url){
    	console.log(name+' '+setname+' '+url)
    }//采用ES6的语法糖的形式进行书写
})


5.3.3深入异步编程
//所谓异步编程,指函数内部还有函数,则此函数相对于外部函数就是异步执行=====>就是闭包函数
function add(x,y,callback){
    console.log(1)
    setTimeout(function(){
        console.log(3)
        var ret=x+y
        callback(ret)
    },1000)
    console.log(2)
}
add(10,20,function(ret){
    console.log(ret)
})
	//打印结果1,2,3,30
//此函数使用setTimeout闭包函数,异步执行,再使用回调函数,取得ret数据,并将其打印出来
5.3.4 ==模拟封装$.ajax()方法
//注册全局对象
$ = {
    //自定义一个ajax全局方法
    ajax:function(options){//这里options为一个{ }对象,里面可以传入各种数据,实名回调函数均可
        //初始化数据
        var method=options.method
        var url=options.url
        //创建服务器请求对象
        xmlhttp=new XMLHttpRequest();
        //初始化发送请求方式及路径
        xmlhttp.open(method,url,true)
        //发送请求
        xmlhttp.send()
        //当加载完成时调用回调函数,将相应的数据传出去
        xmlhttp.onload=function(){
           // console.log(xmlhttp.responseText)
            options.success(xmlhttp.responseText)//调用options的success实名回调函数,将相应数据传给success回调函数
        }
    }	///封装完毕!!!
}
//开始调用$.ajax方法
$.ajax({
    method:'get',
    url:'http://www.baidu.com',
    success:function(res){
        console.log(xmlhttp.responseText)
    }
})

​ **调用出现成功结果:**这里注意本地直接使用Ajax方法请求访问本地文件,会出现跨域问题,必须本地开启服务器,使用完整的Http的URL请求才能访问成功!!!这里我自己开启了本地的Apache服务器,并将文件放置在了Apache网页主目录www中…

在这里插入图片描述

5.4回调函数的烦恼—回调地狱!!!
背景描述:

使用多个异步执行函数无法保证执行顺序,如下:

setTimeout(function(){
        console.log(1)
    },1000)
setTimeout(function(){
        console.log(2)
    },0)
setTimeout(function(){
        console.log(3)
    },1000)
setTimeout(function(){
        console.log(4)
    },1000)
	///打印结果3,1,2,4

//解决办法如下,使用嵌套的回调函数
setTimeout(function(){
        console.log(1)
        setTimeout(function(){
            console.log(2)
            setTimeout(function(){
       			 console.log(3)
                 setTimeout(function(){
                    console.log(4)
                },1000)
    		},1000)
        },0)
    },1000)
	///必定打印结果1,2,3,4
///思考如果嵌套more个函数呢????于是乎嵌套的回调地狱就出现了,代码的维护,可读性非常差!!
使用promise优化:
//使用Promise存放多个异步任务的容器
	//ES6提供Promise的API
var p1=new Promise( function(resolve,reject){
    //pending正在做的两大状态,resolve成功,reject解决
    //创建一个容器,一旦创建,立即执行,Promise本身不是异步,包含异步任务!!
    setTimeout(function(){
        var err=true;
        var data='我的数据';
        if(err){
            reject(err);
        }else{
            resolve(data);
        }
        console.log(2);
    },1000);
    console.log(1);
})
var p2=new Promise( function(resolve,reject){
    setTimeout(function(){
        var err=true;
        var data='我的数据';
        if(err){
            reject(err);
        }else{
            resolve(data);
        }
        console.log(3);
    },1000);
    // console.log(1);
})
var p3=new Promise( function(resolve,reject){
    setTimeout(function(){
        var err=true;
        var data='我的数据';
        if(err){
            reject(err);
        }else{
            resolve(data);
        }
        console.log(4);
    },1000);
    // console.log(1);
})
//使用Promise.then()方法接受容器的回调函数
p1
   .then(function(data){
    console.log(data)
    return p2
},function(err){
    console.log(err)
})  //第一个函数参数为resolve函数,第二个函数为reject函数
	.then(function(data){
	console.log(data)
	return p3
})
自己封装Promise
//自己封装Promise
function PsetTimeout(num){
    return new Promise( function(resolve,reject){
    setTimeout(function(){
        var data='我的数据';
        resolve(data);
        console.log(num);//回调函数resolve和reject可以不使用
    },1000);
    // console.log(1);
})
}
PsetTimeout(1)
    .then(function(data){
    console.log(data)
    return PsetTimeout(2)
})
    .then(function(data){
    console.log(data)
    return PsetTimeout(3)
})
    .then(function(data){
    console.log(data)
    return PsetTimeout(4)
})
		/*
		打印结果如下: 1 我的数据
				     2 我的数据
				     3 我的数据
				     4 我的数据
		*/
	//建议封装好函数,代码易于维护,而且有木有觉得很优美,对比上一段长长的代码
Promise的使用场景:在多个ajax请求接口时,必须使用promise封装
//封装一个get的promise请求
function get(method,url){
    return new Promise(function(resovle,reject){
        var xmlhttp=new XMLHttpRequest()
        xmlhttp.open(method,url,true)
        xmlhttp.send()
        xmlhttp.onload=function(){
            resovle(xmlhttp.responseText)
        }
    })
}
get('get','http://localhost/callback-ajax/callback.html')//请求接口一的数据
    .then(function(data){
    console.log(data)
    return get('get','http://localhost/callback-ajax/callback2.html')
    //一请求完毕之后,再请求接口二的数据
})
	.then(function(data){
    console.log(data)
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值