创建闭包的四个条件:

1.要有函数嵌套,且里层函数要操作外层函数被保护的变量。

2.返回里层函数

3.里层定义的函数要被调用,哪怕是返回一个匿名函数也行。

4.用一个变量接住,方便后续的使用。

注意:外层函数调用几次就会创建几个闭包。受保护的变量就有几个副本。同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量

 在三个特定事件里可以使用闭包达到节流防抖的作用:分别是onmousemove oninput onresize;

对象的三个特点:封装、继承、多态

1.继承:子对象能够直接使用父对象的属性和方法。

2.如何查找父对象、原型对象:保存子类对象共有属性和共有方法的对象。

对象名.__proto__;//必须先创建一个实例对象
构造函数名.prototype;//通过构造函数名的方式来查找

3.两链一包的概念:作用域链(查找变量)、原型链(查找父对象的方法和属性)、闭包(反复使用一个被保护的局部变量);

4.顶层对象Object的原型对象有toString( )方法,所以是个对象都有这个方法。

5.有了原型对象,就可以设置共有属性和方法了。

原型对象.属性名 = 属性值。

原型对象.方法名 = function(){}

继承过程中的笔试题:

1.判断属性或方法是自有还是共有的?

1.1判断自有:obj.hasOwnProperty( "属性名" );

1.2判断共有:if( obj.hasOwnProperty( "属性名" ) == false && ”属性名“ in obj ){//in关键字会查找整个原型链

共有

}else{

没有

}

2.修改&删除自有或共有

自有的修改:obj.属性名 = 新值;

删除:delete obj.属性名;

共有的修改:原型对象.属性名 = 新值; //千万不要直接在本地做操作,非常危险,添加上一个同名属性

删除:delete 原型对象.属性名; //如果对本地删除,没有任何效果的

    注意:所以这个要用   delete  子对象.__proto__.父对象的属性  这种格式来删除。

3.老IE添加indexOf()方法。

4.判断一个数据类型是不是一个数组。

四种API:
Array.prototype.isPrototypeOf(x); 其他对象也可以如法炮制
x instanceof Array 其他对象也可以如法炮制
Array.isArray(x); 只能用于判断是不是数组
Object.prototype.toString.apply(x)==="[object Array]" 其他对象也可以如法炮制

保护对象

1.四大特性-每一个属性或方法都有四大特性

如何设置四大特性:

Object.defineProperties(obj,{
            "属性名":{
                value: 实际保存值的地方,
                writable: true/false,//开关:控制着这个属性是否可以被修改
                enumerable: true/false,//开关:控制着这个属性是否可以被for in循环遍历到
                configurable: true/false,//开关:控制着这个属性是否可以被删除
            }
})

2.三个级别:

2.1防扩展:禁止给对象添加新属性

Object.preventExtensions( obj );

2.2密闭:禁止给对象添加新属性和删除属性

Object.seal( obj );

2.3冻结:禁止给对象添加新属性和删除属性和修改属性

Object.freeze( obj );

 

数组的新API:

用于判断的API:

every:每个元素都要满足,结果才为true,只要有一个不满足,结果则为false 类似逻辑判断&&,遇到返回的是false就不会再执行操作了;语法如下

arr.every(
    function(val,i,arr){
        return 判断条件;
    }
)

some:所有的元素都不满足,结果才为false,只要有一个满足,结果就为true,类似于逻辑运算||,碰到true就不会再执行下去了。语法如下

arr.some(
    function(val,i,arr){
        return 判断条件;
    }
)
用于遍历的API:

遍历:将数组中的每一个元素取出来执行相同或相似的操作

forEach:遍历数组,直接修改原数组;语法如下:

arr.forEach(function(val,i,arr){
                    直接做操作
})
注意:forEach里面的val 和 arr[ i ]还是有差别的,后者不光保存着值,还记录了数据的位置信息。

map:遍历数组,不会修改原数组,而是返回的是一个新数组;操作如下

var newArr=arr.map(function(val,i,arr){
                    return 操作;
})
汇总和过滤

过滤:筛选自己想要的,但是不会修改原来的数组;语法如下:

var newArr = arr.filter(function(val,i,arr){
        return 操作;
})

汇总:把数组中的每个元素都汇总在一起格式如下:

var result=arr.reduce(function(prev,val,i,arr){
            return prev+val;
},基础值)

这里的prev初始值为0,reduce的第二个参数是基础值,可以在基础值上进行相加。

Object.create( ):希望根据父对象创建子对象,继承自动设置完毕。语法如下:
var 子对象 = Object.create(
    父对象,{
        “自有属性”:{四大特性}
    }
)

call/apply/bind:考点和难点

call()和apply( )方法的功能相同,但是传入的实参不同,call()可以传入多个实参,而apply只能传入一个数组。两者的语法如下:

