js-----1.2

149 阅读20分钟

*****function

    作用域:21.全局:随时可用可以被反复使用.缺点,容易被污染
        2.函数:只能在函数内部调用时使用,不会被污染,缺点:一次性的,是会自动释放
    ***函数的执行原理:
        1.程序加载时:
        创建执行环境栈(ECS):保存函数顺序的数组
        首先压入全局执行环境(ECS)
        全局EC引用着全局window
        window中保存着全局变量和全局函数
        
        2.定义函数时
        创建出函数对象:封装代码段
        在函数对象中有一个scope(作用域)属性:记录着此函数来自的作用域是哪里
        全局函数scope都是window
        
        3.调用前
        在执行环境栈(ECS)压入新的EC(函数的EC)
        创建活动对象(AO):保存着本次函数调用时用到局部变量
        在函数的EC中有一个scope chain(作用域链),属性引用着AO
        AO有一个parent属性是函数的scope引用着的对象
        
        4.调用时:正是因为前面三步,我们才有了变量的使用规则:优先使用局部,局部没有找全局,全局没有就报错
        
        5.调用完时:函数的EC会出栈,AO自动释放,局部变量也就会自动释放了
        
    ***两链一包
        作用域链:以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成一条链式结构
        作用:查找变量,带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错.
        
  ***闭包:我们发现全局和函数都有缺点,希望保护一个[可以反复使用的局部变量]的一种语法结构,--其实还是函数
  何时使用:希望保护一个[可以反复使用的局部变量]的时候
  如何使用:
      1.两个函数进行嵌套
      2.外层函数创建出受保护的变量
      3.外层函数要return出内层函数
      4.内层函数要去操作受保护的变量
  语法:
      function f1(){
              创建受保护的变量
              return function(){
                  操作受保护的变量
              }
      }
  强调:
      1.判断是不是闭包,有没有两个函数嵌套,返回内层函数,内层函数在操作受保护的变量
      2.外层函数调用几次,就会创建几个闭包,受保护的变量就有了几个副本
      3.同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
  
  缺点:受保护的变量永远不会被释放,使用过多,会导致内层泄露---不可多用
  问题:应该在哪里用呢?---防抖节流
      1.三个事件需要防抖节流
          (1)elem.onmousemove--鼠标移动事件
          (2)input.oninput----每次输出改变都会触发
          (3)window.onresize----每次窗口的大小发生变化就会触发
          
          公式:
          
          function AST(){
            var timer=null
            return function(){
             if(timer){clearTimeout(timer);timer=null}关闭之前的定时器
             timer=setTimeout(function(){--开启定时器,等一秒才执行
                     //书写操作
             },1000)
              }
          }
          
          var result=AST();

