SampsonKY


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

Js 事件

发表于 2019-07-24 | 分类于 前端学习

JS事件

一、 事件与事件流

先来看它们的定义:

事件,就是通过文档或浏览器窗口中发生的一些特定的交互瞬间。

事件是您在编程时系统内发生的动作或者发生的事情— 系统会在事件出现的时候触发某种信号并且会提供一个自动加载某种动作(例如:运行一些代码)的机制。

事件流描述的是从页面中接收事件的顺序。

事件流包括事件冒泡和事件捕获,两者分别由微软和网景公司提出。两个概念都是为了解决页面中事件发生顺序的问题。

事件冒泡的思想是:从最具体的元素(文档中嵌套层次最深的那个节点)开始接收,然后逐级向上传播到最不具体的节点(文档)。

事件捕获的思想是:不太具体的节点应该更早接受到事件,而最具体的节点应该最后接收到事件。

DOM事件流:在DOM2级事件中规定,事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会;然后是实际的目标接收到事件;最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

比如:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>事件</title>
</head>
<body>
<div>aaaa</div>
</body>
</html>

如果单击了<div>标签,在事件冒泡的概念下,click事件传播顺序:div -> body -> html -> document;在事件捕获的概念下,click事件传播的顺序:document -> html -> body -> div.

在DOM事件流中,实际的目标(<div>元素)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从document到<html>再到<body>就停止了。下一个阶段是“处于目标阶段”,于是事件在<div>上发生,并在事件处理中看成冒泡阶段的一部分。然后冒泡阶段发生,事件又传播回文档。

【注意】:对于事件代理而言,在事件捕获或事件冒泡阶段处理并没有明显的优劣之分,但由于事件冒泡的事件流模型被所有主流的浏览器兼容,从兼容角度来说,建议使用事件冒泡模型。最好只在需要在事件到达目标之前截获它的时候将将事件处理程序添加到捕获阶段。

几个题目,看你是否懂了:

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <div id="s1">s1
        <div id="s2">s2</div>
    </div>
    <script>
        s1.addEventListener("click", function (e) {
            console.log("s1 捕获事件");
        }, true);
        s2.addEventListener("click", function (e) {
            console.log("s2 捕获事件");
        }, true);
        //点击s1,结果为:s1捕获事件
        //点击s2, 结果为:s1捕获事件,s2捕获事件
    </script>
  2. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <div id="s1">s1
    <div id="s2">s2</div>
    </div>
    <script>
    s1.addEventListener("click", function (e) {
    console.log("s1 冒泡事件");
    }, false);
    s2.addEventListener("click", function (e) {
    console.log("s2 冒泡事件");
    }, false);
    //点击s1:s1冒泡事件
    //点击s2: s2冒泡事件,s1冒泡事件
    </script>
  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <div id="s1">s1
    <div id="s2">s2</div>
    </div>
    <script>
    s1.addEventListener("click", function (e) {
    console.log("s1 冒泡事件");
    }, false);
    s2.addEventListener("click", function (e) {
    console.log("s2 冒泡事件");
    }, false);

    s1.addEventListener("click", function (e) {
    console.log("s1 捕获事件");
    }, true);

    s2.addEventListener("click", function (e) {
    console.log("s2 捕获事件");
    }, true);
    //点击s1: s1冒泡,s1捕获
    //点击s2: s1捕获事件 s2冒泡事件 s2捕获事件 s1冒泡事件
    </script>

    当事件捕获和事件冒泡一起存在的情况:

    先记被点击的DOM节点为target节点

    1. document 往 target节点,捕获前进,遇到注册的捕获事件立即触发执行
    2. 到达target节点,触发事件(对于target节点上,是先捕获还是先冒泡则捕获事件和冒泡事件的注册顺序,先注册先执行)
    3. target节点 往 document 方向,冒泡前进,遇到注册的冒泡事件立即触发

    总结:

    • 对于非target节点则先执行捕获在执行冒泡
    • 对于target节点则是先执行先注册的事件,无论冒泡还是捕获

二、事件处理程序

事件是用户或浏览器自生执行的某种动作。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。

HTML中的事件处理程序

1
<input type="button" value="click me" onclick="alert('Clicked')" />
  • 某个元素支持的每种事件都可以使用一个与相应事件处理程序同名的HTML特性来制定。这个特性的值应该是能够执行的JavaScript代码。
  • 在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面中其他地方定义的脚本。

独到之处:

  1. 会创建一个封装着元素属性值的函数。这个函数有一个局部变量event,也就是事件对象。通过event变量,可以直接访问事件对象,不用自己定义,也不用从函数的参数列表中读取。
  2. 在这个函数内部,this的值等于事件的目标元素。
  3. 拓展作用域的方式

缺点:

  1. 存在一个时差问题,因为用户可能会在HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。为此,很多HTML事件处理程序都会被封装在一个try-catch块中,以便错误不会浮出水面。
  2. 这样拓展事件处理程序的作用域链在不同浏览器中会导致不同结果。
  3. HTML与JavaScript代码紧密耦合。

DOM0级事件处理程序

1
2
3
4
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
};
  • 将一个函数赋值给一个事件处理程序属性这种传统方法依然被所有现代浏览器所支持的原因是:简单、跨浏览器优势。
  • 我们首先要做的就是必须取得一个要操作的对象的引用。
  • 每个元素(包括window和document)都有自己的事件处理程序属性,将这种属性的值设为一个函数,就可以指定事件处理程序。

【注意】:

  1. 使用DOM0级事件方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行,即程序中的this引用当前元素。
  2. 可以在事件程序中通过this访问元素的任何属性和方法。
  3. 以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
  4. 可以通过将事件处理程序设置为null来删除DOM0级方法指定的事件处理程序

DOM2级事件处理程序

1
2
3
4
5
6
7
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
},false);
btn.removeEventListener("click", function(){
alert("this.id");
},false);
  • DOM2级事件定义了两个方法,用于指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。所有DOM节点都包含这两个方法,并且它们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。如果这个布尔值参数为true,表示在捕获阶段调用事件处理程序;为false表示在冒泡阶段调用事件处理程序。
  • 与DOM0级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。
  • 使用这种方法的主要好处是可以添加多个事件处理程序,并且事件处理程序会按照添加它们的顺序触发。
  • 通过传入addEventListener()添加的事件处理程序只能用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。也意味着通过addEventListener()添加的匿名函数无法移除。比如上面的例子。

IE事件处理程序

1
2
3
4
5
6
7
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this.id);
});
btn.detachEvent("onclick", function(){
alert("this.id");
});
  • IE实现了和DOM中类似的两个方法: attachEvent()和detachEvent()。这两个方法接收两个参数:事件处理程序的名称和事件处理程序函数。通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。
  • 在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序中的作用域。在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
  • attachEvent()也可以用来为一个元素添加多个事件处理程序。但以相反的顺序被触发。
  • 使用 attachEvent()添加的事件可以通过detachEvent()来移除。条件是必须提供相同的参数。这意味着添加的匿名函数无法移除。

跨浏览器的事件处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var EventUtil = {
addHandler: function(element, type, handler){
if(element.addEventListener){
element.addEventListener(type, handler, false);
} else if( element.attachEvent){
element.attachEvent("on"+type,handler);
} else{
element["on"+type] = handler;
}
},
removeHandler:function(element, type, handler){
if(element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if( element.detachEvent){
element.detachEvent("on"+type,handler);
} else{
element["on"+type] = null;
}
}
};

EventUtil.addHandler(btn,"click",handler);

三、事件对象

在触发DOM上某个事件时,会产生一个事件对象event,这个对象中包含所有与事件有关的信息。包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。

DOM中的事件对象

1.兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0级或DOM2级),都会传入event对象。

1
2
3
btn.onclick = function(event){
alert(event.type); //"click"
};

2.在通过HTML特性指定事件处理程序时,变量event中保存着event对象。

1
<input type="button" value="Click me" onclick="alert(event.type)">

以这种方式提供event对象,可以让HTML特性事件处理程序与JavaScript函数执行相同的操作。

event对象中包含着与创建它的特定事件有关的属性和方法。

  • 在事件处理程序内部对象this始终等于currentTarget的值,而target则只包含事件的实际目标。
  • 要阻止特定事件的默认行为,可以使用preventDefault()方法。
  • 只有cancelable为true的事件,才可以使用preventDefault()方法
  • stopPropagation()方法用于立即停止事件在DOM层次中的传播,即进一步取消事件的捕获或冒泡。
  • 事件对象的eventPhase属性可以用来确定事件当前正位于事件流的哪个阶段。

只有在事件处理程序执行期间,event对象才会存在;一旦事件处理程序执行完成,event对象就会被销毁。

IE中的事件对象

情况1.DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。

情况2.如果事件处理程序是使用attachEvent()添加的,那么就会有一个event对象作为参数传入事件处理程序函数中。

情况3.如果通过HTML特性制定的事件处理程序,那么可以通过一个名叫event的变量来访问event对象。

IE的event对象也包含与创建它的事件相关的属性和方法:

  • cancelBubble属性 —– 取消冒泡
  • returnValue属性 —– 取消事件的默认行为
  • srcElement属性 —- 事件的目标
  • type属性 — 事件的类型

因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this会始终等于事件目标。故而,最好还是使用event.srcElement比较保险。

跨浏览器的事件对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var EventUtil = {
addHandler: function(...){...},
getEvent: function(event){
return event? event:window.event;
},
getTarget: function(event){
return event.target||event.srcElement;
},
preventDefault: function(event){
if(event.preventDefault){
event.perventDefalut();
} else{
event.returnValue = false;
}
},
removeHandler:....

stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
} else{
event.cancelBubble = true;
}
}
};

四、内存和性能

在JavaScript中,添加到页面上的事件处理程序数量直接关系到页面的整体运行性能。导致这一问题的原因有很多,首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

事件委托就是解决方案,时间委托利用了事件冒泡,只指定一个事件处理程序就可以管理某一类的所有事件。使用事件委托,只需要在DOM树中尽量最高的层次上添加一个事件处理程序。

内存中存有那些“过时不用”的“空事件处理程序”,也是造成web应用程序内存与性能问题的主要原因。在不需要的时候移除事件处理程序也是一种解决方案。

五、参考

  • JS中事件冒泡与捕获
  • JavaScript高级程序设计

Js 定时器

发表于 2019-07-21 | 分类于 前端学习

JavaScript定时器

一、什么是定时器

JavaScript提供了一些原生的方法来实现延时去执行某一段代码,下面简单介绍一下:

setTimeout:设置一个定时器,在定时器到期后执行一次函数或代码段,

1
var timeoutId = window.setTimeout(func|code, delay);
  • timeoutId: 定时器ID
  • func: 延迟后执行的函数
  • code: 延迟后执行的代码字符串,不推荐使用原理类似eval()
  • delay: 延迟的时间(单位:毫秒),默认值为0

setInterval: 以固定的时间间隔重复调用一个函数或者代码段·

1
var intervalId = window.setInterval(func|code, delay);
  • intervalId: 重复操作的ID
  • func: 延迟调用的函数
  • code: 代码段
  • delay: 延迟时间,没有默认值

另外,还有两种不常见的定时器:setImmediate, requestAnimationFrame。

二、定时器的工作原理以及不定时的原理

JavaScript是一个单线程的解释器,因此一定时间内只能执行一段代码。为了要控制执行的代码,就有一个JavaScript任务队列。这些任务会按照它们添加到队列的顺序执行。setTimeout()的第二个参数告诉JavaScript再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么它就要等前面的代码执行完了以后再执行。