两者立刻调用(借用),相当于执行了立刻执行函数,立刻执行。
函数名.call(借用的对象,实参,...);  // 单独传入每一个实参
函数名.apply(借用的对象,[实参,...]);  // 只能传入一个实参,是一个数组,但是其实apply也会悄悄的将数组打散
而bind则是永久替换了函数中的this

1.创建了一个和原函数功能完全相同的新函数

2.将新函数中的this永久的绑定固定伪类指定的对象,被人借不走

3.将新函数中的部分参数永久固定

语法如下
var 新函数 = 原函数.bind(指定对象,永久固定参数,...) //不是立刻执行,不要自己调用

关于call()和apply()的固定套路:

 

Math.max().apply(Math,arr) //获取数组中的最大最小值的时候
Object.prototype.toString.call/apply(arr) === "[objdct Array]"
//类数组转换为普通数组
let result = Array.prototype.slice.call/apply(类数组)

箭头函数:简化回调函数

括号里放的参数箭头后面跟着return的内容。

 

for of循环

for(var v of arr){
            v;//当前元素
 }

1.不能修改原数组,只能返回新数组。

2.不支持哈希数组,不支持对象。

 

DOM

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

DOM分为核心DOM、HTML DOM、XML DOM。

DOM类型优缺点
核心DOM 【无敌】,既可以操作HTML 和 XML 缺点:API比较繁琐
HTML DOM 只能操作HTML,API简单,缺点:比如属性部分,只能操作标准属性,不能操作自定义属性
XML DOM 只能操作XML,XML基本已经被淘汰了 - 现在最流行的数据格式json代替了

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

 

DOM树由浏览器的js解释器自动生成

 

每个DOM都有三大属性:nodeType、nodeValue、nodeName

1、xx.nodeType:描述节点的类型 document节点:9 元素节点:1 属性节点:2 文本节点:3

2、xx.nodeValue:描述节点值,说白了就是获取属性值

3、xx.nodeName:描述节点名称 - 判断xx是什么标签 - 后期搭配上事件委托(利用冒泡)

 

递归:自己调用自己,知道终止条件满足

function 函数名(root){ 1、第一层要做什么操作就直接做

2、判断他有没有下一级,如果有下一级再次调用此方法,但是传入的实参是下一级

}

 

递归 vs 循环 递归:优点:直观、易用 缺点:性能较低 循环:优点:性能高,几乎不占内存 缺点:难得一匹

 

遍历的API:TreeWalker:一个在DOM树上行走的人

缺点:1.会自动跳过根节点的操作 2.只能遍历层级不明确的DOM树,而不能遍历层级不明确的数据。

公式:

1.固定公式:

1.创建tw对象:var tw = document.createTreeWalker( 根元素,NodeFilter.SHOW / SHOW_ELEMENT )

2.反复调用nextNode方法找到每一个元素

while((node=tw.nextNode())!==null){
            node要做什么操作
}

 

DOM元素的增删改查

 

没找到得到的是
没找到元素的children 列表的长度为0
没找到元素或对象的属性 undefined
某个元素没找到儿子 null
1.创建元素,添加元素

document.createElement('p') ;

渲染页面:父元素.appendchild ;
父元素.insertBefore(新元素,已有子元素);//新元素会追加到父元素中当儿子,会插到已有子元素的前面
父元素.replaceChild(新,已有子元素);新元素会替换到父元素中当儿子,会替换已有子元素
2.用方法来添加

 

element.insertAdjacentHTML("position", "标签");

 

通过标签名获取元素
通过TagName来查询

element.getElementsByTagName()

注: 1.得到的是一个类数组元素

2.想要操作里面的元素记得添加下标(用类名查找的时候如果遇见多个标签同名,同理)

通过ID来查询

element.getElementById("id值")

注: 1、如果页面上有多个重复的id,只会返回第一个 2、此方法找到的是单个元素 - DOM节点是可以直接用于做操作的 3、此方法你不能使用 - 以后id留给后端使用,而且此方法一次也只能找到一个元素操作起来不方便

 

 

两种获取元素的方式有何区别:getXXX 、 querySelectorXXX有什么区别 ?
1.返回的结果不同:

1.getXXX:得到的是HTMLCollection==>是一个动态集合

2.queryXXX:得到的是一个nodeList ===>是一个静态集合

动态集合:

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

静态集合:

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

 

----根据标签名获取元素中的指定的后代元素

element.childNodes

----根据标签名获取元素中的父亲元素
element.parentNode
----获取当前元素的所有子节点
element.children
----获取当前元素的所有子元素

element.firstChild

----获取第一个子节点
element.firstElementchild
----获取第一个子元素

element.lastChild

----获取最后一个子节点
element.lastElementchild
----获取最后一个子元素

element.previoussibling

----获取前一个兄弟节点
element.previousElementSibling
----获取前一个兄弟元素

element.nextSibling

