第五单元
6.面向对象编程基础
一.建立面向对象3步:
1.创建构造函数或类(公有属性):
function Person(name1,gender1){ //声明一个构造函数
this.name=name1; // 把变量变成对象的属性用this
this.gender=gender1;
}
2.通过原型扩展构造函数功能:把函数变成对象的方法(用prototype)
Person.prototype.eat=function(){
console.log('姓名:'+this.name+'性 别:'+this.gender)
}
3.创建实例化对象,通过new
var man=new Person('奎哥','男');
调用方法:
man.eat();
man.say();
面向对象编程(OOP)的特点:
抽象:抓住核心问题
封装:只能通过对象来访问方法
继承:从已有的对象下继承出新的对象
多态:多对象的不同形态,目的是灵活的复用
JS不支持面向对象(半面向对象)
最终目的:方便扩展,灵活复用
一.选项卡-面向过程:
1.this指向问题
事件函数里直接调用方法指向当前对象 obj.onclick=tab;
2.如果又套一层函数,调用方法 obj.onclick=function(){tab()}this指向window;
解决方法:定义全局变量 var that=0;在函数里存储this obj.onclick=function(){
that=this;
tab()
}
相对应tab方法里用到的this,修改成相对应的that
二.选项卡-面向对象:
面向对象写法
// - 尽量不要出现函数嵌套函数
// - 可以有全局变量
// - 把onload中不是赋值的语句放到单独的函数中
1.构造函数里this指向:new出来的对象或当前父类
2.通过原型扩展的tab方法要通过构造函数里的this(new出来的对象)调用 This.tab();
/*修改步骤:1.把传统方法升级成不要函数嵌套的方法
2.把局部变量变成全局:同时页面内用到局部变量修改成对应的this调用
3.存储this:var This=this;//存储外面new对象的this,调用原型上的方法时用This.change();调用
1. json处理
.数据类型:对象 {}
1.字符串 var str='1802b'
2.数组 var arr=['a',1] 取值:arr[0] 遍历 for(var i=0;i<arr.length;i++)
3.对象:key,value var json={key:value,key1:value1} 遍历:
for(var i in json)
json数据渲染-字符串拼接变量法
var a=" ";
for(var i=0;i<arr.length;i++){
a += "<dl><dt>"+arr[i].name+"</dt>";
for(var j=0;j<arr[i].content.length;j++){
a += "<dd class="+arr[i].content[j].hot+">"+arr[i].content[j].name+"</dd>";
}
a += "</dl>"
box.innerHTML = a; //别忘记获取对象追加页面
}
//渲染数据时字符串拼接比较麻烦-"字符串"+变量
//es6[现在es5语法]字符串拼接: `` 反引号代替'' , ${变量}代替原来变量写法
json数据大部分是后台给你的,后台给你数据都是'{}',原本要用的对象{},把它转成原本格式用到的方法:eval("("+原本对象+")");
处理逻辑
obj.onchage=function(){
//改变时拿到当前索引内的值select对象属性: options ,selectedIndex
oinpt.value = osel.options[this.selectedIndex].innerHTML;
}
2.鼠标滚轮加数据
概念: 鼠标滚轮事件 onmousewheel-应用场景:跟鼠标滚轮有关系-全屏滚动等场景
onscroll 滚动条事件 -应用场景-电商网站折叠楼层,回到顶部,懒加载,瀑布流等
.onmousewheel-鼠标滚轮事件 -ie,ch
dom0级事件绑定方法: obj.事件=function(){}
DOMMouseScroll -ff火狐 dom二级事件:需要通过事件绑定方式执行
obj.addEventListener('不带on事件',函数,false)
obj.addEventListener('DOMMouseScroll',函数,false)
.事件对象:事件里包含的属性.
obj.onclick=function(ev){
var event=ev||window.event
console.log(event)
console.log( event.wheelDelta ); //跟滚轮有关的属性
}
封装-通过引入插件(别人封装好的代码,直接用)形式引用
//回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当主函数执行完之后,再执行传进去的这个函数
function A(cb){
console.log('我是主函数')
cb()
}
A(B)
function B(){
console.log('我是回调函数')
}
7.继承,封装组件
一.建立面向对象3步:
1.创建构造函数或类(公有属性):
function Person(name1,gender1){ //声明一个构造函数
this.name=name1; // 把变量变成对象的属性用this
this.gender=gender1;
}
2.通过原型扩展构造函数功能:把函数变成对象的方法(用prototype)
Person.prototype.eat=function(){
console.log('姓名:'+this.name+'性 别:'+this.gender)
}
3.创建实例化对象,通过new
var man=new Person('奎哥','男');
调用方法:
man.eat();
man.say();
1.通过原型实现继承方法:
//构造函数名.prototype=new 构造函数名();
Son.prototype=new Person(); //建立继承关系
var son1=new Son(); //实例化子类
2.通过call或aplly改变this指向实现继承-常用
function Son(){
this.gender='男';
this.hobby='玩';
this.say=function(){
console.log('说话')
}
Person.call(this); //在子类里通过call方法改变父类指向,让它指向子类
}
三.思考:将方法写在原型里与将方法写在构造函数里有什么不同
1.把方法写在原型中比写在构造函数中消耗的内存更小,因为在内存中一个类的原型只有一个,而写在类中的方法,实例化的时候会在每个实例中再复制一份,所以消耗的内存更高
所以没有特殊原因,我们一般把属性写到类中,而方法写到原型中
2、构造函数中定义的属性和方法要比原型中定义的属性和方法的优先级高,如果都定义了同名称的属性和方法,构造函数中的将会覆盖原型中的
原型链关系:原型链的形成是真正是靠__proto__
// 构造函数有属性:prototype ,对象有隐式属性:__proto__ ,js中一切又都是对象
console.log(Person.prototype==man.__proto__) //true
console.log(Person.prototype.__proto__==Object.prototype) //true
console.log(Object.prototype.__proto__==null) //true
3.同步,异步,自执行函数,闭包,回调
特点:
1.省个函数名
2.里面的变量也是局部变量
3.形成了封闭的空间,主要是用于隔离作用域。除了局部作用域避免污染,广告,第三方统计需求这种,也是需要自执行的
用法:
1.自执行函数 (函数)()
(function (){
alert('a');
})();
2.第二种写法(function(){}()) -推荐用这种
(function(){
alert('b');
}());
3. 函数有名字也可以:
(function show(){
alert('c');
}());
或者
(function show(){
alert('c');
})();
作用:主要用于隔离作用域,形成封闭空间,互不影响,避免函数重名造成的问题
(function show(){
alert('c');
}());
function show(){
alert('c');
}
show();
8.弹窗,轮播图组件
通用组件封装:页面内某个功能(或相似功能)使用很频繁被多个地方调用( 代码复用的一种形式 )
对象的多种表现形式
提高对象的复用性
初始化:
var d1 = new Dialog();
d1.init({ //配置参数,有配置走配置,没配置走默认
w : 100,
h : 400,
dir : 'right',
title : '公告'
});
一.思考:如何配置参数和默认参数-对外暴露哪些属性:
1.1居中弹窗:
{ //配置参数
w : 300,
h : 300,
dir : 'center',//方向
title : '登录'
}
1.2靠右弹窗:
{ //配置参数
w : 100,
h : 400,
dir : 'right',
title : '公告'
}
提练公有属性:默认参数配置:
function Dialog(){
this.oLogin = null;
this.settings = { //默认参数
w : 300,
h : 300,
dir : 'center',
title : ''
};
}
二.参数如何合并?
Dialog.prototype.init = function( opt ){
//1.把new传入的对象合并到默认参数,如果有冲突就合并,没有就继承默认参数
extend( this.settings , opt );
this.create();
this.fnClose();
};
function extend(obj1,obj2){
for(var attr in obj2){
obj1[attr] = obj2[attr];
}
}
三.弹窗动态创建共用方法create(如何找相同方法):
Dialog.prototype.create = function(){
this.oLogin = document.createElement('div');
this.oLogin.className = 'login';
this.oLogin.innerHTML = '<div class="title"><span>'+ this.settings.title +'</span><span class="close">X</span></div><div class="content"></div>';
document.body.appendChild( this.oLogin );
this.setData();//不同方向方法
};
四.如何设置不同位置方法setData(单独找不同方法)
this.oLogin.style.width = this.settings.w + 'px'; //获取自己宽高
this.oLogin.style.height = this.settings.h + 'px';
if( this.settings.dir == 'center' ){
//居中
}
else if( this.settings.dir == 'right' ){
//居右
}
4.链式运动
链式运动:一个物体运动完,下一个运动开始
1.一个运动里怎么让一个物体同时加多个属性-可传入对象json={width: 400, height: 400}
for(var attr in json) //循环执行json里的值
{
}
2.怎么判断是否有没走完的{}目标值-可加开关进行判断
cur=parseInt(getStyle(obj, attr)) //获取非行间样式
if(cur!=json[attr]) //判断是否有没执行完的目标值-cur是获取对象里的值跟页面上的对象对比
bStop=false;
匀速速度设置:
匀速速度=(对象里的值-当前走了多少的值)/6
var speed=(json[attr]-cur)/6;
最后赋值对象上:
obj.style[attr]=cur+speed+'px';
如何设置回调函数-一个对象走完后,接着另一个对象
if(bStop) // 如果目标值全部都执行完了,执行这一步,清除定时器,
{
clearInterval(obj.timer);
if(fnEnd)fnEnd(); //如果还有传入的目标值继续执行
}
多个物体运动时-清除定时器,要清除自己对象的,否则定时器会累加
obj.timer=setInterval(function(){},30)
clearInterval(obj.timer);
5.数组filter的应用
筛选数据内容思路:
一.根据事件进行筛选
1.获取焦点事件
opt.oninput=function(){
//根据获取内容对比遍历所有数据里名字name,符合的显示-字符串indexOf方法
if(personArr[i].name.indexOf(txt)!=-1)
}
2.点击all事件
$$('span')[2].onclick=function(){
//两种情况:1.输入文本为空时 2.不为空
for(){
//为空时,全部数据渲染
$$('ul li')[i].style.display='block'
//不为空:获取内容对比遍历所有数据里name
}
}
3.点击男,女事件单独写-因为要遍历性别
obj.onclick=function(){
for(){
//为空时
if(txt==undefined){
//筛选性别出来
if(personArr[i].sex.indexOf(sexM)==-1){ }
}
}
//不为空
else{
//名字与性别同时满足才显示
if(personArr[i].name.indexOf(txt)!=-1&&personArr[i].sex.indexOf(sexM)!=-1)
{
$$('ul li')[i].style.display='block'
}
}
点击性别事件根据性别渲染
$("span").on("click", function () {
sexVal = $(this).attr("sex");
//调用共用筛选方法
all()
})
共用筛选方法 all()-传入不同数据,渲染不同视图
function all() {
//根据名字筛选数组
var lastArr = nameFilter(searchVal, personArr);
//在筛选出全部名字基础上,在筛选性别
// console.log(lastArr)
lastArr = sexFilter(sexVal, lastArr)
//调用共用渲染方法,传入不同筛选数据
renderList(lastArr)
}
不同筛选过滤方法-传入不同值
//根据名字筛选数组
function nameFilter(name, arr) {
返回符合姓名条件的新数组
return ele.name.indexOf(name) != -1 ? true : false
}
}
//根据性别筛选数组
function sexFilter(sex, arr) {
返回符合性别条件的新数组
return ele.sex == sex;
}
9.本地存储,cookie
一.本地数据库 webStorage:包含两个 localStorage ,sessionStorage 可把数据存储到本地(浏览器上)
查看: F12-application-找到,localStorage常用些
应用场景:搜索记录,浏览记录,购物车,角标等
注意!!!存储要的是字符串类型
localStorage,sessionStorage,cookie 区别
cookie localStorage sessionStorage
容量 4K 5M
过期 有 没有 浏览器关闭过期
网络 走 不走
兼容 兼容 不兼容 (IE6,7,8)
1.如何存:
localStorage.a=12;
取:
localStorage.a
删除:
delete localStorage.a
-------------------------------
2.第二种用法:
存:
localStorage.setItem('a',12);
用:
localStorage.getItem('a')
删除:
localStorage.removeItem('a');
-------------------------------
localStorage.clear(); 清空所有
读取cookie document.cookie
多个cookie的读取: alex=123; blue=123; jianjian=123; xuxu=123
;空格
cookie如果没有 返回'';
属性名相同会相互覆盖
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。
例如购物网站存储用户曾经浏览过的产品列表,或者门户网站记住用户喜欢选择浏览哪类新闻。 在用户允许的情况下,还可以存储用户的登录信息,使得用户在访问网站时不必每次都键入这些信息?
cookie用法:
其它浏览器打开,文件要放在服务器,火狐中可直接打开
cookie(可在火狐中打开,也能直接读取cookie):
离不开wamp:
必须要有域名,才能用cookie
域名:一个域名值能有一个cookie
cookie不能"跨域"
"跨域"==两个域名的cookie不能共享
做什么?
保存信息
用在哪?
自动登录,记住用户信息(用户名,密码,地址)
大小: 4k左右 4*1024英文 2*1024中文
为什么小?
出现的早
cookie在哪?
浏览器的缓存文件,在用户的电脑上
安全:别存隐私
cookie里面可以有很多条字符:
expires 过期(3天后过期,1小时后,几年)
session 会话结束(浏览器关闭cookie消失)