【注意】:

  1. 首先,JavaScript是以单线程的方式运行的。JavaScript的主要用途是与用户互动,以及操作DOM。若以多线程的方式,则可能出现冲突。假设有两个线程同时操作一个DOM元素,线程1要求浏览器删除DOM,而线程2却要求修改DOM样式,这时浏览器就无法决定采用哪个线程的操作。(但是JavaScript有个基于“Event Loop”并发的模型。<此处不讨论。。>)
  2. js既然是单线程的,也就意味着所有任务需要排队。所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)
    • 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,形成了一个执行栈
    • 异步任务指的是,不进入主线程,而进入”任务队列”(task queue)的任务。”任务队列”是一个事件的队列(可以当作消息的队列来理解)。IO设备完成一项任务or异步任务有了运行结果,就在”任务队列”中添加一个事件,表示相关的操作可以进入”执行栈”,就等着执行栈调用了。
  3. 因为setTimeout, setInterval是异步任务,调用之后不会直接进入执行栈,而是进入任务队列,所以只有等到当前执行栈没有其他操作,它们才会进入执行栈中执行, 以上就是为什么定时器不总是定时的原因了。
  4. 如果delay时间周期设为0,相当于一个插队操作

三、实例

例1:

1
2
3
4
5
6
7
8
var a = true;
setTimeout(function(){
a = false;
}, 1000);

while(a){}

console.log(a);

console.log(a)永远不会执行,因为JavaScript是单线程的,且定时器的回调将在等待当前正在执行的任务完成后才执行,而while(a){}直接进入了死循环,一直占用线程,不会给回调函数执行机会。

例2:

1
2
3
4
5
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 0);
}

代码会输出5 5 5 5 5。当i = 0时,生成一个定时器,将回调函数插入到事件队列中,等待当前队列中无任务执行时立即执行,而此时for循环正在执行,所以回调被搁置。当for循环执行完之后,队列中存在5个回调函数,它们都将执行console.log(i)的操作,因为当前JS代码中并没有使用块级作用域,所以i的值在for循环结束后一直为5.

例3:

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
msg: 'obj',
shout: function () {
alert(this.msg);
},
waitAndShout: function() {
setTimeout(function () {
this.shout();
}, 0);
}
};
obj.waitAndShout();

这个问题涉及到了this的指向问题,由setTimeout()调用的代码运行在与与所在函数完全分离的执行环境上。这会导致这些代码中包含的this关键字会指向window(或全局)对象,window对象中并不存在shout方法,所以就会报错。

可以这样修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
msg: 'obj',
shout: function () {
alert(this.msg);
},
waitAndShout: function() {
var self = this; //这里将this赋给一个变量
setTimeout(function () {
self.shout();
}, 0);
}
};
obj.waitAndShout();

四、注意事项

  1. 我们可以使用clearTimeout()和clearInterval()方法来取消定时器
  2. 对于setTimeout(f, 0)指定时间为0,并不是说回调函数f会马上执行,而是会在下一轮事件循环一开始就执行。
  3. 在使用超时调用时,没必要跟踪超时调用ID,因为每次执行代码之后,如果不再设置另一次超时调用,调用就会自行停止。
  4. 最好不要使用间歇调用

五、参考

  • 《JavaScript高级程序设计》第三版

  • MDN

  • JS 定时器的四种写法及简介

  • 定时器

  • js定时器,你所要了解的那点事

JavaScript高级程序设计总结

发表于 2019-07-19 | 分类于 前端学习

第1章 JavaScript简介

part 1 JavaScript基本概念

包括定义,组成部分,基本特点,日常用途,历史,特性,编程,版本,与其他语言的比较(参考).

part 2 组成部分

  • ECMAScript,由ECMA-262定义,提供JavaScript核心功能。
  • DOM(DOM级别),提供访问和操作网页内容的方法和接口。
  • BOM(5个对象)(JS高程第八章),提供与浏览器交互的方法和接口。

第二章 在HTML中使用JavaScript

主要注意点:

  • <script>的六个属性是什么以及各自的用途?
  • 延迟脚本&异步脚本各自的特点?
  • 标签可以放在哪些位置?
  • 当嵌入代码和外部文件同时存在于一个<script>标签里,会发生什么?
  • 多个<script>存在于页面中时,它们的解析顺序?(注意延迟脚本和异步脚本的存在)
  • 外部文件相对于嵌入代码有什么好处?
  • 文档模式&doctype?(混杂模式,标准模式,准标准模式,严格模式……)
  • <noscript>标签解决了怎样的问题?

第三章 基本概念

part 1 基本语法

  • 区分大小写
  • 标识符是什么?标识符命名规则?
  • 严格模式用在哪?怎么启用?有哪些特点?
  • 关键字和保留字的区别?关键字和保留字分别有哪些?

part2 变量

  • 变量仅仅是一个用于保存值的占位符,变量可以用来保存任何值,未经初始化的变量的值为undefined
  • var、let、const的区别?

part 3 数据类型

  • 基本数据类型有哪些,它们各自有哪些特点?

  • typeof操作符有什么作用,它有哪些特点?

  • 检测变量数据类型有哪些方法?

  • 包含undefined值的变量和尚未定义的变量的区别?

  • undefined与null的区别?

  • 关于Boolean()函数转化(哪些转换为true,哪些转换为false)

  • JavaScript是如何储存数值的?为什么会出现 0.1+0.2 != 0.3 的情况? 参考

  • 数值范围以及isFinite()函数

  • NaN是什么,isNaN()函数

  • 数值转换函数Number(),parseInt(),parseFloat()各自特点以及它们之间的区别?

  • 转义序列是用来干嘛的?有哪些?

  • 字符串又什么特点?(ECMAScript中的字符串是不可变的,也就是说,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另外一个包含新值的字符串填充该变量)

  • 转换为字符串方法toString(),String()的区别

  • Object类型所具有的的任何属性和方法同样存在于更具体的对象中。Object的每个实例都有这些属性和方法(constructor、hasOwnProperty(propertyName)、isPrototypeOf(object)、propertyIsEnumerable(propertyName)、toLocaleString()、toString()、valueOf())

  • toLocaleString()、toString()、valueOf()各自的功能以及它们的区别?

part 4 操作符

  • ++、–、+、- 对非数值应用时,会像Number()转型函数一样对这个值执行转换。
  • 位操作(& | ~ ^ << >>)的基本概念
  • 左移位不会影响操作数的符号位;有符号右移,空位由符号位填充;无符号右移,空位由0填充。
  • 布尔操作符(&& || !)基本操作。
  • 逻辑非会先把它的操作数强转为一个布尔值,然后再求反。逻辑与,逻辑或在有一个操作数不是布尔值的情况下,不一定返回布尔值,它们的规则是?(p45、p46)
  • 关系操作符(>, < ,<=, >=…)的操作数使用了非数值时,要进行数据转换或完成某些操作,规则是怎样的?(p50)
  • 相等和不相等——先转换再比较;全等和不全等——仅比较而不转换。相等和不相等操作符对操作数进行强制转型的规则是什么?(p51)

part 5 语句

  • if语句、do-while语句、while语句、for语句、for-in语句、label语句、break和continue语句、with语句、switch语句

  • for-in语句是一种精准的迭代语句,可以用来枚举对像的属性。语法:for (property in expression) statement。ECMAScript对象的属性没有顺序,因此,通过for-in循环输出的属性名的顺序是不可预测的。但是,如果表示要迭代的对象的变量值为null或undefined,for-in语句会抛出错误。

  • label语句可以在代码中添加标签,以便将来使用。语法:label: statement。

  • break和continue语句都可以和label语句联合使用,从而返回代码中特定的位置。例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var num = 0;
    outermost:
    for(var i = 0; i < 10; i++){
    for(var j = 0; j < 10; j++){
    if(i==5 && j==5){
    break outermost;//①添加这个标签的结果导致break语句不仅会退出内部的for语句,而且与会退出外部的for语句。
    //continue outermost; //退出内部循环,执行外部循环
    }
    num++;
    }
    }
    conslole.log(num); //①55 ②95

part 6 函数

  • return 语句可以不带有任何返回值。在这种情况下,函数停止执行后将返回undefined值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下。
  • ECMAScript中的参数在内部都是用一个数组来表示的。函数接收到的始终是这个数组,而不关心数组中包含哪些参数。函数体内的argument对象可以访问这个参数数组,从而获取传递给函数的每一个参数。
  • 命名的参数只提供便利,但不是必需的。ECMAScript中也没有函数签名的概念,因为其函数参数是一个包含0个或多个值的数组的形式传递的。
  • argument对象可以与命名参数一起使用。argument对象的值永远与对应命名参数的值保持同步。虽然值保持同步,但它们的内存空间是独立的。
  • 没有传递值的命名参数自动被赋予undefined值。
  • 由于不存在函数签名的特性,ECMAScript函数不能重载。

第四章 变量、作用域、内存问题

part 1 引用类型和基本类型的值

  • 引用类型、基本类型是什么?它们有哪些异同?
  • 定义基本类型和引用类型的值的方式是类似的:创建一个变量并为该变量赋值。但对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。
  • 复制:①基本类型:两者是完全独立的,相当于创建了一个副本。②引用类型:副本实际是一个指针,指针指向存储在堆中的一个对象。复制结束后,两者实际引用同一个对象。
  • 传递参数:所有函数的参数都是按值传递的!

part 2 执行环境和作用域

  • 执行环境、作用域、作用域链这些是什么?
  • 怎么延长作用域链?
  • 关于没有块级作用域怎么理解?
  • 作用域的类型有哪些?

part 3 垃圾收集

  • 为什么需要进行垃圾收集?
  • 垃圾收集的方式有哪些以及它们的原理?(标记清除&引用计数)
  • 当代码中存在循环引用现象时,“引用计数”算法就会导致问题,问题是什么?如何解决?
  • 解除引用是什么?它有哪些好处?

第五章 引用类型

  • 引用类型是什么?引用类型的值(对象)是什么?

part 1 Array类型

数组的每一项都可以保存任何类型的数据。数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新增数组。

  • 创建数组的方式:

    1
    2
    3
    4
    5
    6
    7
    //使用Array()构造函数
    var a = new Array();
    var a = new Array(20);
    var a = new Array("red","blue","black");
    var a = Array(3);//在使用Array构造函数时也可以省略new操作符
    //使用字面量表示法【与对象一样,在使用数组字面量表示法时,也不会调用Array构造函数。
    var a = ["red", "blue", "black"];
  • 检测数组的方法有哪些?

  • 数组有哪些方法?(转换方法、栈方法、队列方法、重排序方法、操作方法<创建、切片、删除、插入、替换>、位置方法、迭代方法、归并方法)

  • sort()方法需要注意的问题。sort()方法接受的比较函数是怎样的?实现的原理是什么?

  • splice()方法如何实现删除、插入、替换操作?

  • every()、some()、map()、filter()、forEach()的区别?

  • 归并数组方法reduce()和reduceRight()是怎么操作的?

part 2 Date类型

Date类型使用UTC(国际协调时间)1970年1月1日零时开始经过的毫秒数来保存日期。

  • 创建日期对象var now = new Date(); //自动获取当前时间和日期

  • 如果想根据特定时间和日期创建日起对象。必须穿入该日期的毫秒数,Date.parse(), Date.UTC()可简化这个过程。两个方法接收的参数有一定的规则。

  • 例:

1
2
3
var someDay = new Date(Date.parse("May 25, 2004"));
var someDay = new Date("May 25, 2004");//后台自动调用Date.parse()方法
var someDay = new Date(Date.UTC(2000,0,1,0,55,55));
  • Date.now()方法,返回表示调用这个方法的日期和时间的毫秒数。使用+操作符也可获取Date对象的时间戳。

    1
    2
    3
    4
    5
    6
    var start = Date.now();
    //var start = +new Date();
    doSomething();
    var stop = Date.now();
    //var stop = +new Date();
    result = stop-start;
  • Date类型继承的toString()、toLocaleStirng、valueOf()方法的区别?

  • 日期格式化有哪些方法?

  • 日期/时间组件的方法有哪些?

    part 3 RegExp类型

    part 4 Function类型

