面试随写md

116 阅读8分钟

CSS优先级 link

  • CSS 优先规则1: 最近的祖先样式比其他祖先样式优先级高。
  • CSS 优先规则2:"直接样式"比"祖先样式"优先级高。

!important

  • 提高指定样式规则的应用优先权(优先级)box{color:red !important;}。
  • .class #id

!important > 内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器

就近原则

@import 导入 @import 语句必须出现在内部样式之前,否则文件引入无效

js操作DOM的方法整理

DOM (Document Object Model)文档对象模型

DOM为HTML提供了结构化表示方法,定义了访问和处理文档结构的方法规范。 HTML可以理解为是由DOM节点构成的集合,主要由元素节点、文本节点、属性节点三部分构成

js操作DOM的方法

js操作DOM主要是对于元素节点,文本节点和属性节点的增删改查

js 新增删除修改查找节点

var newNode = document.createElement('div')
// 创建一个新的元素节点

var newNode = document.createTextNode("hello world!")
// 创建一个文本节点

var mycloneNode = newNode.cloneNode(true)
// 克隆一个节点

document.createDocumentFragment();
// 创建文档对象变量,主要用来临时存储节点,大量操纵dom时性能有很大的提升
// 但是不太清楚为什么

var deleteNode = parentNode.removeChild(item)
// 删除指定的节点并且返回

// 修改节点
node.appendChild(newNode);// 在指定元素后面新增子节点
parentNode.insertBefore(newNode,node);  //在parentNode的子节点newNode前面插入newNode节点
parentNode.replaceChild(newNode,oldNode);//用oldNode节点替换parentNode的子节点newNode

// 查找结点 指点id
var parentNode = document.getElementById('ids')

// 指定的class

var classNodes = document.getElementsByClassName('classes')

// 指定的tag

var tagNodes = document.getElementsByTagName('tags')

var Names = document.getElementsByTagName('name')
// selector 
// 返回第一个带有指定id或者class的元素
var list = document.querySelector('#wrapper')
var lists = document.querySelectorAll('.wrapper')

通过节点之间的关系查找元素节点,dom节点的关系图以及操作方法如下 link

查找元素节点的方法
element.parentNode    //返回该节点的父节点,每个节点都会有一个父节点,Element的父节点可能是Element,Document或DocumentFragment;
element.parentElement    //返回父节点,只有父节点为元素节点时返回,否则返回null

element.children    //返回所有元素子节点的集合,仅包含元素节点
element.childNodes    //返回当前元素所有的子节点,包含元素节点,文本节点,属性节点。(注释、空格、换行等也会被当作一个节点)

element.firstChild    //返回当前元素的第一个子节点,该子节点可以是任意节点,如果没有则返回null
element.firstElementChild    //返回当前元素的第一个子节点,该子节点只可以是元素节点,如果没有则返回null
element.lastChild   第一个子元素节点(标签)  //返回当前元素的最后一个子节点,该子节点可以是任意节点,如果没有则返回null
element.lastElementChild   
(包括标签、空文档和换行节点)
//返回当前元素的最后一个子节点,该子节点只可以是元素节点,如果没有则返回null

element.previousSibling    //返回该节点的前一个兄弟节点
element.previousElementSibling    //返回该节点的前一个元素兄弟节点
element.nextSibling    //返回该节点的后一个兄弟节点
element.nextElementSibling    //返回该节点的后一个元素兄弟节点

修改元素属性

key: classList setAttribute node.style.color

var node =document.getElementById("list");
// classList方法操作元素的class属性
node.classList.add("test"); //给node节点添加一个class
node.classList.remove("test");//删除node节点名为test的class
node.classList.replace("old-class","new-class");//替换node节点的class
var hasClass = node.classList.contains("test");//node节点是否存在给定的class,如果存在则返回 true,否则返回 false。
node.classList.toggle("test")//如果节点已经存在给定的class则删除,如果没有则添加

node.setAttribute("id","123");//给node节点设置id=123
var id = node.getAttribute("id");//获取node节点的id属性值
var hasAttr =node.hasAttribute("id");//判断node节点是否存在id属性

// dataset方法获取元素的data- 属性值
var dataId=node.dataset.id; //获取node节点的data-id属性值
var dataName=node.dataset.userName;//类似data-user-name属性必须使用驼峰式来访问
'id' in node.dataset     // 判断node节点是否有data-id属性

// style方法修改元素的样式
node.style.color = 'red';   //设置color样式
node.style.setProperty('font-size', '16px');  //设置font-size样式
node.style.removeProperty('color');  //移除color属性


获取元素类型
element.nodeType //返回元素的节点类型 1元素节点 2属性节点 3文本节点 4CDATA节点 5实体引用名称节点 6实体名称节点  7处理指令节点  8注释节点  9文档节点  10文档类型节点 11文档片段节点 12DTD声明节

获取当前节点的文本值
element.innerHtml  //返回当前节点的所有文本包含html
element.innerText //返回当前节点及所有后代节点的文本值,不包含html

实例

比如寻找到