----获取后一个兄弟节点
element.nextElementSibling
----获取后一个兄弟元素
如何读取元素的属性:

元素.属性名

ele.name

ele.value

ele.id

ele.className

如何设置元素属性

元素.属性名 = 属性值

ele.name = XXX

ele.value = XXX

ele.id = XXX

ele.className = XXX

读取一个标签内部的文本:
<span>哈哈哈</span>
span.innerHTML
span.innerText
span.firstChild.nodeValue
span.textContent

操作元素

获取&设置属性

属性:什么是属性:HTML属性:id、class、title、alt、style、type、href...只要是放在HTML标签上的我们都称为属性

使用核心DOM获取属性:

1、获取属性值:elem.getAttribute("属性名"); - 多半用于判断操作
2、设置属性值:elem.setAttribute("属性名","属性值"); - 修改

使用HTML DOM获取属性:

1、获取属性值: elem.属性名 虽然简单,但是不能操作自定义属性。
2、设置属性值:elem.属性名 = 新值。
删除属性

核心DOM操作:elem.removeAttribute( "属性名" ) - 完整删除整个属性节点

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

判断有没有某个属性

核心DOM的操作:elem.hasAttribute("属性名"); 结果是一个布尔值

 

 

 

设置内容
内容:innerHTML /innerText/value ;

注:主流浏览器也支持innerText

获取内容的API:textContent:获取 和 设置元素的文本,不能识别标签 - 有兼容性问题老IE不支持

value属性:专门为单标签(input)操作内容准备的

获取:input.value; - 多半用于判断操作
设置:input.value="新内容"; - 修改内容

 

操作样式
元素.style.样式名 = 样式值 注:如果样式名中间有横线链接,记得去掉横线采用驼峰命名法。

修改内联样式:

获取元素的属性:

getComputedStyle(元素).属性

// - 该函数用来获取元素的当前样式

// - 参数:

// 1.要获取样式的对象

// 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";

注:client、offset、scroll三个系列获取值均不带单位

 

clientWidth,clientHeight用来获取盒子内部大小(包含内边距和内容)
offsetWidth,offsetHeight用来获取盒子可见框的大小(内容区,内边距,边框)

clientTop & clientLeft 返回元素上/左边框的大小

 

注:以上四个属性是只读属性,只能获取,不能修改。

offsetParent 获取当前元素的定位父元素

//定位父元素是离当前元素最近的开启了定位的祖先元素,如果所有祖先元素都没有开启定位,则返回body

offsetLeft 获取当前元素相对其定位元素(offsetParent )的左侧偏移量
offsetTop 获取当前元素相对其定位元素(offsetParent )的上侧偏移量

offsetWidth & offsetHeight 返回自身包含padding、边框、内容区域的宽/高度

 

scrollTop 垂直滚动条的滚动的 距离 (唯二可修改的)
scrollLeft 水平滚动的 距离 (唯二可修改的)

 

scrollHeight 设置可滚动区域的高度
scrollWidth 设置可滚动区域的宽度

注:当scrollHeight - scrollTop = clientHeight ; 时说明滚动条滑到底了

 

删除元素

删除节点

父节点.removeChild( ); 或 子节点.remove( );

 

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

1、Image对象:图片对象;

简化了创建方式:var img = new Image( );

2.Form对象:表单对象:

简化了查找元素:var form = document.forms[ i ];//获取页面上的第 i 个from元素;

简化了查找表单控件元素:var inp = form.elements[ i ]//获取此form表单中的第 i 个表单控件元素;

3.Select对象:

属性:

1.select.options === select.children 获取到select下面的所有option

2.select.selectedIndex; //获取到选中项的下标

方法:

1.select.add( option );//将option上树

2.select.remove( i ) ;//删除下标为 i 的option

专属事件:onchange 选中项发生改变后才触发
4.Option对象:
简化了创建方式:var opt = new Option( "innerHTML",”value“ ); ==>这个方法最好搭配select.selectedIndex使用

Object 对象

对象都有属性和方法,有三大特点,继承、封装、多态

封装对象的三种方法:

1.直接量方法

2.用构造函数的方式创建

3.使用自定义构造函数来创建对象

 

            格式:function 类名(name,age,salary){
                this.name=name;
                this.age=age;
                this.salary=salary;
            }
            var obj=new 类名(实参,...);

 

获取对象的属性的方式有两种:对象.属性名、对象["属性名"];

js的底层万物皆对象,对象底层都是哈希数组。

倘若访问不存在的属性则返回一个哈希数组。

可以使用for...in来遍历对象的属性,而object[ i ]则可以访问 对象的属性值。

如果在对象中的方法中要用到对象的属性,则可以使用this来代替创建的对象,以此来引用对象的属性。



posted on 2022-04-23 23:19  叛逆的缪斯  阅读(46)  评论(0编辑  收藏  举报