******Object对象:Array,Function,RegExp,String....对象具有书写和方法,都是预定义好的,现在学会自定义对象

   面向对象:三大特点:封装,继承多态
       1.****开发方式:面向对象和面向过程
           1.面向过程:经过:开始-->结束,我们一直以为的开发方式就是面向过程,先干什么在干什么最后干什么
           2.面向对象:对象(属性和方法),js有一句话,万物皆对象,假设一个人是一个对象的话
                       属性:姓名,身高,体重,性别
                       方法:吃饭睡觉...
           为什么要面向对象:显示生活中所有的数据都必须包含在一个事务中才有意义
           何时使用面向对象:以后做任何操作都要封装在一个对象当中
      2.封装:创建自定义对象:31.*直接量方式:适合创建单个对象
              var obj={
                  "属性名":属性值
                  ....
                  "方法名":function(){}
                  ....
              }
          强调:1.其实属性名和方法名的双引号可以省略不写,暂时建议加上,为了以后学习jaso的数据格式
              2.访问对象的属性和方法:
                  *obj.属性名;     ====   obj["属性名"]
                  *obj.方法名();   ====   obj["方法名"]();
                  建议使用前面的方式-->更简单
              3.访问到不存在的属性放回undefined
              4.可以随时随地的添加新属性和新方法
              5.希望获取出对象的所有东西,for in , obj[i]才能拿到
              6.***如果你希望在对象的方法里使用对象自己的属性,
                写为this.属性名
                ******难点:this的指向
                    1.单个元素绑定事件-->this指定这个元素
                    2.多个元素绑定事件-->this指定当前触发事件的元素
                    3.函数中的this-->谁在调用此方法,this就是谁
                    4.定时器中的this-->指定的是window
                    5.箭头函数中的this--->指的的外部对象
                    6.构造函数中的this-->指当前正在创建的对象
                    
       2.预定义函数构造方式:
           var obj=new Object();--->空对象---垃圾
           需要后续自己慢慢追加属性和方法
           obj.属性名=属性值;
           obj.方法名=function(){};
           
   以上两个方法都有缺陷:一次只能创建一个对象
   
      3.自定义构造函数方式:21.创建自定义构造函数
              function 类名(name,age,salary){
                  this.name=name;
                  this.age=age;
                  thia.salary=salary;
              }
          2.调用构造函数创建出的对象
              var obj=new 类名(实参....)
              
    面向对象:
        优点:1、逼格高,所有的属性和方法都保存在了一个对象之中 - 更符合现实,更有意义
            2、每个功能特地分开书写,越细越好 - 便于维护
            3、铁索连舟 - 一个方法触发多个方法联动
        缺点:缺点:对新手不友好,this的指向非常恶心
          

2022.4.19

*****Object:三大特点

    *****继承:
        1.*****父对象的成员(属性和方法),子对象可以直接使用
            为什么:代码重用,节约内存空间,提升网站性能
        何时继承:只要多个子对象共用的属性和[方法],都要几种定义在父对象中
        2.*****如何找到父对象(原型对象),:保存一类子对象共有属性和共有方法的父对象
            1.对象名.__proto__;//必须先有一个对象
            2.构造函数名.prototype;//构造函数名:Array/Object/String/Number/Boolean/RegExp/Date...几乎人人都有,除了Math
        3.面试题:两链一包:作用域链(查找变量),原型链(查找属性和方法),闭包(保护一个可以反复使用的局部变量),
        每个对象都有一个属性,.__proto__;可以一层一层的找到每一个人的父亲,形成一条链式结构,我们就称之为原型链.
        可以找到所有父对象的成员(属性和方法),作用:查找共有属性和共有方法
        最顶层的是Object的原型,上面放着我们很眼熟的toString方法,怪不得人人都可以使用
        js万物皆对象
        4.有了原型对象设置共有的属性和方法
        原型对象.属性名=属性值
	原型对象.方法名=function(){};
***继承具有非常多的鄙视题:
        1、判断是自有还是共有:
	1、判断自有:obj.hasOwnProperty("属性名");
	如果为true,说明是自有,如果为false,可能是没有或共有
	2、判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj) {//in关键字会查找整条原型链
        共有
}else{
	没有
}

完整版:
	if(obj.hasOwnProperty("属性名")){
			自有
	}else{
                if("属性名" in obj){
			共有
	}else{
			没有
	}
}
		
2、修改&删除:自有和共有
自有:修改:obj.属性名=新值;
删除:delete obj.属性名;

共有:修改:原型对象.属性名=新值; - 千万不要直接在本地做操作,非常危险,添加上一个同名属性
删除:delete 原型对象.属性名; - 如果对本地删除,没有任何效果的