函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上是一个指向函数对象的指针。使用不带圆括号的函数名是访问函数指针,而非调用函数!

函数名本身就是变量,所以函数也可以通过作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。

  • 理解函数为什么没有重载?
  • 函数提升是什么?
  • 函数内部的两个特殊对象:argument和this分别是什么?
  • argument对象的callee属性有什么用?(callee属性是一个指针,指向拥有这个argument对象的函数。)
  • 函数的另一个对象属性caller是什么?它有什么用?(caller属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null)。
  • 函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。length属性标识函数希望接收的命名参数的个数。
  • 对于EMCAScript引用类型而言,prototype是保存它们所有实例和方法的真正所在。换句话说,诸如toString(),valueOf()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。prototype属性是不可枚举的,因此使用for-in无法发现。
  • 每个函数都包含两个非继承而来的方法:apply()和call()。它们的用途是什么?它们两个的区别是什么?它们的适用情况?
  • bind()方法是什么?

part 5 基本包装类型

为了便于操作基本类型值,ECMAScript还提供了3个特殊的引用类型:Boolean,Number和String。这些类型和其他引用类型相似,但同时也有各自的基本类型相应的特殊行为。实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象。

引用类型和基本包装类型的主要区别就是对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法。

Object构造函数会根据传入值的类型返回相应基本包装类型的实例。把字符串传给Object构造函数,就会创建String的实例;传入数值参数会得到Number的实例;传入布尔值参数就会得到Boolean的实例。

注意:使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。

1
2
3
4
5
6
var a = "25";
var b = Number(a);//转型函数
console.log(typeof b);//"number"

var c = new Number(a);//构造函数
console.log(typeof c);//"object"

Boolean类型

  • 创建Boolean对象:var a = new Boolean(ture)
  • Boolean类型改写了toString()、valueOf()方法
  • 布尔表达式中所有对象都会被转换为true

Number类型

  • 重写后的valueOf方法返回对象表示的基本类型的数值
  • 创建:var a = new Nubmer(10);
  • toString() toFixed() toExponential() toPrecision()方法

String类型

  • 创建:var s = new String("Hello world");
  • 方法: 字符方法、字符串操作方法、字符串位置方法、trim()方法、字符串大小写转换方法、字符串模式匹配方法、localeCompare()方法、fromCharCode()方法

part 6 单体内置对象

内置对象的定义:由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。

Global对象

不属于任何其他对象的属性和方法,最终都是它的属性和方法。事实上,没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性。

  • URI编码方法
  • eval()方法
  • Global对象的属性
  • window对象

Math对象

  • Math对象的属性有哪些?
  • min()和max()方法
  • 舍入方法
  • random()方法
  • 其他方法

js的new操作符

发表于 2019-07-17 | 分类于 前端学习

js的new操作符

我们先来了解一下new运算符的基本概念:

new运算符创建一个用户自定义的对象类型的实例或具有构造函数的内置对象的实例。new关键字会进行如下操作:

  1. 先创建一个新的空的简单JavaScript对象(即{})
  2. 然后让这个空对象的_proto_指向函数的原型prototype
  3. 将步骤1创建的对象作为this的上下文(将对象作为函数的this传进去)
  4. 如果该函数没有返回对象,则返回this

再来看一段代码:

1
2
3
4
5
6
7
8
9
function Person(name){
this.name = name;
return name;
}
var person = new Person("Tom");
var person1 = Person("Tom");

console.log(person); //Person { name: 'Tom' }(返回的是构造函数实例化后的对象)
console.log(person1);//Tom

可以看到,有new和没new的区别所在,现在分析一下new做了什么

当代码new Person(...)执行时,会发生以下事情:

  1. 一个继承自Person.prototype的新对象被创建
  2. 使用参数Tom调用构造函数Person,并将this绑定到新创建的对象。
  3. 由构造函数Person返回的对象就是 new 表达式的结果(即构造函数实例化后的对象)。

那要是构造函数返回的是一个对象呢?

1
2
3
4
5
6
function Person(name){
this.name = name;
return {name : "Gates"};
}
var person = new Person("Tom"); //Person{ name: 'Gates'}
var person1 = Person("Tom");//Person{ name: 'Gates'}

可以看到,当函数返回的是对象时,则返回的即为该对象。

可是,当构造函数返回null,undefined等非对象时,情况又是什么样的?

1
2
3
4
5
6
function Person(name){
this.name = name;
return null;
}
var person = new Person("Tom"); //Person{ name: 'Tom'}
var person1 = Person("Tom");//null

可以看到,return null时(当使用new操作符)返回的也是构造函数实例后的对象。这是因为null、undefined为非对象,所以return的其实为this

那,要是没有return语句呢?

1
2
3
4
5
function Person(name) {
this.name = name;
}
var person = new Person("Tom"); //Person{ name: 'Tom'}
var person1 = Person("Tom"); //Undefined

其实,如果在JavaScript没有return语句,那么函数就会默认return this

所以,我们可以得出结论:当我们使用了new操作符时,①构造函数如果没有返回对象,那么这个返回值毫无意义;②构造函数如果返回值为对象,那么这个返回值会被正常使用

接下来,我们再看一个例子:

1
2
3
4
5
6
7
8
9
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
var person = new Person("Tom");
console.log(person.name);//Tom
person.sayName(); //Tom

从这里,我们可以看出new操作符的一些作用:

  • new 通过构造函数Person 创建出来的实例可以访问到构造函数中的属性
  • new 通过构造函数Person 创建出来的实例可以访问到构造函数原型链中的属性,也就是说通过 new 操作符,实例与构造函数通过原型链连接了起来

最后,我们可以自己尝试模拟实现new运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
function create() { //(Con, ...args)函数接收不定量的参数,第一个参数为构造函数,接下来的参数被构造函数使用
var obj = {}; //内部创建一个空对象obj
Con = [].shift.call(arguments);
obj._proto_ = Con.prototype;
//将新对象的内部属性__proto__指向构造函数的原型,这样新对象就可以访问原型中的属性和方法。等同于Object.setPrototypeOf(obj, Con.prototype);
var result = Con.apply(obj, arguments);//使用apply,将构造函数中的this指向新对象,这样新对象就可以访问构造函数中的属性和方法;将obj对象绑定到构造函数上,并且传入剩余参数
return result instanceof Object ? result : obj;//判断构造函数返回值是否为对象,如果为对象就使用构造函数返回的值,否则使用 obj,这样就实现了忽略构造函数返回的原始值
}

function Person(name) {
this.name = name;
}
var person = objectFactory(Person, 'Tom');

参考资料:

  • MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new

  • 通过例子深入了解new:https://www.cnblogs.com/shuaihan/p/7392771.html

  • 一道面试题引发的思考:https://juejin.im/post/5c1bbc16e51d4552e01a0114

  • 聊聊new操作符:https://juejin.im/post/5c7b963ae51d453eb173896e

HTML、CSS面试

发表于 2019-07-15 | 分类于 前端学习

1.了解什么是Web

web即全球广域网,也称万维网。它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统。它有三种表现形式:超文本、超媒体、超文本协议。

2.HTML是什么,HTML5是什么

HTML 不是一门编程语言,而是一种用来告知浏览器如何组织页面的标记语言。它用来构造一个网页的基本骨架,由一系列的元素组成,这些元素可以用来包围不同部分的内容,使其以某种方式呈现或者工作。

html5是html的最新标准。

3.HTML元素标签、属性都是什么概念?

一:标签

标签用来标记内容块,也用来标明元素内容的意义,标签使用尖括号包围,如和,这两个标签表示一个HTML文档。
标签有两种形式:成对出现的标签和单独出现的标签
1、成对出现的标签
成对出现的标签包括开始标签和结束标签,<开始标签>内容</结束标签>
所谓开始标签,及标志一段内容的开始,例如:
<html>表示HTML文档开始了;到</html>结束,从而形成一个HTML文档。
<head>和</head>标签描述HTML文档的相关信息,之间的内容不会在浏览器窗口上显示出来
<body>和</body>标签包含所有要在浏览器窗口上显示的内容,也就是HTML文件的主体部分。
所谓结束标签,是指和开始标签相对的标签。结束标签比开始标签多一个斜杠”/“。
2、单独出现的标签
虽然并不是所有的开始标签都必须有结束标签对应<br><hr><img><input><link><meta>等
3、标签的嵌套
标签可以放在另外一个标签所能影响的片段中,以实现对某一段文档的多重标签效果,但是要注意必须要正确嵌套。

二:元素

标签是为一个元素的开始和结束做标记,网页内容是由元素组成的,一个元素通常由一个开始标签、内容、其他元素及一个结束标签组成。

如<head>和</head>是标签,但是下面的就是一个head元素:

<head><title>HTML中的几个基本概念------标签、元素、属性</title></head>

其中<title></title>是标签,但

<title>HTML中的几个基本概念------标签、元素、属性</title>

又是一个title元素,同时这个title元素又是嵌套在head元素中的另一个元素。

三:属性

与元素相关的特性叫做属性,可以为属性赋值,属性包含元素的额外信息,这些信息不会出现在实际的内容中
①:不定义属性值
HTML规定属性也可以没有值
浏览器会使用compact属性的默认值,但有的属性没有默认值,因此不能省略属性值。

4.文档类型doctype是什么概念,起什么作用?

!DOCTYPE ,是用来声明并帮助浏览器正确识别网页的最短有效声明。因为HTML发展至今有许多的不同版本,所以声明不同的文档类型可以让浏览器完全正确地显示出 HTML 页面。

DOCTYPE是docunment type(文档定义)的简写,用来说明web设计中所用的html或xhtml的类型,指出浏览器或者其他阅读程序按照什么样的规则集去解释文档中的标记.

5.meta标签都用来做什么的?

meta标签提供关于 HTML 文档的元数据。元数据不会显示在页面上,但是对于机器是可读的。
典型的情况是,meta 元素被用于规定页面的描述、关键词、文档的作者、最后修改时间以及其他元数据。
meta标签始终位于 head 元素中。
元数据可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。

6.Web语义化是什么,是为了解决什么问题

简单说来就是让机器可以读懂内容。由编写者对网页内容进行语义化主要可以让不同的人和机器对这段内容的作用和所属有清晰的认识,从而查看或者找到自己需要的内容

Web语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解。如果可以在合适的位置使用恰当的标签,那么写出来的页面语义明确,结构清晰,搜索引擎也可以认出哪些是页面重要内容,予以较高的权值。

web语义化的好处

  1. 去掉或者丢失样式的时候能够让页面呈现出清晰的结构

  2. 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;

  3. 方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;

  4. 便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

7.链接是什么概念,对应什么标签?

HTML 使用超级链接与网络上的另一个文档相连。对应a标签。

超链接使互联网成为互联的网络。超链接使我们能够将我们的文档链接到任何其他文档(或其他资源),也可以链接到文档的指定部分,我们可以在一个简单的网址上提供应用程序(与必须先安装的本地应用程序或其他东西相比)。几乎任何网络内容都可以转换为链接,点击(或激活)超链接将使网络浏览器转到另一个网址(URL)

