无缝轮播
思路:
- 始终只有一张图,点左边按钮和右边按钮,默认图片出现的位置是不一样的
- 始做做着一件事:第一张在离开,第二张在进来,动画完毕后,要删除第一张
- 图片的加载速度比JS的执行速度慢,所以想要动画还是需要搭配onload事件
- 小圆点要区分左右,要得到新的计数器和老的计数器进行比较
Object对象
面向对象:三大特点:封装、继承、多态
何时使用面向对象:以后任何操作都要封装在一个对象之中 - 但是新手并不是太友好,难度较大
为什么要面向对象:现实生活中所有的数据都必须要包含在一个事物之中才有意义 - 更符合现实生活
封装/创建/定义:封装自定义对象:3种
-
直接量方式: var obj{
"属性名":属性值,
...,
"方法名":function(){操作},
...
}
强调:- 其实属性名和方法名的""可以不加 -建议还是加上,以后要学习一个数据格式叫JSON,它的键就必须加上""
- 访问对象的属性和方法
对象名.属性名;===对象名["属性名"];
对象名.方法名();===对象名"方法名";
建议使用.去访问对象的属性和方法,更简单,
js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组 - 访问到不存在的属性,返回undefined
- 可以随时随地的添加新属性和新方法
obj.属性名=属性值;
obj.方法名=function(){} - 如果我希望遍历出对象所有的东西,必须使用for in循环,必须写为obj[i]才能拿到,不要使用.会得到undefined
- 如果你希望在对象的方法里,使用对象自己的属性,必须写为this.属性名!
this的指向- 单个元素绑定事件this->这个元素
- 多个元素绑定事件this->当前元素
- 定时器中this->window
- 箭头函数this->外部对象
- 函数中的this->谁在调用此方法,this就是谁
- 自定义构造函数的this->当前正在创建的对象
-
预定义构造函数方式
var obj=new Object();//空对象 //需要自己后续慢慢的添加属性和方法 obj.属性名=属性值; obj。方法名=function(){}- 自定义构造函数方式:2种
- 创建自定义构造函数
function 类名(name,age,hobby){
this.name=name;
this.age=age;
this.hobby=hobby;
} - 调用构造函数创建对象:
var obj=new 类名(实参,...) 面向对象:
优点:
- 所有的属性和方法都保存在一个对象之中
- 每个功能特地得分开写 - 便于以后维护
- 铁锁链舟 - 一个方法触发,多个方法联动
- 创建自定义构造函数
- 自定义构造函数方式:2种
-
继承:父对象的成员(属性和方法),子对象可以直接使用
-
如何找到原型对象(父对象):保存一类子对象的共有属性和共有方法
- 对象名.proto;//必须要先有一个对象
- 构造函数名.prototype;//构造函数几乎人人都有 - 除了Math和Window
-
有了原型对象,可以设置共有属性和共有方法
- 原型对象.属性名=属性值;
- 原型对象.方法名=function(){};
-
判断是自有还是共有
- 判断自有:boj.hasOwnProperty("属性名");结果为true,则为自有,如果为false,则可能是共有,也可能没有这个属性
- 判断共有:if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in关键字,会自动查找整条原型链上的属性,找到了结果就为true,没找到结果就为false
完整公式:
if(obj.hasOwnProperty("属性名")){
console.log("自有");
}else{
if("属性名"in obj){
console.log("共有");
}else{
console.log("没有");
}
}
-
修改和删除:自有和共有
- 自有:
修改:obj.属性名=新值;
删除:delete obj.属性名; - 共有:
修改:原型.属性名=新值;
删除:delete 原型.属性名;
- 自有:
-
-
如何判断x是不是一个数组:4种 - 千万不要用typeof,只能检查原始类型,不能检查引用类型,如果检查引用类型会得到是一个object
-
判断x是不是继承自Array.prototype
Array.prototype.isPrototypeOf(x);ture为数组,false则不是 -
判断x是不是由Array这个构造函数创建的
X instanceof Array;ture为数组,false则不是 -
Array.isArray(x) - ES5提供的:老IE不支持,只有数组有此操作结果为true,说明是数组,结果为false,说明不是数组
-
输出【对象的字符串】形式 在Object的原型上保存着最原始的toString();
5.多态:子对象觉得父对象的成员不好用,就在本地定义了一个同名函数,覆盖了父对象的成员,不严格的定义:同一个函数,不同的人来使用,表现出来的效果是不一样的,有多种形态
借用的固定套路:Object.prototype.toString.call/apply(x)==="[object Array]";
-
-
实现自定义继承:
- 俩个对象之间设置继承
子对象.proto=父对象 - 批量设置继承:
构造函数名.prototype=父对象
注意时机:应该在创建对象之前设置好继承关系
- 俩个对象之间设置继承
ES6-class关键字:简化面向对象
class 类名 extends 老类{
constructor(name,speed,rl){//写在constructor里面的其实就是自有属性
super(name,speed);
this.rl=rl;
}
}
3. Ffunction:作用域链&闭包
-
作用域:2种
- 全局:随处可用,可以反复使用,缺点:容易被污染
- 函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,使用完就会自动释放
-
函数的执行原理:
- 程序加载时:创建执行环境栈(ECS):保存函数调用顺序的数组首先压入全局执行环境(全局EC)全局EC引用着全局对象windowwindow中保存着我们的全局变量
- 定义函数时:创建函数对象:封装代码段在函数对象中有一个scope(作用域)的属性:记录着函数来自的作用域是哪里全局函数的scope都是window
- 用前:在执行环境栈(ECS)中压入新的EC(函数的EC)创建出活动对象(AO):保存着本此函数调用时用到的局部变量在函数的EC中有一个scope chain(作用域链)属性引用着AOAO还有parent属性是函数的scope引用着的对象
- 调用时:正是因为有了前三部,才带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
- 函数的EC会出栈,没人引用着AO,AO自动释放,局部变量也就释放了
-
闭包::希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
- 如何使用
- 两个函数进行嵌套
- 外层函数创建出受保护的变量
- 外层函数return出内层函数
- 内层函数操作受保护的变量
- 强调
- 判断是不是闭包,有没有两个函数进行嵌套,返回内层函数,内层函数再操作受保护的变量
- 外层函数调用几次,就创建了几个闭包,受保护的变量就有了几个副本
- 同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
- 缺点:受保护的变量,永远不会被释放,使用过多,会导致内存泄漏 - 闪退,不可多用
- 如何使用
-
闭包的使用场景:防抖节流
- 5个事件需要防抖节流 - 共同:触发的很快,但是我们不需要很快的修改DOM树
- elem.onmousemove;
- input.oninput;
- elem.onclick;
- window.onscroll;
- window.onresize;
- 固定公式:
function fdjl(){
var timer=null;
return function(){
if(timer!=null){clearTimeout(timer)}
timer=setTimeout(()=>{
操作
},1000)
}
}
- 5个事件需要防抖节流 - 共同:触发的很快,但是我们不需要很快的修改DOM树
ES5-保护对象:保护对象的属性和方法
-
对象的每个属性都具有四大特性:
- value: 155521, //实际保存值的地方
- writable: true, //开关,控制着这个属性是否可以被修改 - 默认值为true
- enumerable: true, //开关,控制着这个属性是否可以被for in循环遍历到 - 默认值为true
- configurable: true//开关,控制着这个属性是否可以被删除 - 默认值为true
-
修改四大属性
- Object.defineProperty(对象名,"属性名",{
writable: true/false,
enumerable: true/false,
configurable: true/false
}) - Object.defineProperties(对象名,{
"属性名":{
四大特性
},
...
})
- Object.defineProperty(对象名,"属性名",{
-
三个级别:
- 防扩展:防添加Object.preventExtensions(x);
- 密封:防添加和防删除Object.seal(x);
- 冻结:防添加和防删除和防修改Object.freeze(x);
四大特性,其实应该叫六大特性 - 可以帮助我们做出动态数据,以后不会手动使用,只是明白Vue底层就是用了
Object.defineProperty(对象名,"属性名",{
get:()=>{
console.log("获取数据会进行拦截")
},
set:(v)=>{
//v就是你设置的东西
console.log("设置数据会进行拦截")
}
})
对象的深拷贝和浅拷贝
-
浅拷贝:利用按值传递
var obj1={"name":"obj1"};
var obj2=obj1;
obj2.name="obj2"; -
深拷贝:俩者互不影响
var obj1={"name":"obj1"};
var obj2={...obj1};
obj2.name="obj2"; -
深拷贝的另一种方式
如何处理后端传来的数据
后端穿衣服:var jsonTxt=JSON.stringify(jsonObj) - Node.js就是这句话,Node.js也是"js",历史上第一次一门语言可以通吃前后端,后端不能直接穿数据,必须穿上衣服才能出门,变成一个JSON字符串
前端脱衣服:var jsonObj=JSON.parse(jsonTxt); 或者 eval("("+jsonTxt+")")
此方法也可以实现深拷贝
Error对象:错误
- 学习是为了快速的找到自己的错误
- 浏览器自带4种错误类型
- 语法错误:SyntaxError - 一定是符号/语法写错了
- 引用错误:ReferenceError - 没有创建就去使用了
- 类型错误:TypeError - 不是你的API,你却去使用了,最有可能的就是你拿到了undefined和null
- 范围错误:RangeError - 只有API会遇到:num.toFixed(d);//d取值范围:0~100之间
- 只要发生错误,就会报错,会导致后续代码终止或是浏览器闪退
- 错误处理:就算发生错误也不希望报错,而是给一个错误提示,让后续代码继续运行
- 语法:
try{
只放入你可能出错的代码
}catch(err){
发生错误后才会执行的代码
err - err形参会报错到错误消息,但是不是报错,只是一个黑色的错误消息
性能太差,可以直接用if...else替代,
- 自定义错误:只要是错误,就会导致后续代码不运行 throw new Errop("自定义错误消息");
- 严格模式:根本不用,看见了直接删除
开启:"use strict"
作用:
- 禁止了全局污染,必须先创建再使用
- 将静默失败升级为报错
- 柯里化函数: function add(a){ return function(b){ return function(c){ console.log(a+b+c); } } } add(3)(5)(7)