一、写在前面的叨叨叨
之前用了四篇对Html,Css进行了总结,从这篇开始就是对Js进行一些温习回顾,在实际业务中框架用的多了,对一些原生属性是越来越不熟悉了,一些基础的操作dom的方法慢慢的也越来越手生了,正好这个机会整理一波,JS和css,html一样也只是针对性的挑了一些比较经典和基础的内容来进行总结。
二、Js基础梳理
1、js的基本类型有哪些?引用类型有哪些?引用类型和基本类型有什么区别?null
和 undefined
的区别。
值类型(基本类型)
:数值(number)、布尔值(boolean)、null、undefined、string(字符串)、Symbol。
基本类型的值是不可变的,比较是它们的值的比较,数据类型不同也可以进行值比较,因为会进行数据类型的隐式转换。基本类型的变量是存放在栈内存(Stack)里的,栈内存中包括了变量的标识符和变量的值。
引用类型
:对象(Object)、数组(Array)、函数(Function)、RegExp、Date 类型。
引用类型的值是可变的,比较是它们引用的比较,引用类型的值是保存在堆内存(Heap)中的对象(Object)。栈内存中保存了变量标识符和指向堆内存中该对象的指针,堆内存中保存了对象的内容。
null 表示”没有对象”,即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined 表示”缺少值”,就是此处应该有一个值,但是还没有定义。典型用法是:
(1) 变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3) 对象没有赋值的属性,该属性的值为undefined。
(4) 函数没有返回值时,默认返回undefined。
2、如何判断对象类型
typeof 操作符
适合判断基本类型,不适合判断引用类型(都返回object),比如自定义的对象类型。如果我们想要判断一个变量是否存在,可以使用typeof a != “undefined”instanceOf操作符
判断一个实例是否存在于某对象的原型链上用对象的 constructor 来判断对象类型
当检测null或者undefined类型的constructor 属性时,js会报错,不推荐使用Object.prototype.toString.call(object)
(主流建议方法)
形式 Object.prototype.toString.call(object).slice(8,-1).toLowerCase();
3、JS常见的DOM操作API
基本概念:浏览器为JavaScript提供的一系列接口。Node有一个属性nodeType表示Node的类型,它是一个整数,其数值分别表示相应的Node类型。
Element类型
:提供了对元素标签名,子节点和特性的访问,nodeType为1。Attr类型
:表示元素的特性,nodeType值为2。Text类型
:表示文本节点,它包含的是纯文本内容,nodeType为3。Comment类型
:表示HTML文档中的注释,nodeType为8。Document
:表示文档,document对象是HTMLDocument的一个实例,nodeType为9。DocumentFragment类型:表示一种轻量级的文档,nodeType为11。
a、节点创建API(用来创建节点)
createElement
(创建元素)
Document.createElement()通过传入指定的一个标签名来创建一个元素.createTextNode
(创建文本)
Document.createdTextNode()传入文本节点中的文本cloneNode
(复制节点)
返回调用方法的节点的一个副本,它接收一个bool参数,用来表示是否复制子元素,为真表示复制子元素,为假表示只复制parent节点。parent.cloneNode(true);。如复制的元素有id,则其副本同样包含该id,所以复制节点后必须要修改其id。createDocumentFragment
(创建一个DocumentFragment)
主要是用于添加大量节点到文档中时会使用到,可以先将节点添加到fragment,最后一次性添加到文档,因为DocumentFragment不是文档树的一部分,它是保存在内存中的,所以不会造成回流问题。
b、页面修改API(用来修改页面DOM)
appendChild
(插入到末尾)
将指定的节点添加到调用该方法的节点的子元素的末尾,如果被添加的节点是一个页面中存在的节点,则执行后这个节点将会添加到指定位置,其原本所在的位置将移除该节点insertBefore
(添加一个节点到一个参照节点之前)
例:parentNode.insertBefore(newNode,refNode),parentNode表示新节点被添加后的父节点,newNode要添加的节点,refNode参照节点,新节点添加到这个节点之前。refNode是必传的,如果不传该参数会报错。removeChild
(删除指定子节点)replaceChild
(用于使用一个节点替换另一个节点)
例:parent.replaceChild(newChild,oldChild);newChild是替换的节点,可以是新的节点,也可以是页面上的节点,如果是页面上的节点,则其将被转移到新的位置。oldChild是被替换的节点。
c、节点查询API
document.getElementById()
根据元素id返回元素,返回值是Element类型,如果不存在该元素,则返回null。document.getElementsByTagName()
根据元素标签名获取元素,返回一个即时的HTMLCollection类型document.getElementsByName()
通过指定的name属性来获取元素,它返回一个即时的NodeList对象。document.getElementsByClassName()
(注:IE9+)
根据元素的class返回一个即时的HTMLCollection,如果要获取2个以上classname,可传入多个classname,每个用空格相隔。document.querySelector()
(注:IE9+)
通过css选择器来查找元素,返回第一个匹配的元素,如果没有,则返回null。document.querySelectorAll()
(注:IE9+)
返回的是所有匹配的元素,而且可以匹配多个选择符。
d、节点关系API
parentNode和parentElement
(父关系型)
parentNode:表示元素的父节点,parentElement:返回元素的父元素节点,与parentNode的区别在于,其父节点必须是一个Element,如果不是,则返回null。previousSibling
、previousElementSibling
、nextSibling
、nextElementSibling
previousSibling:节点的前一个节点,previousElementSibling:返回前一个元素节点,前一个节点必须是Element(注:IE9+)。nextSibling:节点的后一个节点,nextElementSibling:返回后一个元素节点,后一个节点必须是Element。(注:IE9+)childNodes
、children
、firstNode
、lastNode
、hasChildNodes
(子关系型)
childNodes:表示元素的子节点列表,children:返回是Element的子节点,firstNode:第一个子节点,lastNode:最后一个子节点。hasChildNodes:判断是否包含子节点。
e、元素属性API
setAttribute
(根据名称和值修改元素的特性)
element.setAttribute(name, value); 其中name是特性名,value是特性值。如果元素不包含该特性,则会创建该特性并赋值。getAttribute
(返回指定的特性名相应的特性值)
element.getAttribute(“id”),如果不存在,则返回null或空字符串。
f、元素样式API
window.getComputedStyle()
获取应用到元素后的样式
window.getComputedStyle(element[, pseudoElt]) element是要获取的元素,pseudoElt指定一个伪元素进行匹配。返回的style是一个CSSStyleDeclaration对象。通过style可以访问到元素计算后的样式.getBoundingClientRect()
返回元素的大小以及相对于浏览器可视窗口的位置
clientRect是一个DOMRect对象,包含left,top,right,bottom,它是相对于可视窗口的距离,滚动位置发生改变时,它们的值是会发生变化的。除了IE9以下浏览器,还包含元素的height和width等。
4、解释一下事件捕获和事件冒泡,事件委托,如何阻止冒泡,阻止默认事件。
DOM2级事件规定的事件流的三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。
事件捕获
:从document到触发事件的那个节点,即自上而下的去触发事件,触发顺序为自外向内。事件冒泡
:事件冒泡是自下而上的去触发事件,直到document/window。个人理解,事件冒泡存在的意义,就是在事件运行过程中,避免使用循环遍历的方式去给每个同级元素触发相同的事件,而优化性能。事件委托
:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。(经典取快递例子理解)
addEventListener(event,fn,false)方法用于向指定元素添加事件,事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获。true,事件捕获;false,事件冒泡。默认false,即事件冒泡。阻止冒泡
: event.stopPropagation()(注:IE9+)阻止默认行为
:event.preventDefault()
5、 js 的作用域有几种?函数的作用域是什么?
一般说三种:全局
、函数
和 eval作用域
。作用域又称执行环境,所有变量都存在于一个执行环境(作用域)中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量,每进入一个执行环境都会创建一个用于搜索变量和函数的作用域链。作用域链本质是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。作用域在函数定义时就已经确定,而不是在函数调用时确定。作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。
6、对闭包的理解?什么时候构成闭包?闭包的优缺点?
当在函数内部定义了其他函数时(引用了父作用域变量)就创建了闭包,闭包有权访问包含函数内部的所有变量。在执行环境中,闭包的作用域链包含着它自己的作用域,包含函数的作用域,全局作用域,通常函数的作用域及其变量都会在函数执行结束后被销毁,但当函数返回一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。
优点
:可以读取函数内部的变量。实现私有作用域(封装插件)
缺点
:创建闭包必须维护额外的作用域,过度使用会占用大量内存。
7、显示原型和隐式原型,手绘原型链,原型链是什么
创建的每个函数都有prototype(原型)
属性,这个属性是个指针,指向一个对象(通过调用构造函数而创建的那个对象实例的原型对象)。 每个对象都有一个__proto__
属性,可成为隐式原型.指向创建该对象的函数的prototype
。
每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(constructor)
,而实例包含一个指向原型对象内部的指针(__prototype__)
。
原型链
:访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找。原型链是实现继承的主要方法。
8、实现继承的多种方式和优缺点
- 原型链(缺点:包含引用类型值的原型属性会被所有实例共享,创建子类型实例时,不能向超类型的构造函数中传参)
- 借用构造函数(方法都在构造函数中定义,函数无法复用)
- 组合继承(原型链+构造函数)*推荐用法
- 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现实例属性的继承。
- 原型式继承 Object.creat() IE9+
9、this有哪些使用场景?如何改变this的值(call,apply,bind)?
this
对象是在运行时基于函数的执行环境绑定的:在全局函数中,this
等于window
,当函数被作为某个对象的方法掉用时,this
等于那个对象,不过匿名函数的执行环境具有全局性,因此其this
通常指向window
。
唯一的一个不同就是采用了function.call
或者function.apply
的情况,function
的this
指向了call
的传参,但这恰恰是针对上述this
指向调用者的情况的一种补充,专用于调整this
指向的。
10、new 一个对象(构造函数)具体做了什么
- 1.创建一个新对象
- 2.将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 3.执行构造函数中的代码(为这个新对象添加属性)
- 4.返回新对象
三、写在后面的叨叨叨
本来自己是单独整理了20个左右的题目,放在这篇文章中自己去总结回答,但是没想到会花费那么多的时间,这十个题目差不多也包含了js
最难得那几块,原型链,闭包,继承之类的,虽然我写的很简单,但是资料查了很多,总结的话也是自己通过查资料后自己理解后进行总结的并没有照搬其他的文章,除了一些标准的API之类的东西,总之时间是花了比较久的,所以暂时只整理了这些,等下次有时间接着撸其他问题。感谢阅读。