8.常用标签都有哪些,都适合用在什么场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<a> 用于超链接。< a href="">some text</ a>
<article> 用于一篇文章。< article>a self-contained article</article>
<aside> 用于页面的侧边栏。<aside>some content</aside>
<blockquote> 用于大段的引用内容。< blockquote>some big texts</blockquote>
<body> 页面上显示的所有内容都被包含在<body></body>里
<button> 用于显示一个按钮
<code> 用于一包裹一段代码内容
<dd> 用于一个dl列表的某个dt名词的描述
<del> 用于删除一些不需要的文字
<div> 用于包裹住一些其他的标签,制造一个容器
<dl> 用于制作一个名词和对应解释的列表
<dt> 用于一个dl列表的某个dt名词
<em> 用于强调一些文本内容
<figcaption> 用于一张图表的说明文字
<figure> 用于一张图表
<footer> 用于包裹页面的底部内容
<form> 用于制作一个表单
<h1>-<h6> 用于标记标题,从h1到h6重要性依次递减
<head> 用于包裹页面的元数据,如<meta>, <link>, <title>等
<header> 用于包裹页面的头部内容
<html> 整个 HTML 文档的根元素,包裹住其他所有的元素
<iframe > 用于嵌入另一个小页面到一个页面中
<img> 用于显示一张图片
<input> 用于显示一个表格输入控件
<label> 用于给一个表格输入控件打上一个标签,说明输入控件的作用
<li> 用于<ul>和<ol>标签,代表一个列表项
<link> 用于链接外部CSS文件
<mark> 用于高亮显示某些文本
<meta> 用于下达一些元数据指令,或者对页面进行说明
<nav> 用于包裹住一个导航条的内容
<ol> 用于制作一个有序列表
<p> 用于显示一个段落
<q> 用于一小段引用文字
< script> 用于一段JavaScript脚本代码,或者引入一个外部JavaScript脚本文件
<section> 用于包裹一部分有逻辑关第的页面内容
<select> 用于制作一个下拉列表选框
<span> 用于包裹住一小段文字,作为一个容器
<strong> 用于着重强调重要的文本内容
< style> 用于给页面元素加上样式
< table> 用于制作一个表格
<tbody> 用于表格里的主体部分
<td> 用于表格里的某一个单元格
<textarea> 用于制作一大块文本输入框
<tfoot> 用于表格里的底部
<th> 用于表格里的表头的单元格
<thead> 用于表格里的表头
<time> 用于页面内容中的时间
<title> 用于显示整个页面的标题(显示在浏览器的tab上)
<tr> 用于标记表格里的一行
<ul> 用于制作一个无序列表

9.表单标签都有哪些,对应着什么功能,都有哪些属性

表单元素是允许用户在表单中(比如:文本域,下拉列表,单选框,复选框等等)输入信息的元素,最主要的作用就是收集信息。表单元素是页面中不可缺少的元素。一般来说,表单包含如下几个部分:

  1. 提示信息:表单中包含的说明性文字

  2. 表单控件:包含了具体的表单功能项

  3. 表单域:容纳所有表单控件和提示信息

    常用的表单元素,包括:

  4. form: 定义供用户输入的表单。

  5. fieldset: 定义域。即输入区加有文字的边框。

  6. legend:定义域的标题,即边框上的文字。

  7. label:定义一个控制的标签。如输入框前的文字,用以关联用户的选择。

  8. input: 定义输入域,常用。可设置type属性,从而具有不同功能。

  9. textarea: 定义文本域(一个多行的输入控件),默认可通过鼠标拖动调整大小。

  10. button: 定义一个按钮。

  11. select: 定义一个选择列表,即下拉列表。

  12. option: 定义下拉列表中的选项。

    接下来是对这些表单元素的具体分析。

    <form name="" action="" method="get">……</form>
    name : 表单名称;action : 用来指定表单处理程序的位置(url);method : 定义表单结果从浏览器传送到服务器的方式,默认为”get”(也可以是post)
    <input type="" name="" value="" size="">
    name:控件名称;value:input控件默认文本值;size:input控件在页面中的显示宽度(必须是正整数)
    input常用type属性如下:

  13. text:单行文本输入框,可以通过正整数的size控制框长度。

  14. password:密码输入框。

  15. radio:单选按钮,同一组的单选按钮必须要有相同的name。

  16. checkbox:复选框,同一组的单选按钮必须要有相同的name。

  17. button:普通按钮。

  18. submit:提交按钮,每出现一次,一个 Submit 对象就会被创建。

  19. reset:重置按钮,会重置当前表单中全部的内容。

  20. image:图像形式的提交按钮,写法是“”。

  21. hidden:隐藏域,隐藏字段对于用户是不可见的。

  22. file:文件域,用于文件上传。

    <selectt size="" multiple="multiple">
    <option hidden>选项1</option>
    size:下拉菜单的可见选项数;multiple:多选。
    在最新的html5中,有一些表单的新增属性,多用于js,如
    datalist : 定义填写一个input时,提示几个option用于提示。可通过input的list特性与此元素作关联。
    output : 表示计算的结果。可通过for特性与其它能够影响运算的元素(如input)作关联。
    还有一些新增的type属性:

  23. search:input会呈现为搜索框(与text类型的唯一区别在于当鼠标覆盖时尾部出现叉号可快速清除输入的内容)。

  24. url:编辑url的控件,提交时换行符与首位的空格都将自动去除。

  25. email:可输入一个邮件地址。

  26. color : 选择颜色的控件。

  27. date : 选择年月日的控件。
    此外,还有time、datetime、datetime-local、month、week、number、range类型

10.ol, ul, li, dl, dd, dt等这些标签都适合用在什么地方,举个例子

ol为有序列表,即为一个需要排序的列表内容进行排列; (问路)
ul为无序列表,即为一个需要列表但不需要排顺序的内容排列; (早点清单)
li为列表的内容; 
dl为定义列表; 
dt为定义列表内的标题或项目名称; 
dd为定义定义列表中项目的描述(独白旁白)

CSS