3、如何为老IE的数组添加indexOf方法 - 如何为一类人添加共有方法
		//判断是不是老IE
		if(Array.prototype.indexOf===undefined){
//				//我为数组类添加了一个indexOf方法
//				Array.prototype.indexOf=function(key,starti){
				//原理
				//用户如果没有传入开始位置,则设置为0
//					starti===undefined&&(starti=0);
				//从开始位置处,循环当前数组的每一个元素
//					for(var i=starti;i<this.length;i++){
					//每一个元素和用户传入的关键字进行比较,如果比较到了
//						if(this[i]==key){
						//返回下标
//							return i;
//						}
//					}
				//没找到返回-1
//					return -1;
//				}
//			}

		4、判断x是不是一个数组 - 4种方式
			1、判断x是不是继承自Array.prototype;
				Array.prototype.isPrototypeOf(x);//true说明是一个数组

			2、判断x是不是由Array这个构造函数创建的
				x instanceof Array;//true说明是一个数组

			3Array.isArray(x);//true说明是一个数组,只有数组可以这么判断,ES5提供的一个新方法,老IE都不支持

			4、输出【对象的字符串】形式
				在Object的原型上保存着最古老最原始的toString方法
				原始的toString输出形式:[object 构造函数名]
				***多态:多种形态:子对象觉得父对象的成员不好用,在本地定义了同名成员覆盖了父对象的成员	
				固定套路:借用:Object.prototype.toString.apply(x)
				if(Object.prototype.toString.apply(obj)==="[object Array]"){
					console.log("数组")
				}else{
					console.log("不是数组")
				}

		5、如何实现自定义继承
			1、两个对象之间继承:子对象.__proto__=新父对象
			2、多个对象之间继承:构造函数名.prototype=新父对象
					时机:应该在开始创建对象之前设置好继承关系

2022.4.20

1、ES5:

1、保护对象:保护对象的成员(属性和方法)

  如何保护:
1、四大特性 - 每一个属性或方法都有四大特性
	如何设置四大特性:
		Object.defineProperties(obj,{
			"属性名":{
				value: 实际保存值的地方,
				writable: true/false,//开关:控制着这个属性是否可以被修改
				enumerable: true/false,//开关:控制着这个属性是否可以被for in循环遍历到
				configurable: true/false,//开关:控制着这个属性是否可以被删除
			}
		})

2、三个级别:
	1、防扩展:禁止给对象添加新属性
		Object.preventExtensions(obj);

	2、密封:禁止给对象添加新属性和删除属性
		Object.seal(obj);

	3、冻结:禁止给对象添加新属性和删除属性和修改属性
		Object.freeze(obj);

	其实保护对象对我们程序员并不重要:为什么
		1、如果你用的是面向过程,你保护个屁
		2、别人基本不可能知道我们的对象名叫什么
		3、前辈们都没有保护,你保护个啥

	学习的目的:应付鄙视和面试
2.*****数组的新得API:361.判断:判断的结果一定是一个布尔值
        every:每一个--要求每一个元素都满足,结果才为true,只要有一个不满足结果就为false--类似&&:碰到false就不会在执行后续操作
            语法:arr.every(function(val,i,arr){
                        //val:当前值
                        //i:当前下标
                        //arr:数组本身
                        return 判断条件
            })
        some:有一些:要求每个元素都不满足则为false,只要有一个满足结果则为true---类似于||:碰到true就不会在执行后续操作了
            语法:arr.some(function(val,i,arr){
                        return 判断条件
            })
   2.遍历:将数组中每一个元素取出来执行相同或者相似的操作
       forEach:遍历数组:直接修改原数组
           语法:arr.forEach(function(){
                       直接操作
           })
           
      map:遍历驻足,不修改原数组,返回一个新数组
          语法:var newArry=arr.map(function(){
                      return 操作;
          })
   3.汇总和过滤
       过滤:筛选出自己想要的,但是不会修改原数组
           语法:var newArr=arr.filter(function(){
                       return 判断条件;
           })
       汇总:吧数组中的每一个元素都汇总到一起
           语法:var result=arr.reduce(function(prev,val,i,arr){
                       return prev+val
           })
           
           以上6API的底层都是for循环,目的:简化for循环
           
           

下午

Object.create():希望根据父对象创建子对象,基础自动设置完毕

 语法:var 子对象=Object.create(父对象,{
         "自有属性":{四大特性};
         ...
 })

面试:严格模式

开启:在你的任何作用域的顶部都可以加上这句话:"use strict"
功能:1.禁止给未声明的变量赋值,--解决了全局污染
    2.静默失败升级为错误

*****call/apply/bind:不是自己的方法也可以使用,不管是笔试,面试,实际开发都很常用

call/apply:[临时替换函数中的this]---借用
    语法:函数名.call(借用的对象,实参,....)--单独传入每一个实参
    函数名.apply(借用的对象,[实参,...])--只能传入一个实参,是一个数组但是其实apply也会悄悄的将数组打散
    **强调**call/apply,相当于立刻调用函数,立刻执行
bind:[永久替换了函数中的this]---买
    3件事:
        1.创建了一个和原函数功能相同的新函数
        2.将函数中的this永久绑定固定为了指定的对象别人借不走
        3.将新函数中的参数永久固定
    语法:var 新函数=原函数.bind(指定对象,永久固定参数,..),--不是立即执行需要自己调用
    **强调:bind绑定的新函数是没办法被call/apply借走的
    个人更推荐:call/apply--借,白嫖
    固定套路:
    1.Math.max/min.apply(Math.arr)
    2.Objict.proptotype.toString.call/apply(arr)="[object Array]";
    3.***类数组转为普通数组:
    保存一下=Array.prototype.slice.call/apply(类数组)

ES5其实并没有任何简化操作,只是提供了更多API

2.ES6:简化了语法--变化很大

1.*模板字符串:可以在字符串中放入变量,不需要再做字符串的拼接了,简化了输入法的切换,${}还实现了一个简单的js环境

2.*块级作用域尽量以后创建变量优先使用[let]关键字
    let 变量名=值;
    作用:
        1.禁止了声明提前
        2.添加了块级作用域,一个{}就是一个块
        3.记录着当前触发事件的元素的下标
        
3.***箭头函数:简化回调函数
    公式:去掉function,在()和{}之间添加=>,如果形参只有一个,省略(),如果函数体只有一句话,省略{},如果函数体只有一句话是ruturn,return和{}都省略
    特殊:千万不要将事件也简化为箭头函数--this会失效--暂时
    
4.for of循环---垃圾
    for(var v of arr){
            //v当前元素
    }
    缺点:1.不能够顾修改原数组,只能返回新数组
        2.不支持hash数组,不支持对象
        

2022.4.21

什么是DOM:Document Object Model(文档对象模型)

面试题:HTML/XHTML/DHTML/XML

HTML - 网页
XHTML - 更严格的网页
DHTML - Dynamic:动态的网页,其实并不是新技术、新概念,只是将现有技术的整合统称,使我们网页在离线版也具有动态效果
		DHTML:HTML+CSS+JS(dom)
XML - 数据格式

DOM:原本是可以操作一切结构化文档的HTML和XML,后来为了方便各类开发者分为了三个部分

1、核心DOM:【无敌】,既可以操作HTML 和 XML
	    缺点:API比较繁琐

2HTML DOM:只能操作HTML,API简单,缺点:比如属性部分,只能操作标准属性,不能操作自定义属性

3、XML DOM:只能操作XML,XML基本已经被淘汰了 - 现在最流行的数据格式json代替了

开发建议:优先使用HTML DOM,HTML DOM实现不了的时候在用核心DOM进行补充

2、DOM树:树根:document - 不需要我们创建,一个页面只有一个document:由浏览器的js解释器自动生成

可以通过数个你找到每一个DOM节点/元素/对象,提供了很多很多的API

3.每个DOM元素都有三大属性:

1.xx.nodeType:描述节点的类型
    document节点:0
    元素节点:1
    属性节点:2
    文本节点:3
    以前有用:判断xx是不是一个页面元素 - 因为以前我们找元素的方法和大家现在不一样
2.xx.nodeValue:描述节点值,说白了就是获取属性值
    以前有用:因为我们获取一个属性值没有现在这么容易
3.****nodeName:描述节点名称--判断xx是什么标签--后期搭配上事件委托(利用冒泡)
    **注意:返回的是一个全大写的标签名**

4.*通过关系获取元素

父:xx.parentNode
子:xx.children;--集合
第一个儿子:xx.firstElementchildr;
最后一个儿子:xx.lastElementchildr;
前一个兄弟:xx.previousElementSibling
后一个兄弟:xx.nextElementSibling

5.*****递归:简单来说就是函数中,有一次调用了函数自己,迟早有一天会停止

何时使用:遍历DOM,专门用于遍历[层级不明确的情况]
如何使用递归:2步
function 函数名(root){
        1.第一层要做什么操作就直接做
        2.判断他有没有下一级,如果有下一级再次调用此方法,但是传入的实参是下一级
}
函数名(实际的根节点)

算法:深度优先,优先遍历当前节点的子节点,子节点遍历完才会调到兄弟节点
缺点:同时开启大量的函数调用,消耗内存,只有一个情况下采用[遍历层级不明确]

6.遍历API:[遍历层级不明确的情况].TreeWalker

缺点:1、会自动跳过根节点的操作
      2、只能遍历层级不明确的DOM树,而不能遍历层级不明确的数据
如何:固定公式:
1、创建tw对象:

var tw=document.createTreeWalker(根元素,NodeFilter.SHOW_ALL/SHOW_ELEMENT);

2、反复调用nextNode方法找到没一个元素
	while((node=tw.nextNode())!==null){
		node要做什么操作
	}
            

7、*API直接查找元素

1、按照HTML的特点去查找元素

    1、id:var elem=document.getElementById("id值")
2class/标签名:var elems=document.getElementsByClassName/TagName/Name("class/标签名");
建议:表单控件元素尽量可以不写class,因为必须要写name

2、按照CSS的选择器去查找元素

1、单个元素:var elem=document.querySelector("任意css选择器");
	强调:万一选择器匹配到多个元素,只会返回第一个
	      没找到null

2、多个元素:var elems=document.querySelectorAll("任意css选择器");
	强调:找到了集合,没找到空集合
	更适合做复杂查找

面试题:getXXX 和 querySelectorXXX 有什么区别?
	返回结果不同:
		1、getXXX:HTMLCollection - 是一个动态集合
		2、queryXXX:nodeList - 是一个静态集合

		动态集合:根据DOM树的改变,动态集合也会悄悄改变,每一次修改DOM树,getXXX都会悄悄再次查找元素
		    缺点:每次都会悄悄重新查找,效率较低,不能使用forEach

		静态集合:每次修改DOM树,静态集合都不会发生变化,只会认准你找的时候的第一次找到的元素
		    优点:每次不会悄悄重新查找,效率较高,支持forEach

总结:找元素

1、直接找元素:getXXX、queryXXX

2、通过关系

3、曾经不明确才用递归

2022.4.22

操作元素:

1、元素的内容:3个

1、*innerHTML:获取 和 设置元素的内容,并且识别标签 - 没有兼容性问题,老IE也支持
	获取:elem.innerHTML;	-   往往用于判断
	设置:elem.innerHTML="新内容"	-   添加/修改

2、textContent:获取 和 设置元素的文本,不能识别标签 - 有兼容性问题老IE不支持
	获取:elem.textContent;	-   往往用于判断
	设置:elem.textContent="新文本"	-   添加/修改
	解决:innerText - 小三上位了,此方法本来是属于老IE的,但是现在主流浏览器也支持

3、*value:获取 和 设置input的内容
	获取:input.value;	-   往往用于判断
	设置:input.value="新文本"	-   添加/修改

2、元素的属性:

1、*获取属性值: - 往往用于判断
	核心DOMelem.getAttribute("属性名");	-   虽然API比较繁琐,但是无敌的

	HTML DOMelem.属性名	  -	虽然简单,但是不能操作自定义属性

2、*设置属性值: - 添加/修改
	核心DOMelem.setAttribute("属性名","属性值");	-   虽然API比较繁琐,但是无敌的

	HTML DOMelem.属性名="属性值"	  -	虽然简单,但是不能操作自定义属性

3、删除属性值:
       *核心DOMelem.removeAttribute("属性名") - 完整删除整个属性节点

	HTML DOMelem.属性名=""	  -  删不干净,只能删掉属性值,属性节点依然存在,而有的属性,只需要写出属性名就已经有作用(比如:hrefdisabledreadonly)了

4、判断有没有 - 垃圾
	elem.hasAttribute("属性名"); - 结果是一个布尔值,但是没有用,只能判断有没有,不能判断具体属性值是什么
	真正推荐判断,你还是使用获取属性值

建议:以后优先使用HTML DOMHTML DOM实现不了在用核心DOM补充
	小心:1class要写为className
	      2、不能操作自定义属性

3、元素的样式:

1、内联样式:
	优点:1、优先级高	2、不会牵一发动全身
	获取:elem.style.css属性名;
	设置:elem.style.css属性名="css属性值";

	特殊:1、css属性名,把横线去掉换成小驼峰命名法
	      2、获取也只能获取内联样式 - 小缺点

2、样式表:
	//1、获取你想要操作的样式表
	var sheet=document.styleSheets[i];
	//2、获取所有样式规则
	var rules=sheet.cssRules;
	//3、数出 你需要操作的某个样式规则
	var rule=rules[i];
	//4、对此规则做获取或者设置
	console.log(rule.style.background);
	rule.style.background="purple";

下午

1.创建元素:2步

1.创建空标签:var elem=docunment.createElement("标签名");
    比如:var a=document.createElement("a");
2.添加必要的属性和事件
    elem.属性名="属性值"
    elem.on事件名=function(){操作}
以上两步只是在js中创建了元素,还需要渲染到DOM树上 

2.渲染页面方式

*1.父元素.appendChild(新);//新元素会追加到父元素中当最后一个儿子
 2.父元素.insertBefore(新,已有子元素)://新元素会追加到父元素中当儿子,会插到已有子元素的前面
 3.父元素.replaceChild(新,已有子元素);//新元素会替换到父元素中当儿子,会替换已有子元素
 

3.删除元素:elem.remove();

4.HTML DOM常用对象:HTML DOM就是对核心DOM进行了简化

1.image对象:图片对象
    简化了创建方式:var img=new Image();
    不是人人可以创建简化,只是个别人可以
2.Form对象:表单对象
    简化了查找元素:var form=document.forms[i];//获取页面上的第i个页面元素
    简化了查找表单控件元素:var inp=form.elements[i]//获取此form表单中的第i个表单控件元素
3.*Select对象:
    属性:
    1.select.option等于select.children--获取select下面的所有option
    2.*select.selectedindex;//获取到选中项的下标
    
    方法:
    1.*select.add(option);//将option上树
    2.select.remove(i)//删除下标为i的option
    
    专属事件:onchange--选中项发生改变才会触发

5.option对象:

简化了创建方式:var opt=new Option("innerHTML","value");
建议:以后如果希望创建出opt放在select中,一句话完成四个操作
    select.add(new Option("innerHTML","value"))
    

一阶段常识:

表单控件元素必须添加name,才能传到服务器端
有的表单控件还需要添加value,用户不能输入只能选择的,我们程序员就要提前吧value写好,供用户选择

扩展记忆;

elem.trim() 方法用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。
select的属性:size----size="n";//显示个数,可以让下拉变成滚动
            multiple:可以实现多选
            selected:默认选中项;