学习Java Script的第四周

87 阅读9分钟

无缝轮播

思路:

  1. 始终只有一张图,点左边按钮和右边按钮,默认图片出现的位置是不一样的
  2. 始做做着一件事:第一张在离开,第二张在进来,动画完毕后,要删除第一张
  3. 图片的加载速度比JS的执行速度慢,所以想要动画还是需要搭配onload事件
  4. 小圆点要区分左右,要得到新的计数器和老的计数器进行比较

Object对象

面向对象:三大特点:封装、继承、多态
何时使用面向对象:以后任何操作都要封装在一个对象之中 - 但是新手并不是太友好,难度较大
为什么要面向对象:现实生活中所有的数据都必须要包含在一个事物之中才有意义 - 更符合现实生活

封装/创建/定义:封装自定义对象:3种

  1. 直接量方式: var obj{
    "属性名":属性值,
    ...,
    "方法名":function(){操作},
    ...
    }
    强调:

    1. 其实属性名和方法名的""可以不加 -建议还是加上,以后要学习一个数据格式叫JSON,它的键就必须加上""
    2. 访问对象的属性和方法
      对象名.属性名;===对象名["属性名"];
      对象名.方法名();===对象名"方法名";
      建议使用.去访问对象的属性和方法,更简单,
      js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组
    3. 访问到不存在的属性,返回undefined
    4. 可以随时随地的添加新属性和新方法
      obj.属性名=属性值;
      obj.方法名=function(){}
    5. 如果我希望遍历出对象所有的东西,必须使用for in循环,必须写为obj[i]才能拿到,不要使用.会得到undefined
    6. 如果你希望在对象的方法里,使用对象自己的属性,必须写为this.属性名!
      this的指向
      1. 单个元素绑定事件this->这个元素
      2. 多个元素绑定事件this->当前元素
      3. 定时器中this->window
      4. 箭头函数this->外部对象
      5. 函数中的this->谁在调用此方法,this就是谁
      6. 自定义构造函数的this->当前正在创建的对象
  2. 预定义构造函数方式
    var obj=new Object();//空对象 //需要自己后续慢慢的添加属性和方法 obj.属性名=属性值; obj。方法名=function(){}

    1. 自定义构造函数方式:2种
      1. 创建自定义构造函数
        function 类名(name,age,hobby){
        this.name=name;
        this.age=age;
        this.hobby=hobby;
        }
      2. 调用构造函数创建对象:
        var obj=new 类名(实参,...) 面向对象:
        优点:
        1. 所有的属性和方法都保存在一个对象之中
        2. 每个功能特地得分开写 - 便于以后维护
        3. 铁锁链舟 - 一个方法触发,多个方法联动
  3. 继承:父对象的成员(属性和方法),子对象可以直接使用

    1. 如何找到原型对象(父对象):保存一类子对象的共有属性和共有方法

      1. 对象名.proto;//必须要先有一个对象
      2. 构造函数名.prototype;//构造函数几乎人人都有 - 除了Math和Window
    2. 有了原型对象,可以设置共有属性和共有方法

      1. 原型对象.属性名=属性值;
      2. 原型对象.方法名=function(){};
    3. 判断是自有还是共有

      1. 判断自有:boj.hasOwnProperty("属性名");结果为true,则为自有,如果为false,则可能是共有,也可能没有这个属性
      2. 判断共有:if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in关键字,会自动查找整条原型链上的属性,找到了结果就为true,没找到结果就为false
        完整公式:
        if(obj.hasOwnProperty("属性名")){
        console.log("自有");
        }else{
        if("属性名"in obj){
        console.log("共有");
        }else{
        console.log("没有");
        }
        }
    4. 修改和删除:自有和共有

      1. 自有:
        修改:obj.属性名=新值;
        删除:delete obj.属性名;
      2. 共有:
        修改:原型.属性名=新值;
        删除:delete 原型.属性名;
  4. 如何判断x是不是一个数组:4种 - 千万不要用typeof,只能检查原始类型,不能检查引用类型,如果检查引用类型会得到是一个object

    1. 判断x是不是继承自Array.prototype
      Array.prototype.isPrototypeOf(x);ture为数组,false则不是

    2. 判断x是不是由Array这个构造函数创建的
      X instanceof Array;ture为数组,false则不是

    3. Array.isArray(x) - ES5提供的:老IE不支持,只有数组有此操作结果为true,说明是数组,结果为false,说明不是数组

    4. 输出【对象的字符串】形式 在Object的原型上保存着最原始的toString();
      5.多态:子对象觉得父对象的成员不好用,就在本地定义了一个同名函数,覆盖了父对象的成员,不严格的定义:同一个函数,不同的人来使用,表现出来的效果是不一样的,有多种形态
      借用的固定套路:Object.prototype.toString.call/apply(x)==="[object Array]";

  5. 实现自定义继承:

    1. 俩个对象之间设置继承
      子对象.proto=父对象
    2. 批量设置继承: 构造函数名.prototype=父对象
      注意时机:应该在创建对象之前设置好继承关系

ES6-class关键字:简化面向对象

class 类名 extends 老类{
constructor(name,speed,rl){//写在constructor里面的其实就是自有属性
super(name,speed);
this.rl=rl;
}
}