1.CSS选择器类型、优先级

  1.标签选择器(如:body,div,p,ul,li)

  2.类选择器(如:class=”head”,class=”head_logo”)

  3.ID选择器(如:id=”name”,id=”name_txt”)

  4.全局选择器(如:*号)

  5.组合选择器(如:.head .head_logo,注意两选择器用空格键分开)

  6.后代选择器 (如:#head .nav ul li 从父集到子孙集的选择器)

  7.群组选择器 div,span,img {color:Red} 即具有相同样式的标签分组显示

  8.继承选择器(如:div p,注意两选择器用空格键分开)

  9.伪类选择器(如:就是链接样式,a元素的伪类,4种不同的状态:link、visited、active、hover。)

  10.字符串匹配的属性选择符(^ $ *三种,分别对应开始、结尾、包含)

  11.子选择器 (如:div>p ,带大于号>)

  12.CSS 相邻兄弟选择器器 (如:h1+p,带加号+)

总结排序:!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

2.CSS继承,层叠,样式优先级机制

当多个相互冲突的CSS声明应用于同一个元素时,CSS层叠算法会根据一定的机制,从最高权重到最低权重的顺序列出

在CSS中,每个CSS属性定义的概述都指出了这个属性是默认继承的还是默认不继承的。这决定了当你没有为元素的属性指定值时该如何计算值。当元素的一个

继承属性没有指定值时,则取父元素的同属性的计算值。只有文档根元素取该属性的概述中给定的初始值;当元素的一个非继承属性没有指定值时,则取属性的初始值。

3.文本,边框,背景,行高等相关属性

border:1px solid red;

background-color: cornflowerblue;

background-image: url(‘1.jpg’);

background-repeat: no-repeat;(repeat:平铺满)

background-position: right(左右距离) top(上下距离)(20px 20px);(横向:left center right)(纵向:top center bottom)

简写:< body style=”background: 20px 20px no-repeat #ff4 url(‘1.jpg’)”>

< div style=”width: 300px;height: 300px;background: 20px 20px no-repeat #ff4 url(‘1.jpg’)”>

4.块状元素,内联元素和内联块状元素的概念

块级元素特点:

1
<div>、<p>、<h1>-<h6>、<ol>、<ul>、<dl>、<table>、<address>、<blockquote> 、<form>

1、每个块级元素都从新的一行开始,并且其后的元素也另起一行。

2、元素的高度、宽度、行高以及顶和底边距都可设置。

3、元素宽度在不设置的情况下,是它本身父容器的100%(和父元素的宽度一致)。默认高度等于子元素高度。父子均是块级元素时,子块的高度可能冲破父级的限制

内联元素特点:

1
<a>、<span>、<br>、<i>、<em>、<strong>、<label>、<q>、<var>、<cite>、<code>

1.和其他内联元素都在一行上;

2.可以通过margin、padding来改变左右的距离,但不可以改变上下的距离,导致width、height、line-height失效或。可以使用border。

3.内联元素之间有空白区域,空白区域的形成是因为之间有回车,在html中,空格、制表符、回车都属于空白符,多个空白符都会视为一个空格,空格的大小由父级

的font-size决定。注意:只有内联(内联块)与内联(内联块)之间的空白符才会形成一个空格,文本元素(除空白符)也是属于内联元素。常用解决方法,给
设置font-size: 0;,在上把font-size设置回去

inline-block 元素特点:

1
<img>、<input>

1.和其他元素都在一行上;

2.元素的高度、宽度、行高以及顶和底边距都可设置。

3.它也会有元素间出现空白区域的问题

5.盒模型的所有概念,学习如何计算各种盒模型

IE盒子:宽高包括padding和border

W3C盒子:宽高为content的宽高

如果想要切换盒模型也很简单,这里需要借助css3的box-sizing属性

  • box-sizing: content-box 是W3C盒子模型
  • box-sizing: border-box 是IE盒子模型

6.position的相关知识,position有几种,absolute和relative的区别

position: static | relative | absolute | fixed | sticky

  • static

    该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index属性无效

  • relative

    ​ 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。

    ​ 相对定位的元素是在文档中的正常位置偏移给定的值,但是不影响其他元素的偏移,未脱离文档流。(其他元素的位置不会受该元素的影响发生位置改变来弥补该元素偏移后剩下的空隙)

  • absolute

    不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并,脱离了文档流。

  • fixed

    固定定位与绝对定位相似,但元素的包含块为 viewport 视口。该定位方式常用于创建在滚动屏幕时仍固定在相同位置的元素。

    不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。

  • sticky

    盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky对 table 元素的效果与 position: relative相同。

    粘性定位可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。

7.float的相关知识

float CSS属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。该元素从网页的正常流动(文档流)中移除,尽管仍然保持部分的流动性(与绝对定位相反)。

当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。


对于浮动,需要了解的是:

*浮动会将元素从文档流中删除,他的空间会被其它元素补上。

*浮动的参数物是父元素,是在父元素这个容器中飘。

*为了清除浮动造成的对浮动元素之后元素的影响,我们在浮动元素之后加一个div,并将这个div的clear设置为both。

*如果两个元素都设置了浮动,则两个元素并不会重叠,第一个元素占据一定空间,第二个元素紧跟其后。如果不想让第二个元素紧跟其后,可以对第二个浮动的元素使用clear。


浮动元素是 float 的计算值非 none 的元素。

8.基本的布局方式

固定布局、流式(百分比)布局、弹性布局、浮动布局、定位布局

9.Grid,Flexbox等布局方式

弹性布局是指通过调整其内元素的宽高,从而在任何显示设备上实现对可用显示空间最佳填充的能力。弹性容器扩展其内元素来填充可用空间,或将其收缩来避免溢出。

这二者都是 CSS 工作组为在不同用户代理、不同书写模式和其他灵活性要求下的网页应用程序有更好的互操作性而做出的更广泛的努力的一部分。都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。flex主要适用于应用程序的组件及小规模的布局,而(新兴的)栅格布局则针对大规模的布局。

Flex 布局是轴线布局,只能指定”项目”针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成”行”和”列”,产生单元格,然后指定”项目所在”的单元格,可以看作是二维布局。它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。

10.神马圣杯布局、双飞翼布局都是些什么东西

11.强大的负外边距都能干嘛

1
影响元素在文档流中的位置、增加元素宽度、对浮动元素的影响、对居中的影响

12.display的几个属性,及其区别

  • inline:
    1. 使元素变成行内元素,拥有行内元素的特性,即可以与其他行内元素共享一行,不会独占一行.
    2. 不能更改元素的height,width的值,大小由内容撑开.
    3. 可以使用padding,margin的left和right产生边距效果,但是top和bottom就不行.
  • block:
    1. 使元素变成块级元素,独占一行,在不设置自己的宽度的情况下,块级元素会默认填满父级元素的宽度.
    2. 能够改变元素的height,width的值.
    3. 可以设置padding,margin的各个属性值,top,left,bottom,right都能够产生边距效果.
  • inline-block:
    1. 结合了inline与block的一些特点,结合了上述inline的第1个特点和block的第2,3个特点.

13.display:none与visibility:hidden的区别

1
display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;

14.浏览器清除浮动的方式及其原理

1》添加额外的标签:在浮动元素末尾添加一个空的标签例如 < div style=”clear:both”>,其他标签br等亦可

2》使用 br标签和其自身的 html属性:< br clear=”all” />

3》父元素设置 overflow:hidden

4》父元素设置 overflow:auto 属性

5》父元素也设置浮动

6》父元素设置display:table

7》使用 :after 伪元素

1
`.clearfix:after {content:"."; display:block; height:0; visibility:hidden; clear:both; }.clearfix { *zoom:1; }`

15.BFC

(1).BFC的特性:

​ ①块级格式化上下文会阻止外边距叠加

​ ②块级格式化上下文不会重叠浮动元素

​ ③块级格式化上下文通常可以包含浮动

创建了 BFC的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素,反之亦然,同时BFC任然属于文档中的普通流。

2.触发BFC的条件

  1、float 除了none以外的值

  2、overflow 除了visible 以外的值(hidden,auto,scroll )

  3、display (table-cell,table-caption,inline-block)

  4、position(absolute,fixed)

  5、fieldset元素

16.src与href的区别

href表示超文本引用。用来建立当前文档和引用资源之间的链接。常用的有:link、a。
src是source的缩写,是引入。src指向的内容会嵌入到文档中当前标签所在的位置。常用的有:img、script、iframe 
简而言之,src用于替换当前元素;href用于在当前文档和引用资源之间建立联系。

17.px、em、rem的区别

都是用于设置字体的大小以及盒子的宽高,但是px不会因为浏览器尺寸的改变而改变,而em和rem会因为浏览器尺寸的变化而变化
像素是相对于显示器屏幕分辨率而言的
em是一个相对长度的单位,是相对于当前对象内文本的字体尺寸。如过我们未设置当前文本的字体尺寸,那么em就会相对于浏览器的默认字体尺寸, em大小不是固定的,会继承父级元素的字体大小。
rem相对的只是HTML根元素,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

18.为什么要使用css sprites

CSS Sprites其实就是把网页中一些[背景图片]整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字能精确的定位出[背景图片]的位置。
当页面加载时,不是加载每个单独图片,而是一次加载整个组合图片。这是一个了不起的改进,它大大减少了[HTTP请求]的次数,减轻服务器压力,同时缩短了悬停加载图片所需要的时间延迟,使效果更流畅,不会停顿。
缺点:就是在拼图时,比较麻烦,还有后期维护也比较麻烦,比如做好的图,然后一个图标改了大小,但是图标之间留的位置不够,那你就要重写很多css。因为每次的图片改动都得往这个图片删除或添加内容,显得稍微繁琐

19.什么是CSS及CSS怎么运作

CSS (Cascading Style Sheets) 是用来样式化和排版你的网页的 
—— 例如更改网页内容的字体、颜色、大小和间距,将内容分割成多列或者加入动画以及别的装饰型效果。是一种用于向用户指定文档如何呈现的语言。
Web浏览器将CSS规则应用于文档以影响它们的显示方式。

20.居中

居中.xmind

JavaScript面试2

发表于 2019-07-15 | 分类于 前端学习

1.你觉得js是一门怎样的语言,它与你学过的其他语言有什么不同

javaScript

​ 一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML网页上使用,用来给HTML网页增加动态功能。JavaScript兼容于ECMA标准,因此也称为ECMAScript。

Javascript的特点:

一、简单性:

JavaScript是一种基于Java基本语句和控制流之上的简单而紧凑的设计,从而对于学习Java是一种非常好的过渡。它的变量类型是采用弱类型,并未使用严格的数据类型。

二、动态性:

avaScript是动态的,它可以直接对用户或客户输入做出响应,无须经过Web服务程序。它对用户的反映响应,是采用以事件驱动的方式进行的。所谓事件驱动,就是指在主页(Home Page)中执行了某种操作所产生的动作,就称为“事件”(Event)。比如按下鼠标、移动窗口、选择菜单等都可以视为事件。当事件发生后,可能会引起相应的事件响应。

三、跨平台性:

JavaScript是依赖于浏览器本身,与操作环境无关,只要能运行浏览器的计算机,并支持JavaScript的浏览器就可正确执行。从而实现了“编写一次,走遍天下”的梦想。

四、安全性:

JavaScript是一种安全性语言,它不允许访问本地的硬盘,并不能将数据存入到服务器上,不允许对网络文档进行修改和删除,只能通过浏览器实现信息浏览或动态交互。从而有效地防止数据的丢失。

2。从静态类型还是动态类型来看

静态类型,编译的时候就能够知道每个变量的类型,编程的时候也需要给定类型,如Java中的整型int,浮点型float等。C、C++、Java都属于静态类型语言。

动态类型,运行的时候才知道每个变量的类型,编程的时候无需显示指定类型,如JavaScript中的var、PHP中的$。JavaScript、Ruby、Python都属于动态类型语言。

静态类型还是动态类型对语言的性能有很大影响。

对于静态类型,在编译后会大量利用已知类型的优势,如int类型,占用4个字节,编译后的代码就可以用内存地址加偏移量的方法存取变量,而地址加偏移量的算法汇编很容易实现。

对于动态类型,会当做字符串通通存下来,之后存取就用字符串匹配。

从编译型还是解释型来看

编译型语言,像C、C++,需要编译器编译成本地可执行程序后才能运行,由开发人员在编写完成后手动实施。用户只使用这些编译好的本地代码,这些本地代码由系统加载器执行,由操作系统的CPU直接执行,无需其他额外的虚拟机等。

源代码=》抽象语法树=》中间表示=》本地代码

解释性语言,像JavaScript、Python,开发语言写好后直接将代码交给用户,用户使用脚本解释器将脚本文件解释执行。对于脚本语言,没有开发人员的编译过程,当然,也不绝对。

源代码=》抽象语法树=》解释器解释执行。

对于JavaScript,随着Java虚拟机JIT技术的引入,工作方式也发生了改变。可以将抽象语法树转成中间表示(字节码),再转成本地代码,如JavaScriptCore,这样可以大大提高执行效率。也可以从抽象语法树直接转成本地代码,如V8

​ Java语言,分为两个阶段。首先像C++语言一样,经过编译器编译。和C++的不同,C++编译生成本地代码,Java编译后,生成字节码,字节码与平台无关。第二阶段,由Java的运行环境也就是Java虚拟机运行字节码,使用解释器执行这些代码。一般情况下,Java虚拟机都引入了JIT技术,将字节码转换成本地代码来提高执行效率。

注意,在上述情况中,编译器的编译过程没有时间要求,所以编译器可以做大量的代码优化措施。

对于JavaScript与Java它们还有的不同:

对于Java,Java语言将源代码编译成字节码,这个同执行阶段是分开的。也就是从源代码到抽象语法树到字节码这段时间的长短是无所谓的。

对于JavaScript,这些都是在网页和JavaScript文件下载后同执行阶段一起在网页的加载和渲染过程中实施的,所以对于它们的处理时间有严格要求

2.js基本数据类型

字符串值,数值,布尔值,数组,undefined,null,对象。
基本类型数据
1.基本数据类型值是指简单的数据段,五种基本类型都是按值访问的(可以操作保存在变量中的实际值);
2.基本类型的值在内存中占据固定大小的空间,被保存在栈内存中。(从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本);
3.不能给基本类型的值添加属性。
引用类型数据:object(还有array、function)
1.引用类型值是指那些可以由多个值构成的对象。js不允许直接访问内存中的位置,也就是不能直接访问操作对象的内存空间,在操作对象时,实际上是在操作对象的引用而不是实际的对象;
2.引用类型的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终指向同一个对象。
3.对于引用类型的值,可以为其添加属性和方法,也可以改变和删除其属性和方法。
4.在ECMAScript中用var关键字来定义变量,因为js是弱类型的,所以无法确定变量一定会存储什么值,也就不知道变量到底会是什么类型,而且变量的类型可以随时改变。这就是ECMAScript是松散类型的来由,所谓松散类型就是可以用来保存任何类型的数据。
在es6中新增了let命令来声明变量,const命令声明一个只读的常量
let的用法类似于var,但是所声明的变量,只有在let代码块内才有效;const一旦声明,常量的值就不能改变。

https://www.cnblogs.com/zhengyeye/p/6485124.html

3.js如何判断变量数据类型

typeof(typeof的局限性在于 数组、对象、null都为object;typeof运算符把函数返回function)、instanceof([1,2] instanceof Array 只对数组有用)、Array.isArray()方法确定某个值是否为数组、Object.prototype.toString.call()(最理想,能够十分准确检测出全部类型)、constructor(引用了初始化该对象的构造函数来判断 ((“123”).constructor === String)

4.类数组和数组

类数组定义
1)拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);
2)不具有数组所具有的方法;
javascript中常见的类数组有 arguments对象和 DOM方法的返回结果。比如 document.getElementsByTagName()。

判断是否是类数组

1
2
3
4
5
function isLikeArray(o) {
if(typeof o === 'object'&& isFinite(o.length) && o.length >= 0 && o.length < 4294967296){// 4294967296: 2^32
return true} else{
return false}
}

5.将类数组转换为数组

  1. 创建一个新的数组,然后将将类数组中的元素添加到新数组里面
  2. Array.prototype.slice.call()
  3. Array.form(arguments)

6.如何遍历数组

1.普通for循环

1
2
3
4
5
6
for(var i = 0; i < arr.length; i++){
}
for(var i = 0,len = arr.length; i < len; i++){
}
for(var i = 0; arr[i] != null; i++){
}

2.for in 循环

1
2
for(i in arr){
}

3.forEach循环

1
2
3
arr.forEach(function(e){
});
//数组自带的foreach循环,使用频率较高,实际上性能比普通for循环弱

4.map遍历

1
2
arr.map(function(n)){
});

5.for of 遍历

1
2
3
for (let value of arr){
});
//这种方式是es6里面用到的,性能好于for in,但仍比不上普通for循环

https://blog.csdn.net/function__/article/details/79555301

7.ARRAY常用方法

push(),pop(),shift(),unshift(),splice(),sort(),reverse(),map(),forEach(),isArray(),toString()等

8.STRING常用方法

toUpperCase():把一个字符串全部变为大写

toLowerCase():把一个字符串全部变为小写

indexOf():会搜索制定字符串出现的位置,有返回索引,没有返回-1

substring():返回制定索引区间的子串(传一个参数的话表示从该参数索引位置开始到结束;传两个参数的话表示从开始索引到结束索引)

slice():使用与substring()基本相同,可以传负数,负数则从字符串尾部算起;substring()不能传负数

substr():用法与上面两个相似,但是第二个参数表示截取的字符串最大长度(三种字符串截取方法,未填第二参数时,自动截取起始位置到字符串末尾)

toString():可以将其他数据类型转换为字符串

split():对字符串进行分割,返回一个数组(如果只传一个参数则表示以哪个字符进行分割;传两个参数的话第二个参数表示返回的字符串数组的最大长度)

replace():字符串替换,默认只进行第一次匹配操作的替换,想要全局替换,需要加上正则全局标识g。例:

1
2
3
4
    var mystr="wozaijinxingzifuchuantihuancaozuo,zifuchuantihuano";
    var replaceStr=mystr.replace("zifuchuan"," "); //wozaijinxing tihuancaozuo,zifuchuantihuano
    var replaceStr=mystr.replace(/zifuchuan/," "); //wozaijinxing tihuancaozuo,zifuchuantihuano
    var replaceStr=mystr.replace(/zifuchuan/g," "); //wozaijinxing tihuancaozuo, tihuano