下面的p标签

  • 一方面我们可以使用querySelectorall
  • 它竟然还支持链式写法,惊呆了
  • 我猜它就支持因为符合逻辑
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div class="box">111</div>
  <div class="box">2222</div>
  <div id="btn">
    <!--标签+enter也算是标签里面有文本内容了-->
    aaaa
    <p>111</p>
    bbb
    <p>2222</p>
    ccc
  </div>
  aaaaaaaaaaaaaaa
  <div name="xxx"></div>
</body>
<script>
  console.log(1)
  var res7=document.getElementById("btn").firstChild
  console.log(res7)
  console.log(1)
  var box3=document.getElementById("btn") //通过id找,推荐用(做js添加效果时的查找依据)
  var res1=document.querySelectorAll("#btn p")
  console.log(box3)
  console.log(res1)
</script>

</html>

js的原型 设计模型 JS 封装多态以及继承

js的原型 设计模式
  • 首先我们应该明白什么是设计模式,以及他与js原型的关系
  • 设计模式 我听到了一时语塞,那不就是js的原型 new object.create() extends

link

组合继承
function Parent(value){
  this.val = value
}

Parent.prototype.getValue = function(){
  console.log(this.val)
}

function Child(value){
  Parent.call(this,value)
}

Child.prototype = new Parent()

child = new Child(1)

child.getValue()

console.log(child instanceof Parent)

以上继承的核心就是在子类的构造函数中通过 Parent.call(this) 继承父类的属性,然后改变子类的原型为 new Parent() 来继承父类的函数

  • 继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费
寄生组合继承
function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function() {
  console.log(this.val)
}

function Child(value) {
  Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true
  }
})

const child = new Child(1)

child.getValue() // 1
child instanceof Parent // true
class继承

super 就是利用子类调用super继承父类的this对象,然后再加工。

class Parent {
  constructor(value) {
    this.val = value
  }
  getValue() {
    console.log(this.val)
  }
}
class Child extends Parent {
  constructor(value) {
    super(value)
    this.val = value
  }
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
ES5,ES6继承的区别

ES6 继承的子类需要调用 super() 才能拿到子类,ES5 的话是通过 apply 这种绑定的方式

js设计模型 面向对象

继承,封装,多态,抽象

继承

深拷贝,浅拷贝,object.create,new

封装

对象的属性外部是可读可写的 如何实现封装

局部变量+变量

多态

其实不害怕你说错,但是害怕你不敢说

同一个父类继承出来的子类各有各的形态

js设计模式
  • 工厂模式
  • 单例模式
  • 模块模式
  • 代理模式
  • 发布订阅模式

easy-demo

var list = {
	arr: [],
	subscribe: function(fn) {
		this.arr.push(fn);
	},
	notify: function() {
		this.arr.forEach(fn => fn());
	}
};

var fn1 = function() {
	console.log(1)
}
var fn2 = function() {
	console.log(2)
}
list.subscribe(fn1);
list.subscribe(fn2);
list.notify();

js map forEach

我只能说之前答的跟是一样

我们首先来看一看MDN上对Map和ForEach的定义:

forEach(): 针对每一个元素执行提供的函数(executes a provided function once for each array element)。

map(): 创建一个新的数组,其中每一个元素由调用数组中的每一个元素执行提供的函数得来(creates a new array with the results of calling a provided function on every element in the calling array)。

到底有什么区别呢?forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。

因为forEach()会改变原始的数组的值,而map()会返回一个全新的数组,原本的数组不受到影响。

forEach适合于你并不打算改变数据的时候,而只是想用数据做一些事情

map()适用于你要改变数据值的时候。不仅仅在于它更快,而且返回一个新的数组。这样的优点在于你可以使用复合(composition)(map(), filter(), reduce()等组合使用)来玩出更多的花样。

能用forEach()做到的,map()同样可以。反过来也是如此。

map()会分配内存空间存储新数组并返回,forEach()不会返回数据。

  • foreach处理普通数组:把原数组拷贝一个后,再从中拿出每个元素,我们使用foreach对这些元素进行处理,并不是对原数组的处理,而只是对一个拷贝的处理,所以不管我们怎么改变其值,原数组的值是不会改变的。

js sort排序

sort 是数组的方法 ((a,b) => a-b)

vue的diff算法

一个DOM节点主要包含 标签名 属性名 子元素

Vue 使用JS对象构建virtual DOM的DOM副本。原因是我们使用JS直接操作DOM的计算成本很高

虚拟DOM是一个轻量级的JS对象,他由渲染函数创建。包含元素 具有的数据,propattr等属性 以及一个数组。数组放置的是该节点的子级。子级包含上述对象。同时具有子级。直至构建完整的DOM树

如果需要更新列表项,我们可以借助前面提到的响应性在 JavaScript 中进行。我们将更改应用至 JavaScript 副本、虚拟 DOM 中,然后在它们和实际 DOM 之间执行 diff

diff算法是通过调用patch函数来实现的。我们将节点分为VNode,oldVNode.同时只会在同层级进行比较

当数据改变时,notif通知所有订阅者。订阅者调用patch给真实DOM打补丁。VNode 和 OldVNode 节点进行比较。节点不同直接替代。相同的话比较子节点。oldVnode vnode 分别设置了头尾指针,通过四种方法进行比较。有key时,利用有key时: Diff算法就可以t通过唯一的标识key正确的识别此节点,复用key不变的节点,找到正确的位置区只插入需要更新的节点。

然后层层比较,直到更新完毕