JavaScript学习 --- 第四周

93 阅读9分钟

插件使用

1、animate.css 动画库 : 提供元素的动画样式

1、打开百度:搜索animate.css 得到网址
	http://www.animate.net.cn/
	https://animate.style/
2、下载animate.css文件
3、引入
4、挑选你喜欢的动画,把class放到那个元素上
5、并且要记得设置上 animation-duration:3s; (执行时长)
6、添加初始效果

2、swiper插件:
专门的一个轮播插件,提供了你HTML/CSS/JS,我们只需要复制。

3、封装一个运动(动画)函数
(1)原代码

btn.onclick=()=>{   
   div.style.background="red";   
   div.style.border="1px solid red";   
  }
  

(2)封装

btn.onclick=()=>{
    move(div,move(div,{
    background:"red";   
    border:"1px solid red";
            })
       }

function move(elem,obj){
        for(var i in obj){
        //对象的底层是哈希数组,要用for in遍历
             div.style[i]=obj[i];
             }
       } 
       

OBJ

1、Object:

  对象 , Array/String/RegExp/Date... 对象具有属性和方法,都是预定义好的,现在我们学习自定义对象 - js是基于原型的面向对象语言

2、面向对象 - 三大特点:封装、继承、多态

1、开发方式:

(1)面向过程:
    过程 - 开始->结束,其实我们一致的开发方式都是面向过程:
    先干什么->再干什么->最后干什么
    
(2)面向对象:
    对象(包括属性和方法),万物皆对象.
    
    假设一个人是一个对象:
    属性:身高、体重、姓名、性别、爱好、智商、情商...   
    方法:吃饭、睡觉、跑步、拉粑粑、打字、上课...
        

为什么要面向对象
现实生活中所有的数据都必须包含在一个事物之中才有意义
何时使用面向对象
以后任何操作都要封装在一个对象之中

2、封装/创建/定义:

1、直接量方式:
var obj={
"属性名":属性值,
...,
"方法名":function(){操作},//可以简化为箭头函数
	...
	}

强调:

1、其实属性名和方法名的""可以不加 - 暂时建议你加上,数据格式JSON,他必须在键上加上""

2、访问对象的属性和方法:
obj.属性名; === obj["属性名"];
obj.方法名( ); === obj["方法名"]();
建议使用.去访问对象的属性和方法,更简单

3、访问到不存在的属性,返回undefined

4、添加新属性/方法
obj.属性名=新值;
obj.方法名=function(){};

5、如果我希望遍历出对象所有的东西,必须使用for in,obj [i] 才能拿到,

6、如果你希望在对象的方法里,使用对象自己的属性,写为this.属性名

2、预定义构造函数方式:
		var obj=new Object();//空对象
		//需要自己后续慢慢添加属性和方法
		obj.属性名=新值;
		obj.方法名=function(){};

以上两个都有一个缺陷:一次只能创建一个对象,适合创建单个元素的时候(第一种方法),第二种方法完全是垃圾,如果你要批量创建多个对象,那么我推荐第三种方法

3、自定义构造函数方式:
1、创建

function 类名(name,age,hobby){
        this.name=name;
        this.age=age;
        this.hobby=hobby;
}
          //千万不要在里面创建方法,每个对象都会创建出一个相同的方法
            //浪费内存 - 学习继承后可以解决

2、调用
        var obj=new 类名(实参,...);
 

面向对象
优点:
1、更符合现实更有意义 - 所有的属性和方法都保存在一个对象之中
2、便于维护 - 每个功能分开写
3、铁锁链舟 - 一个方法触发多个方法联动

2、继承:

父对象的成员(属性和方法),子对象可以直接使用

为什么要继承:
代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!

何时继承:
只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中

1、如何找到原型对象(父对象):保存了一类子对象共有属性和共有方法
1、对象名.__proto__; 
    //必须先有一个对象
    
2、构造函数名.prototype;
    //构造函数名几乎人人都有,除了Math和Window,new 构造函数名();
    //Array、String、Date、RegExp...
    
3、有了原型对象,可以设置共有属性和共有方法
		(1)、原型对象.属性名=属性值;
		(2)、原型对象.方法名=function(){}

继承 -- 面试笔试题:

1、判断是自有还是共有:

1、判断自有:
    obj.hasOwnProperty("属性名");
    //如果结果为true,说明是自有属性
    //如果结果为false,有两种可能,说明可能是共有,也可能是没有
2、判断共有:
        
        //in关键字,会自动查找整条原型链上的属性,
        //找到了结果为true
        //找不到结果为false
        if ( obj . hasOwnProperty("属性名") == false && "属性名" in obj ){
			共有				
		}else{
			没有
		}
3、整合:
完整公式:
		if(obj.hasOwnProperty("属性名")){
                                自有
			}
                            else{
                                if ("属性名" in obj){
                                            共有
				}
                                else{
                                            没有
                                    }
                        }

2、修改和删除:自有和共有

1、自有:
		修改:obj.属性名=新属性值;
		删除:delete obj.属性名;
2、共有:
		修改:原型对象.属性名=新属性值;
                    //千万不要觉得,自己能拿到,就能直接修改,这样很危险,并没有修改原型的东西,而是在本地添加了一个同名属性
		删除:delete 原型对象.属性名;
                    //如果你对着本地直接删除,那么此操作直接无效

3、*如何为老IE的数组添加indexOf方法:-

这道题不是固定的:可能问如何为一类人创建某个方法

if ( Array.prototype.indexOf === undefined ){
                        //判断老IE
        Array.prototype.indexOf=function(key,starti){
			starti === undefined&&(starti=0);
			for ( var i=starti; i<this.length; i++){
					if ( this[i]===key){
						return i;
                                                    }
                                               }
                           return -1;
			}
		}
		var arr1=[1,2,3,4,5];
		var arr2=[2,4,6,8,10];

4、*如何判断x是不是一个数组:4种方法

typeof ( )
只能检查原始类型,不能检查引用类型,如果检查引用类型得到的结果都是一个object。

1、判断x是否继承自 Array . prototype:
		Array.prototype.isPrototypeOf(x);
		// true -> 是数组
                // false -> 不是数组
	
2、判断x是不是由Array这个构造函数创建的
		x instanceof Array;
		结果为true,说明是数组,结果为false,说明不是数组

3Array . isArray(x); - ES5新增的方法,只有数组可以这么使用
		结果为true,说明是数组,结果为false,说明不是数组

4、*输出【对象的字符串】形式
	在Object的原型上保存着最原始的toString方法
	原始的toString输出形式:[object 构造函数名]
        判断的固定套路:
	Object.prototype.toString.call(x)==="[object Array]"
            

多态:

    子对象觉得父对象的成员不好用,就在本地定义了同名函数,覆盖了父对象的成员
    不严格定义:同一个方法,不同的人使用,效果不同,有多种形态
	

5、实现自定义继承:
	1、两个对象之间设置继承
                        子对象.__proto__=父对象

	2、多个对象之间设置继承
                        构造函数名.prototype=父对象;
                        //注意代码执行顺序,应该在开始创建对象之前就设置好继承关系
                        
6class关键字:简化面向对象(封装、继承、多态)
        class 子类 extends 父类{
	constructor(name,age,hobby,...){
             //放在constructor里面的都是自有属性
		super(name,age);
		this.hobby=hobby;
	}
       //放在constructor外面的都是共有方法
	//还会继承到老类所有的API,也可以添加新的
}

3、闭包

作用域:2种

1、全局:随处可用,可以反复使用,缺点:容易被污染

2、函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,是会自动释放的

函数的执行原理:

	1、程序加载时
		创建执行环境栈(ECS):保存函数调用顺序的数组
		首先压入全局执行环境(全局EC)
		全局EC引用着全局对象window
		window中保存着我们全局变量

	2、定义函数时
		创建函数对象:封装代码段
		在函数对象之中有一个scope(作用域)属性:记录着函数来自己的作用域是哪里
		全局函数的scope都是window

	3、调用前
		在执行环境栈(ECS)压入新的EC(函数的EC)
		创建出活动对象(AO):保存着本次函数调用时用到的局部变量
		在函数的EC中有一个scope chain(作用域链)属性引用着AO
		AO有一个parent属性是函数的scope引用着的对象

	4、调用时:
		正是因为有前面三步,才来带变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错

	5、调用完:
		函数的EC会出栈,没人引用AO,AO自动释放,局部变量也就释放了

闭包作用:

希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

(1)何时使用:希望保护一个可以【反复使用的局部变量】的时候

(2)如何使用:
1、两个函数进行嵌套
2、外层函数创建出受保护的变量
3、外层函数return出内层函数
4、内层函数再操作受保护的变量

(3)强调:
1、判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量

(4)缺点:
受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏 - 不可多用

(5)使用场景:

三个事件需要防抖节流 - 共同点:触发的速度飞快
  • 1、elem.onmousemove - 鼠标移动事件
  • 2、input.oninput - 每次输入/改变都会触发
  • 3、onresize - 每次窗口改变大小都会触发
防抖节流的公式:
function fdjl () {
var timer = null;
return function ( ) {
	if ( timer !== null){
            clearTimeout(timer);
            timer = null;
            }
	
            timer=setTimeout(()=>{
				操作
				},500)
			}
		}
		
var inner=fdjl( );

elem.on事件名=function(){
			inner();
		}

两链一包:

1、作用域链:

  以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链
作用 : 查找变量
带来了变量的使用规则 :
优先使用自己的,自己没有找全局,全局没有就报错

2、原型链:

  每个对象都有一个属性叫做.__proto__,可以一层一层的找到每个对象的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做原型链

作用:查找属性和方法,哪怕自己没有也会顺着原型链向上找,怪不得人人都能用toString(),因为他在最顶层

3、闭包:

  希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
作用:专门用于防抖节流