length:获取字符串长度

indexOf():查询子字符串,对大小写敏感,返回字符串中子串第一处出现的索引(从左到右)。如果没有匹配项,返回-1。

lastIndexOf():查询子字符串,对大小写敏感,返回字符串中子串第一处出现的索引(从右到左)。如果没有匹配项,返回-1。

charAt():返回制定位置的字符

match():字符串匹配。若有相匹配的字符,则返回所要匹配的字符串;没有相匹配的,返回null(也可定义一个变量为正则表达式进行匹配)

exec():字符串匹配。与match()效果相同,用法相反

search():进行正则匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回-1

trim():删除字符串前后的空格

9.DOM 事件级别

dom0级事件就是在js中写到 element.onclick=function(){},是一种比较传统的方式:把一个函数(或者匿名函数)赋值给一个事件的处理程序属性。

优势(兼容所有浏览器)

缺点:不能给元素添加多个事件处理程序,只能添加一个,如果添加多个事件处理程序,后面的会覆盖前面的

2 DOM1级主要是映射文档,没有事件。

3 DOM2级事件 element.addEventListerner(‘click’,function(){},false) false指的是冒泡,早期浏览器都支持冒泡,为了兼容基本上最后一个参数都是false.

删除事件:element.removeEventListener(‘click’,function(){},false),这样的删除方式只能删除DOM2级添加的事件。删除的时候传递的参数必须跟添加时传递的参数一样才能正确删除事件。

优点,可以给元素添加多个事件处理程序,这些事件处理程序按照他们的顺序执行。

4 Dom3级事件跟dom2级事件写法一样的,只是增加了许多事件类型,包括点击事件和键盘事件。

10.DOM 事件类型

Web浏览器中可能发生的事件有很多类型。不同的事件类型具有不同的信息,而“DOM3级事件”规定了以下几类事件:

  • UI(用户界面)事件,当用户与界面上的元素交互时触发
  • 焦点事件,当元素获得或失去焦点时触发
  • 鼠标事件,当用户通过鼠标在页面上执行操作时触发
  • 滚轮事件,当使用鼠标滚轮时触发
  • 文本事件,当在文档中输入文本时触发
  • 键盘事件,当用户通过键盘在页面上执行操作时触发
  • 合成事件,当为IME输入字符时触发
  • 变动事件,当底层DOM结构发生变化时触发

11.DOM 事件流

什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。
事件捕获阶段
处于目标阶段
事件冒泡阶段

首先发生的是事件捕获,为截获事件提供了机会;然后是实际的目标接收到事件;最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
IE只支持事件冒泡。

img12.描述一下冒泡/事件捕获的具体流程

1.事件冒泡:即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

2.事件捕获:思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。

13.html、dom0、dom2是如何注册事件

1.在html代码元素中添加事件为Html事件。

1
<input type="button" value="按钮" id="btn1" onclick="showMess()"/>

2.使用元素的onclick方法为DOM0级事件处理。

1
btn2.onclick=null;

3.使用事件添加方法为元素添加事件(

1
2
chrome:addEventListener,removeEventListener
IE:attachEvent,detachEvent

)为DOM2级事件处理。

14.事件流

JavaScript高级程序设计–p345

15.事件委托(代理)

https://www.jianshu.com/p/a77d8928c5c9

16.自定义事件

 1.Event() 构造函数, 创建一个新的事件对象 Event
 2.CustomEvent() 创建一个自定义事件
 3.document.createEvent() 创建一个新的事件(Event),随之必须调用自身的 init 方法进行初始化
4.https://www.cnblogs.com/shapeY/p/7923353.html

17.怎么防止冒泡

1
2
3
4
5
6
7
8
9
function stopBubble(e) { 
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}

阻止默认行为

http://caibaojian.com/javascript-stoppropagation-preventdefault.html

1
2
3
4
5
6
7
8
9
10
//阻止浏览器的默认行为 
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}

18.谈谈innerHTML、 nodeValue与 textContent之间的区别

nodeValue:是节点的值

innerHTML:浏览器会将内容解析为HTML代码

textContent:使用纯文本而不是解析为HTML

19.简单说一下DOM操作中如何查找元素

document.getElementById(id) 通过元素 id 来查找元素

document.getElementsByTagName(name) 通过标签名来查

document.getElementsByClassName(name) 通过类名来查

document.getElementsByName();//name属性值,一般不用

* 通过css选择器查找HTML元素 (document.querySelector()返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回null)

* 通过HTML对象选择器查找HTML对象

20.dom节点获取,及其特性

通过 JavaScript,您可以使用以下节点属性在节点之间导航:

parentNode

childNodes[nodenumber]

firstChild

lastChild

nextSibling

previousSibling

21.如果一个 ul 下面有 5个 li 如何给他们添加点击事情的方法

js为li列表添加点击事件 - caoPengFlying的博客 - CSDN博客

JS中for循环出现的问题:如何给li元素绑定事件,点击每个li元素弹出对应的 - 骆小胖~ - CSDN博客

22.window document 对象是什么?

window对象

代表浏览器中的一个打开的窗口或者框架,window对象会在或者每次出现时被自动创建,在客户端JavaScript中,Window对象是全局对象,所有的表达式都在当前的环境中计算,要引用当前的窗口不需要特殊的语法,可以把那个窗口属性作为全局变量使用,例如:可以只写document,而不必写window.document。同样可以把窗口的对象方法当做函数来使用,如:只写alert(),而不必写window.alert

window对象实现了核心JavaScript所定义的全局属性和方法。

indow对象的window属性和self属性引用都是他自己。

document对象

代表整个HTML文档,可以用来访问页面中的所有元素 。

每一个载入浏览器的HTML文档都会成为document对象。document对象使我们可以从脚本中对HTML页面中的所有元素进行访问。
document对象是window对象的一部分可以通过window.document属性对其进行访问
HTMLDocument接口进行了扩展,定义HTML专用的属性和方法,很多属性和方法都是HTMLCollection对象,其中保存了对锚、表单、链接以及其他可脚本元素的引用。

23.setTimeout 和 setInteval 的区别和使用方法

https://blog.csdn.net/HandSome_He/article/details/81676640

24.异步同步

异步

如果在函数返回的时候,调用者还不能购得到预期结果,而是将来通过一定的手段得到(例如回调函数),这就是异步。例如ajax操作。
如果函数是异步的,发出调用之后,马上返回,但是不会马上返回预期结果。调用者不必主动等待,当被调用者得到结果之后会通过回调函数主动通知调用者。

同步

如果在函数返回结果的时候,调用者能够拿到预期的结果(就是函数计算的结果),那么这个函数就是同步的.如果函数是同步的,即使调用函数执行任务比较耗时,也会一致等待直到得到执行结果。

25.如何实现页面跳转

第一种:直接跳转加参数

1
2
    <script language="javascript" type="text/javascript">           window.location.href="login.jsp?backurl="+window.location.href;
</script>

直接跳转无参数:

1
<script>window.location.href='http://www.baidu.com';</script>

第二种:返回上一次预览界面

1
<script language="javascript">alert("返回");window.history.back(-1);</script>标签嵌套:
1
<a href="javascript:history.go(-1)">返回上一步<a><a href="<%=Request.ServerVariables("HTTP_REFERER")%>">返回上一步</a>

第三种:指定跳转页面 对框架无效。。。

1
<script language="javascript">       window.navigate("top.jsp");  </script>

第四种:指定自身跳转页面 对框架无效。。

1
<script language="JavaScript">          self.location='top.htm';   </script>

第五种:指定自身跳转页面 对框架有效。。

1
<script language="javascript">          alert("非法访问!");          top.location='xx.aspx';   </script>

第六种:按钮式 在button按钮添加 事件跳转。。

1
<input name="pclog" type="button" value="GO" onClick="location.href='login.aspx'">

第七种:在新窗口打开:

1
 <a href="javascript:" onClick="window.open('login.aspx','','height=500,width=611,scrollbars=yes,status=yes')">开新窗口</a>

26.children 和 childNodes 的区别

childNodes:获取节点,不同浏览器表现不同;

  IE:只获取元素节点;

  非IE:获取元素节点与文本节点;

  解决方案:if(childNode.nodeName==”#text”) continue 或者 if(childNode.nodeType != ‘3’) continue

2、children:获取元素节点,浏览器表现相同。

  因此建议使用children。

27.如何实现insertAfter

parent.insertBefore(newElement,targetElement.nextSibling)他的三部分为 父节点 新节点 目标节点 他会把新节点创建在目标节点之前 需要注意的是 父节点并无需获取 你通过目标节点.parentNode就可以获取
但是js并没有提供插入在目标节点之后的方法 我们可以自己写一个

1
2
3
4
5
6
function insertAfter(newElement,targetElement) {
var parent = targetElement.parentNode;
if(parent.lastChild == targetElement){
parent.appendChild(newElement);
} else { parent.insertBefore(newElement,targetElement.nextSibling);
}

首先 他把目标节点的父节点找到包装在parent里 然后进行对比 如果这个父节点的最后一个节点是目标节点 那么无需插入在中间 因为appendChild默认就是将节点插入到末尾

如果不是 目标节点游在中间 那么他会调用Before方法 把新节点插入到 目标节点的后面一个节点之前 其实也就是他的节点之后 绕了一点

28.变量提升

JavaScript 变量提升 - 云+社区 - 腾讯云

29.执行环境与作用域

https://www.jb51.net/article/83585.htm

30.克隆对象

31.this以及修改this

https://www.cnblogs.com/yummylucky/p/10225066.html

32.call和apply区别

通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2…这种形式(两者区别仅在于接收参数的方式不同。apply()方法第二个参数可以是Array的实例也可以是argument对象,call()方法必须明确地传入每一个参数)。通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。

apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。

call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。

bind除了返回是函数以外,它的参数和call一样。

33.闭包

一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。

(1)什么是闭包: 闭包是指有权访问另外一个函数作用域中的变量的函数。闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。

(2)为什么要用: 匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。 结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。

34.js运行机制

https://www.baidu.com/link?url=HbzsQy4I1L5Y8RWr5NEReBaQkfm4vCCrb7qa9KYGo0tAglavxUxtAFUCZ2uxKxsEFl3ToD2XukSuaPtSDSDgcWGQmN2PlrmRRrj-ZRpq7g7&wd=&eqid=bfa5949d0000d54b000000065d294ed0

35.js对象的创建方法

js中对象与对象创建方法的各种方法_javascript技巧_脚本之家

36.原型链

JS重点整理之JS原型链彻底搞清楚 - sinat_21274091的博客 - CSDN博客

37.对象的继承机制

详解JavaScript对象继承方式 - 雨霖月寒 - 博客园

38.JS垃圾回收机制

面试题——js垃圾回收机制和引起内存泄漏的操作 - yingzizizizizizzz的专栏 - CSDN博客

JavaScript面试1

发表于 2019-07-15 | 分类于 前端学习

面试

几个很实用的BOM属性对象方法?

Bom是浏览器对象。
(1)location对象
location.href– 返回或设置当前文档的URL
location.search – 返回URL中的查询字符串部分。例 如http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu返回包括(?)后面的内容?id=5&name=dreamdu
location.hash – 返回URL#后面的内容,如果没有#,返回空
location.host – 返回URL中的域名部分,例如[www.dreamdu.com](http://www.dreamdu.com)
location.hostname – 返回URL中的主域名部分,例如dreamdu.com
location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/
location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080
location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/返回(//)前面的内容http:
location.assign – 设置当前文档的URL
location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL
location.replace(url);
location.reload() – 重载当前页面
(2)history对象
history.go() – 前进或后退指定的页面数 history.go(num);
history.back() – 后退一页
history.forward() – 前进一页
(3)Navigator对象
navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)
navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie

Doctype作用?严格模式与混杂模式如何区分?它们有何意义?

Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。
严格模式的排版和JS 运作模式是 以该浏览器支持的最高标准运行。
混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。

click在ios上有300ms延迟,原因及如何解决?

(1)粗暴型,禁用缩放
< meta name=”viewport” content=”width=device-width, user-scalable=no”>
(2)利用FastClick,其原理是:
检测到touchend事件后,立刻出发模拟click事件,并且把浏览器300毫秒之后真正出发的事件给阻断掉

addEventListener参数

addEventListener(event, function, useCapture)
其中,event指定事件名;function指定要事件触发时执行的函数;useCapture指定事件是否在捕获或冒泡阶段执行。

前端优化

降低请求量:合并资源,减少HTTP 请求数,minify / gzip 压缩,webP,lazyLoad。
加快请求速度:预解析DNS,减少域名数,并行加载,CDN 分发。
缓存:HTTP 协议缓存请求,离线缓存 manifest,离线数据缓存localStorage。
渲染:JS/CSS优化,加载顺序,服务端渲染,pipeline。

GET和POST的区别

get和post是http常见的请求方法,还有很多比如patch、delete、put、options等等
get参数通过url传递,post放在request body中。
get请求在url中传递的参数是有长度限制的,而post没有。
get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
get请求只能进行url编码,而post支持多种编码方式
get请求会浏览器主动cache,而post支持多种编码方式。
get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
GET产生一个TCP数据包;POST产生两个TCP数据包。

说一下浏览器缓存

缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。
强缓存相关字段有expires,cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match 

浏览器在生成页面的时候,会生成那两颗树?

构造两棵树,DOM树和CSSOM规则树.当浏览器接收到服务器相应来的HTML文档后,会遍历文档节点,生成DOM树,CSSOM规则树由浏览器解析CSS文件生成, 

怎么看网站的性能如何

检测页面加载时间一般有两种方式,一种是被动去测:就是在被检测的页面置入脚本或探针,当用户访问网页时,探针自动采集数据并传回数据库进行分析,另一种主动监测的方式,即主动的搭建分布式受控环境,模拟用户发起页面访问请求,主动采集性能数据并分析,在检测的精准度上,专业的第三方工具效果更佳,比如说性能极客 

浏览器输入网址到页面渲染全过程

DNS解析 TCP连接发送 HTTP请求服务器 处理请求并返回HTTP报文 浏览器解析渲染页面 连接结束 

HTML5和CSS3用的多吗?你了解它们的新属性吗?有在项目中用过吗?

html5:
1)标签增删
8个语义元素 header section footer aside nav main article figure
内容元素mark高亮 progress进度
新的表单控件calander date time email url search
新的input类型 color date datetime datetime-local email
移除过时标签big font frame frameset
2)canvas绘图,支持内联SVG。支持MathML
3)多媒体audio video source embed track
4)本地离线存储,把需要离线存储在本地的文件列在一个manifest配置文件
5)web存储。localStorage、SessionStorage
css3:
CSS3边框如border-radius,box-shadow等;CSS3背景如background-size,background-origin等;CSS3 2D,3D转换如transform等;CSS3动画如animation等。