3. Ffunction:作用域链&闭包

  1. 作用域:2种

    1. 全局:随处可用,可以反复使用,缺点:容易被污染
    2. 函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,使用完就会自动释放
  2. 函数的执行原理:

    1. 程序加载时:创建执行环境栈(ECS):保存函数调用顺序的数组首先压入全局执行环境(全局EC)全局EC引用着全局对象windowwindow中保存着我们的全局变量
    2. 定义函数时:创建函数对象:封装代码段在函数对象中有一个scope(作用域)的属性:记录着函数来自的作用域是哪里全局函数的scope都是window
    3. 用前:在执行环境栈(ECS)中压入新的EC(函数的EC)创建出活动对象(AO):保存着本此函数调用时用到的局部变量在函数的EC中有一个scope chain(作用域链)属性引用着AOAO还有parent属性是函数的scope引用着的对象
    4. 调用时:正是因为有了前三部,才带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
    5. 函数的EC会出栈,没人引用着AO,AO自动释放,局部变量也就释放了
  3. 闭包::希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

    1. 如何使用
      1. 两个函数进行嵌套
      2. 外层函数创建出受保护的变量
      3. 外层函数return出内层函数
      4. 内层函数操作受保护的变量
    2. 强调
      1. 判断是不是闭包,有没有两个函数进行嵌套,返回内层函数,内层函数再操作受保护的变量
      2. 外层函数调用几次,就创建了几个闭包,受保护的变量就有了几个副本
      3. 同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
    3. 缺点:受保护的变量,永远不会被释放,使用过多,会导致内存泄漏 - 闪退,不可多用
  4. 闭包的使用场景:防抖节流

    1. 5个事件需要防抖节流 - 共同:触发的很快,但是我们不需要很快的修改DOM树
      1. elem.onmousemove;
      2. input.oninput;
      3. elem.onclick;
      4. window.onscroll;
      5. window.onresize;
    2. 固定公式: function fdjl(){
      var timer=null;
      return function(){
      if(timer!=null){clearTimeout(timer)}
      timer=setTimeout(()=>{
      操作
      },1000)
      }
      }

ES5-保护对象:保护对象的属性和方法

  1. 对象的每个属性都具有四大特性:

    1. value: 155521, //实际保存值的地方
    2. writable: true, //开关,控制着这个属性是否可以被修改 - 默认值为true
    3. enumerable: true, //开关,控制着这个属性是否可以被for in循环遍历到 - 默认值为true
    4. configurable: true//开关,控制着这个属性是否可以被删除 - 默认值为true
  2. 修改四大属性

    1. Object.defineProperty(对象名,"属性名",{
      writable: true/false,
      enumerable: true/false,
      configurable: true/false
      })
    2. Object.defineProperties(对象名,{
      "属性名":{
      四大特性
      },
      ...
      })
  3. 三个级别:

    1. 防扩展:防添加Object.preventExtensions(x);
    2. 密封:防添加和防删除Object.seal(x);
    3. 冻结:防添加和防删除和防修改Object.freeze(x);

四大特性,其实应该叫六大特性 - 可以帮助我们做出动态数据,以后不会手动使用,只是明白Vue底层就是用了

Object.defineProperty(对象名,"属性名",{
get:()=>{
console.log("获取数据会进行拦截")
},
set:(v)=>{
//v就是你设置的东西
console.log("设置数据会进行拦截")
}
})

对象的深拷贝和浅拷贝

  1. 浅拷贝:利用按值传递
    var obj1={"name":"obj1"};
    var obj2=obj1;
    obj2.name="obj2";

  2. 深拷贝:俩者互不影响
    var obj1={"name":"obj1"};
    var obj2={...obj1};
    obj2.name="obj2";

  3. 深拷贝的另一种方式
    如何处理后端传来的数据
    后端穿衣服:var jsonTxt=JSON.stringify(jsonObj) - Node.js就是这句话,Node.js也是"js",历史上第一次一门语言可以通吃前后端,后端不能直接穿数据,必须穿上衣服才能出门,变成一个JSON字符串
    前端脱衣服:var jsonObj=JSON.parse(jsonTxt); 或者 eval("("+jsonTxt+")")
    此方法也可以实现深拷贝

Error对象:错误

  1. 学习是为了快速的找到自己的错误
  2. 浏览器自带4种错误类型
    1. 语法错误:SyntaxError - 一定是符号/语法写错了
    2. 引用错误:ReferenceError - 没有创建就去使用了
    3. 类型错误:TypeError - 不是你的API,你却去使用了,最有可能的就是你拿到了undefined和null
    4. 范围错误:RangeError - 只有API会遇到:num.toFixed(d);//d取值范围:0~100之间
  3. 只要发生错误,就会报错,会导致后续代码终止或是浏览器闪退
    1. 错误处理:就算发生错误也不希望报错,而是给一个错误提示,让后续代码继续运行
    2. 语法:
      try{
      只放入你可能出错的代码
      }catch(err){
      发生错误后才会执行的代码
      err - err形参会报错到错误消息,但是不是报错,只是一个黑色的错误消息
      性能太差,可以直接用if...else替代,
  4. 自定义错误:只要是错误,就会导致后续代码不运行 throw new Errop("自定义错误消息");
  5. 严格模式:根本不用,看见了直接删除 开启:"use strict" 作用:
    1. 禁止了全局污染,必须先创建再使用
    2. 将静默失败升级为报错
  6. 柯里化函数: function add(a){ return function(b){ return function(c){ console.log(a+b+c); } } } add(3)(5)(7)