link标签和@import标签的区别

link属于html标签,而@import是css提供的
页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
link方式样式的权重高于@import的。 

transition和animation的区别

animation和transition大部分属性是相同的,他们都是随时间改变元素的属性值,他们的主要区别是transition需要触发一个事件才能改变属性,而animation不需要触发任何事件的情况下才会随时间改变属性值,并且transition为2帧,从from .... to,而animation可以一帧一帧的。 

BFC(块级格式化上下文,用于清楚浮动,防止margin重叠等)

直译成:块级格式化上下文,是一个独立的渲染区域,并且有一定的布局规则。
BFC区域不会与float box重叠
BFC是页面上的一个独立容器,子元素不会影响到外面
计算BFC的高度时,浮动元素也会参与计算
那些元素会生成BFC:
根元素
float不为none的元素
position为fixed和absolute的元素
display为inline-block、table-cell、table-caption,flex,inline-flex的元素
overflow不为visible的元素 

visibility=hidden, opacity=0,display:none

opacity=0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的visibility=hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样。

双边距重叠问题(外边距折叠)

多个相邻(兄弟或者父子关系)普通流的块元素垂直方向marigin会重叠
折叠的结果为:
两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
两个外边距一正一负时,折叠结果是两者的相加的和。 

position属性 比较

固定定位fixed:
元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed定位使元素的位置与文档流无关,因此不占据空间。 Fixed定位的元素和其他元素重叠。
相对定位relative:
如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
绝对定位absolute:
绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于<html>。 absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠。
粘性定位sticky:
元素先按照普通文档流定位,然后相对于该元素在流中的flow root(BFC)和 containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
默认定位Static:
默认值。没有定位,元素出现在正常的流中(忽略top, bottom, left, right 或者 z-index 声明)。
inherit:
规定应该从父元素继承position 属性的值。 

z-index的定位方法

z-index属性设置元素的堆叠顺序,拥有更好堆叠顺序的元素会处于较低顺序元素之前,z-index可以为负,且z-index只能在定位元素上奏效,该属性设置一个定位元素沿z轴的位置,如果为正数,离用户越近,为负数,离用户越远,它的属性值有auto,默认,堆叠顺序与父元素相等,number,inherit,从父元素继承z-index属性的值 

line-height和height的区别

line-height一般是指布局里面一段文字上下行之间的高度,是针对字体来设置的,height一般是指容器的整体高度

设置一个元素的背景颜色,背景颜色会填充哪些区域?

background-color设置的背景颜色会填充元素的content、padding、border区域

知道属性选择器和伪类选择器的优先级吗

属性选择器和伪类选择器优先级相同 

inline-block、inline和block的区别;为什么img是inline还可以设置宽高

Block是块级元素,其前后都会有换行符,能设置宽度,高度,margin/padding水平垂直方向都有效。
Inline:设置width和height无效,margin在竖直方向上无效,padding在水平方向垂直方向都有效,前后无换行符
Inline-block:能设置宽度高度,margin/padding水平垂直方向 都有效,前后无换行符

overflow的原理

要讲清楚这个解决方案的原理,首先需要了解块格式化上下文,A block formatting context is a part of a visual CSS rendering of a Web page. It is the region in which the layout of block boxes occurs and in which floats interact with each other.翻译过来就是块格式化上下文是CSS可视化渲染的一部分,它是一块区域,规定了内部块盒 的渲染方式,以及浮动相互之间的影响关系
当元素设置了overflow样式且值部位visible时,该元素就构建了一个BFC,BFC在计算高度时,内部浮动元素的高度也要计算在内,也就是说技术BFC区域内只有一个浮动元素,BFC的高度也不会发生塌缩,所以达到了清除浮动的目的

css布局

六种布局方式总结:圣杯布局、双飞翼布局、Flex布局、绝对定位布局、表格布局、网格布局。
圣杯布局是指布局从上到下分为header、container、footer,然后container部分定为三栏布局。这种布局方式同样分为header、container、footer。圣杯布局的缺陷在于 center 是在 container 的padding中的,因此宽度小的时候会出现混乱。
双飞翼布局给center 部分包裹了一个 main 通过设置margin主动地把页面撑开。
Flex布局是由CSS3提供的一种方便的布局方式。
绝对定位布局是给container 设置position: relative和overflow: hidden,因为绝对定位的元素的参照物为第一个postion不为static的祖先元素。 left 向左浮动,right 向右浮动。center 使用绝对定位,通过设置left和right并把两边撑开。 center 设置top: 0和bottom: 0使其高度撑开。
表格布局的好处是能使三栏的高度统一。
网格布局可能是最强大的布局方式了,使用起来极其方便,但目前而言,兼容性并不好。网格布局,可以将页面分割成多个区域,或者用来定义内部元素的大小,位置,图层关系。

说一下闭包

一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。

(1)什么是闭包: 闭包是指有权访问另外一个函数作用域中的变量的函数。闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。

(2)为什么要用: 匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。 结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。

类的继承和创建

(1)类的创建(es5):new一个function,在这个function的prototype里面增加属性和方法。
下面来创建一个Animal类:
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || ‘Animal’;
// 实例方法
this.sleep = function(){
console.log(this.name + ‘正在睡觉!’);
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + ‘正在吃:’ + food);
};
这样就生成了一个Animal类,实力化生成对象后,有方法和属性。
(2)类的继承——原型链继承
–原型链继承

1
2
3
4
5
6
7
8
9
10
function Cat(){ }
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true

介绍:在这里我们可以看到new了一个空对象,这个空对象指向Animal并且Cat.prototype指向了这个空对象,这种就是基于原型链的继承。
特点:基于原型链,既是父类的实例,也是子类的实例
缺点:无法实现多继承
(3)构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

1
2
3
4
5
6
7
8
9
10
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特点:可以实现多继承
缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法。
(4)实例继承和拷贝继承
实例继承:为父类实例添加新特性,作为子类实例返回
拷贝继承:拷贝父类元素上的属性和方法
上述两个实用性不强,不一一举例。
(5)组合继承:相当于构造继承和原型链继承的组合体。通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

1
2
3
4
5
6
7
8
9
10
11
12
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特点:可以继承实例属性/方法,也可以继承原型属性/方法
缺点:调用了两次父类构造函数,生成了两份实例
(6)寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性

1
2
3
4
5
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){

// 创建一个没有实例方法的类

1
2
var Super = function(){};
Super.prototype = Animal.prototype;

//将实例作为子类的原型

1
2
3
4
5
6
7
8
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

较为推荐

说说前端中的事件流

HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。
事件捕获阶段
处于目标阶段
事件冒泡阶段
addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
IE只支持事件冒泡。

如何让事件先冒泡后捕获

在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获之间。

说一下事件委托

事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。
举例:最经典的就是ul和li标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加。
好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。

mouseover和mouseenter的区别

mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave

js的new操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

改变函数内部this指针的指向函数(bind,apply,call的区别)

通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2…这种形式。通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。

apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。

call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。

bind除了返回是函数以外,它的参数和call一样。

js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?

clientHeight:表示的是可视区域的高度,不包含border和滚动条
offsetHeight:表示可视区域的高度,包含了border和滚动条
scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。
clientTop:表示边框border的厚度,在未指定的情况下一般为0
scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

js拖拽功能的实现

首先是三个事件,分别是mousedown,mousemove,mouseup
当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。
clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY来表示元素的元素的初始坐标,移动的举例应该是:
鼠标移动时候的坐标-鼠标按下去时候的坐标。
也就是说定位信息为:
鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.
还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left
以及top等等值。
补充:也可以通过html5的拖放(Drag 和 drop)来实现

JS中的垃圾回收机制

必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
这段话解释了为什么需要系统需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:
var a=”hello world”;
var b=”world”;
var a=b;
//这时,会释放掉”hello world”,释放内存以便再引用
垃圾回收的方法:标记清除、计数引用。
标记清除
这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。
垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。
引用计数法
另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0的这些值。
用引用计数法会存在内存泄露,下面来看原因:
function problem() {
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
在这个例子里面,objA和objB通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,因为计数不为0,这样的相互引用如果大量存在就会导致内存泄露。
特别是在DOM对象中,也容易存在这种问题:
var element=document.getElementById(’‘);
var myObj=new Object();
myObj.element=element;
element.someObject=myObj;
这样就不会有垃圾回收的过程。

eval是做什么的

它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行)

如何理解前端模块化

前端模块化就是复杂的文件编程一个一个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(编译等处理)的工具webpack

对象深度克隆的简单实现

1
2
3
4
5
6
7
8
function deepClone(obj){
var newObj= obj instanceof Array ? []:{};
for(var item in obj){
var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];
newObj[item] = temple;
}
return newObj;
}

ES5的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以我们一开始判断了一些类型,决定newObj是对象还是数组

实现一个once函数,传入函数参数只执行一次

1
2
3
4
5
6
7
8
9
10
function ones(func){
var tag=true;
return function(){
if(tag==true){
func.apply(null,arguments);
tag=false;
}
return undefined
}
}

js监听对象属性的改变

我们假设这里有一个user对象,
(1)在ES5中可以通过Object.defineProperty来实现已有属性的监听
Object.defineProperty(user,’name’,{
set:function(key,value){
}
})
缺点:如果id不在user对象中,则不能监听id的变化
(2)在ES6中可以通过Proxy来实现
var user = new Proxy({},{
set:function(target,key,value,receiver){
}
})
这样即使有属性在user中不存在,通过user.id来定义也同样可以这样监听这个属性的变化哦~

如何实现一个私有变量,用getName方法可以访问,不能直接访问

(1)通过defineProperty来实现
obj={
name:yuxiaoliang,
getName:function(){
return this.name
}
}
object.defineProperty(obj,”name”,{
//不可枚举不可配置
});
(2)通过函数的创建形式
function product(){
var name=’yuxiaoliang’;
this.getName=function(){
return name;
}
}
var obj=new product();

==和===、以及Object.is的区别

(1)==
主要存在:强制转换成number,null==undefined

1
2
3
4
5
" "==0  //true
"0"==0 //true
" " !="0" //true
123=="123" //true
null==undefined //true

(2)Object.js
主要的区别就是+0!=-0而NaN==NaN
(相对比===和==的改进)

setTimeout、setInterval和requestAnimationFrame之间的区别

这里有一篇文章讲的是requestAnimationFrame:http://www.cnblogs.com/xiaohuochai/p/5777186.html
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔,
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。
RAF采用的是系统时间间隔,不会因为前面的任务,不会影响RAF,但是如果前面的任务多的话,
会响应setTimeout和setInterval真正运行时的时间间隔。
特点:
(1)requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
(2)在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
(3)requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。

实现一个两列等高布局,讲讲思路

为了实现两列等高,可以给每列加上 padding-bottom:9999px;
margin-bottom:-9999px;同时父元素设置overflow:hidden;

this的指向 哪几种

默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。
【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。

数组移除第一个元素的方法

splice和shift方法

事件委托

把一个元素响应事件(click、keydown……)的函数委托到另一个元素;
优点:减少内存消耗、动态绑定事件。

dom是什么,你的理解?

文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。

事件代理

事件代理是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件代理,代理它们父级代为执行事件。 事件代理/事件委托:利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的事件, 简而言之:事件代理就是说我们将事件添加到本来要添加的事件的父节点,将事件委托给父节点来触发处理函数,这通常会使用在大量的同级元素需要添加同一类事件的时候,比如一个动态的非常多的列表,需要为每个列表项都添加点击事件,这时就可以使用事件代理,通过判断e.target.nodeName来判断发生的具体元素,这样做的好处是减少事件绑定,同事动态的DOM结构任然可以监听,事件代理发生在冒泡阶段

箭头函数和function的区别

箭头函数根本就没有绑定自己的this,在箭头函数中调用 this 时,仅仅是简单的沿着作用域链向上寻找,找到最近的一个 this 拿来使用

arguments

arguments是类数组对象,有length属性,不能调用数组方法
可用Array.from()转换

箭头函数获取arguments

可用…rest参数获取

数组去重

法一:indexOf循环去重
法二:ES6 Set去重;Array.from(new Set(array))
法三:Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。

es6的常用

promise,await/async,let,const,块级作用域,箭头函数

引用类型常见的对象

Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)等

JS的数据类型

字符串,数字,布尔,数组,null,Undefined,symbol,对象。

JavaScript中的轮播实现原理?假如一个页面上有两个轮播,你会怎么实现?

图片轮播的原理就是图片排成一行,然后准备一个只有一张图片大小的容器,对这个容器设置超出部分隐藏,在控制定时器来让这些图片整体左移或右移,这样呈现出来的效果就是图片在轮播了。
如果有两个轮播,可封装一个轮播组件,供两处调用

js对象类型,基本对象类型以及引用对象类型的区别

分为基本对象类型和引用对象类型
基本数据类型:按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。基本数据类型有这六种:undefined、null、string、number、boolean、symbol。
引用类型:当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。
引用类型有这几种:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。

js加载过程阻塞,解决方法。

指定script标签的async属性。
如果async=”async”,脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
如果不使用async 且 defer=”defer”:脚本将在页面完成解析时执行

private和public

public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用

怎么获得对象上的属性:比如说通过Object.key()

从ES5开始,有三种方法可以列出对象的属性
for(let I in obj)该方法依次访问一个对象及其原型链中所有可枚举的类型
object.keys:返回一个数组,包括所有可枚举的属性名称
object.getOwnPropertyNames:返回一个数组包含不可枚举的属性

js原型链,原型链的顶端是什么?Object的原型是什么?Object的原型的原型是什么?在数组原型链上实现删除数组重复数据的方法

能够把这个讲清楚弄明白是一件很困难的事,
首先明白原型是什么,在ES6之前,JS没有类和继承的概念,JS是通过原型来实现继承的,在JS中一个构造函数默认带有一个prototype属性,这个的属性值是一个对象,同时这个prototype对象自带有一个constructor属性,这个属性指向这个构造函数,同时每一个实例都会有一个proto_属性指向这个prototype对象,我们可以把这个叫做隐式原型,我们在使用一个实例的方法的时候,会先检查这个实例中是否有这个方法,没有的话就会检查这个prototype对象是否有这个方法,
基于这个规则,如果让原型对象指向另一个类型的实例,即constructor1.protoytpe=instance2,这时候如果试图引用constructor1构造的实例instance1的某个属性p1,
首先会在instance1内部属性中找一遍,
接着会在instance1._proto_(constructor1.prototype)即是instance2中寻找p1
搜寻轨迹:instance1->instance2->constructor2.prototype……->Object.prototype;这即是原型链,原型链顶端是Object.prototype
补充学习:
每个函数都有一个prototype属性,这个属性指向了一个对象,这个对象正是调用该函数而创建的实例的原型,那么什么是原型呢,可以这样理解,每一个JavaScript对象在创建的时候就会预制管理另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型继承属性,如图: img
那么怎么表示实例与实例原型的关系呢,这时候就要用到第二个属性_proto

这是每一个JS对象都会有的一个属性,指向这个对象的原型,如图: img
既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢,指向实例是没有的,因为一个构造函数可以生成多个实例,但是原型有属性可以直接指向构造函数,通过constructor即可
接下来讲解实例和原型的关系:
当读取实例的属性时,如果找不到,就会查找与对象相关的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层,那么原型的原型是什么呢,首先,原型也是一个对象,既然是对象,我们就可以通过构造函数的方式创建它,所以原型对象就是通过Object构造函数生成的,如图:img
那么Object.prototype的原型呢,我们可以打印console.log(Object.prototype.proto === null),返回true
null表示没有对象,即该处不应有值,所以Object.prototype没有原型,如图: img
图中这条蓝色的线即是原型链,
最后补充三点:
constructor:
function Person(){
}
var person = new Person();
console.log(Person === person.constructor);
原本person中没有constructor属性,当不能读取到constructor属性时,会从person的原型中读取,所以指向构造函数Person
proto:
绝大部分浏览器支持这个非标准的方法访问原型,然而它并不存在与Person.prototype中,实际上它来自Object.prototype,当使用obj.proto时,可以理解为返回来Object.getPrototype(obj)
继承:
前面说到,每个对象都会从原型继承属性,但是引用《你不知道的JS》中的话,继承意味着复制操作,然而JS默认不会复制对象的属性,相反,JS只是在两个对象之间创建一个关联,这样子一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,叫委托更合适

let const var的区别 ,什么是块级作用域,如何用ES5的方法实现块级作用域(立即执行函数),ES6 呢

提起这三个最明显的区别是var声明的变量是全局或者整个函数块的,而let,const声明的变量是块级的变量,var声明的变量存在变量提升,let,const不存在,let声明的变量允许重新赋值,const不允许

JS中string的startwith和indexof两种方法的区别

JS中startwith函数,其参数有3个,stringObj,要搜索的字符串对象,str,搜索的字符串,position,可选,从哪个位置开始搜索,如果以position开始的字符串以搜索字符串开头,则返回true,否则返回false
Indexof函数,indexof函数可返回某个指定字符串在字符串中首次出现的位置

有了解过事件模型吗,DOM0级和DOM2级有什么区别,DOM的分级是什么

JSDOM事件流存在如下三个阶段:
事件捕获阶段
处于目标阶段
事件冒泡阶段
JSDOM标准事件流的触发的先后顺序为:先捕获再冒泡,点击DOM节点时,事件传播顺序:事件捕获阶段,从上往下传播,然后到达事件目标节点,最后是冒泡阶段,从下往上传播
DOM节点添加事件监听方法addEventListener,中参数capture可以指定该监听是添加在事件捕获阶段还是事件冒泡阶段,为false是事件冒泡,为true是事件捕获,并非所有的事件都支持冒泡,比如focus,blur等等,我们可以通过event.bubbles来判断
事件模型有三个常用方法:
event.stopPropagation:阻止捕获和冒泡阶段中,当前事件的进一步传播,
event.stopImmediatePropagetion,阻止调用相同事件的其他侦听器,
event.preventDefault,取消该事件(假如事件是可取消的)而不停止事件的进一步传播,
event.target:指向触发事件的元素,在事件冒泡过程中这个值不变
event.currentTarget = this,时间帮顶的当前元素,只有被点击时目标元素的target才会等于currentTarget,
最后,对于执行顺序的问题,如果DOM节点同时绑定了两个事件监听函数,一个用于捕获,一个用于冒泡,那么两个事件的执行顺序真的是先捕获在冒泡吗,答案是否定的,绑定在被点击元素的事件是按照代码添加顺序执行的,其他函数是先捕获再冒泡

setTimeout(fn,100);100毫秒是如何权衡的

etTimeout()函数只是将事件插入了任务列表,必须等到当前代码执行完,主线程才会去执行它指定的回调函数,有可能要等很久,所以没有办法保证回调函数一定会在setTimeout指定的时间内执行,100毫秒是插入队列的时间+等待的时间

深浅拷贝的区别和实现

数组的浅拷贝:
如果是数组,我们可以利用数组的一些方法,比如slice,concat方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,我们把这种复制引用的拷贝方法称为浅拷贝,
深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也互相分离,修改一个对象的属性,不会影响另一个
如何深拷贝一个数组
1、这里介绍一个技巧,不仅适用于数组还适用于对象!那就是:

1
2
3
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse( JSON.stringify(arr) );
console.log(new_arr);

原理是JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序列化为一个js对象,通过这两个方法,也可以实现对象的深复制。
但是这个方法不能够拷贝函数
浅拷贝的实现:
以上三个方法concat,slice ,JSON.stringify都是技巧类,根据实际项目情况选择使用,我们可以思考下如何实现一个对象或数组的浅拷贝,遍历对象,然后把属性和属性值都放在一个新的对象里即可

1
2
3
4
5
6
7
8
9
10
11
12
13
var shallowCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}

深拷贝的实现
那如何实现一个深拷贝呢?说起来也好简单,我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好了~

1
2
3
4
5
6
7
8
9
10
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}

不同数据类型的值的比较,是怎么转换的,有什么规则 img

去除字符串首尾空格

使用正则(^\s)|(\s$)即可

如何判断一个数组(讲到typeof差点掉坑里)

instanceof
Object.prototype.call.toString()

数组常用方法

push(),pop(),shift(),unshift(),splice(),sort(),reverse(),map()等

简单使用hexo

发表于 2019-07-15 | 分类于 Hexo

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

12
SampsonKY

SampsonKY

Dreams are destined to be lonely, and there is no doubt and ridicule on the road, but what about it, even if it is bruised and bruised, it must live beautifully.

18 日志
3 分类
15 标签
RSS
GitHub E-Mail
© 2020 SampsonKY
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4