前端基础知识点总结

本文主要总结学习过程中自己觉得重要或者不懂常见的小知识,持续更新

parseInt

parseInt方法用于将字符串转为整数。

parseInt的返回值只有两种可能,要么是一个十进制整数,要么是NaN。

如果parseInt的参数不是字符串,则会先转为字符串再转换。

第二个参数

parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。

ex:

parseInt('1000') // 1000
// 等同于
parseInt('1000', 10) // 1000

parseInt('1000', 2) // 8
parseInt('1000', 6) // 216
parseInt('1000', 8) // 512

 
 
 
 

Number.prototype.toString()

Number对象部署了自己的toString方法,用来将一个数值转为字符串形式。

参数

toString方法可以接受一个参数,表示输出的进制。如果省略这个参数,默认将数值先转为十进制,再输出字符串;否则,就根据参数指定的进制,将一个数字转化成某个进制的字符串

ex:

(10).toString(2) // "1010"
(10).toString(8) // "12"
(10).toString(16) // "a"

 
 
 
 

setTimeout

 
学习promise时发现的问题

第三个参数
setTimeout(resolve, ms, 'done');

这里的第三个参数为附加参数,一旦定时器到期,它们会作为参数传递给 function 或执行字符串

setTimeout(resolve, ms, 'done')setTimeout(resolve('done'), ms)区别

就是func()和func的区别,setTimeout的第一个参数应该是函数,如果用func()相当于其返回值为第一个参数,不再为函数,所以func()会立即执行,不会又延时的作用。

本例中 resolve 是一个函数,因此行为正常
setTimeout(resolve(‘World’), ms)中 resolve(‘World’) 不是函数,是什么决定于 resolve 的返回值类型,但无论如何,resolve 在 注册 timer 的时候 就已经执行了,自然也就没有延迟效果了

 
 
 
 

鼠标事件

 

鼠标进入节点
  • mouseenter 鼠标进入一个节点时触发,进入子节点不会触发这个事件
  • mouseover 鼠标进入一个节点时触发,进入子节点会再一次触发这个事件

他们都是鼠标移入一个节点时触发,区别仅在于进入子节点会不会再次触发事件

鼠标离开节点
  • mouseleave 鼠标离开一个节点时触发,离开父节点不会触发这个事件
  • mouseout 鼠标离开一个节点时触发,离开父节点也会触发这个事件

ps:一般mouseentermouseleave配合使用, mouseovermouseout配合使用

其他:

  • mousedown:按下鼠标键时触发。
  • mouseup:释放按下的鼠标键时触发。
  • contextmenu:按下鼠标右键时(上下文菜单出现前)触发,或者按下“上下文菜单键”时触发。
  • wheel:滚动鼠标的滚轮时触发,该事件继承的是WheelEvent接口。

 
 
 
 

js 阻塞效应解决

在这里插入图片描述
在这里插入图片描述

 

defer属性

为了解决脚本文件下载阻塞网页渲染的问题,一个方法是对<script>元素加入defer属性。它的作用是延迟脚本的执行,等到 DOM 加载生成后,再执行脚本。

<script src="a.js" defer></script>
<script src="b.js" defer></script>

上面代码中,只有等到 DOM 加载完成后,才会执行a.js和b.js。

defer属性的运行流程如下。

  1. 浏览器开始解析 HTML 网页。
  2. 解析过程中,发现带有defer属性的<script>元素。
  3. 浏览器继续往下解析 HTML 网页,同时并行下载<script>元素加载的外部脚本。
  4. 浏览器完成解析 HTML 网页,此时再回过头执行已经下载完成的脚本。

ps:对于内置而不是加载外部脚本的script标签,以及动态生成的script标签,defer属性不起作用。另外,使用defer加载的外部脚本不应该使用document.write方法。

async 属性
<script src="a.js" async></script>
<script src="b.js" async></script>

async属性的作用是,使用另一个进程下载脚本,下载时不会阻塞渲染。

  1. 浏览器开始解析 HTML 网页。
  2. 解析过程中,发现带有async属性的script标签。
  3. 浏览器继续往下解析 HTML 网页,同时并行下载<script>标签中的外部脚本。
  4. 脚本下载完成,浏览器暂停解析 HTML 网页,开始执行下载的脚本。
  5. 脚本执行完毕,浏览器恢复解析 HTML 网页。

注意:一旦采用这个属性,就无法保证脚本的执行顺序。哪个脚本先下载结束,就先执行那个脚本。另外,使用async属性的脚本文件里面的代码,不应该使用document.write方法。
一般来说,如果脚本之间没有依赖关系,就使用async属性,如果脚本之间有依赖关系(比如只有先引入jquery.js才能使用jquery语法),就使用defer属性。如果同时使用async和defer属性,后者不起作用,浏览器行为由async属性决定。

脚本的动态加载

<script>元素还可以动态生成,生成后再插入页面,从而实现脚本的动态加载。

['a.js', 'b.js'].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  document.head.appendChild(script);
});

这种方法的好处是,动态生成的script标签不会阻塞页面渲染,也就不会造成浏览器假死。但是问题在于,这种方法无法保证脚本的执行顺序,哪个脚本文件先下载完成,就先执行哪个。

如果想避免这个问题,可以设置async属性为false。

['a.js', 'b.js'].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});
加载所用协议

如果不指定协议,浏览器默认采用 HTTP 协议下载。

如果要采用 HTTPS 协议下载,必需写明

<script src="https://example.js"></script>

根据页面本身的协议来决定加载协议,这时可以采用下面的写法。

<script src="//example.js"></script>

 
 
 
 

不同浏览器渲染引擎及渲染机制

 

  • Firefox:Gecko 引擎
  • Safari:WebKit 引擎
  • Chrome:Blink 引擎(基于 WebKit 的 fork Web 渲染引擎)
  • IE: Trident 引擎
  • Edge: EdgeHTML 引擎 (随着win10推出的)
  • Opera: Presto->blink

渲染引擎处理网页,通常分成四个阶段。

  1. 解析代码:HTML 代码解析为 DOM,CSS 代码解析为 CSSOM(CSS Object Model)。
  2. 对象合成:将 DOM 和 CSSOM 合成一棵渲染树(render tree)。
  3. 布局:计算出渲染树的布局(layout)。
  4. 绘制:将渲染树绘制到屏幕。

以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的 HTML 代码还没下载完,但浏览器已经显示出内容了

 
 
 
 

重流和重绘及优化技巧

 
渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具有阻塞效应,并且会耗费很多时间和计算资源。

页面生成以后,脚本操作和样式表操作,都会触发“重流”(reflow)和“重绘”(repaint)。用户的互动也会触发重流和重绘,比如设置了鼠标悬停(a:hover)效果、页面滚动、在输入框中输入文本、改变窗口大小等等。

重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。比如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流。

优化技巧:

  1. 读取 DOM 或者写入 DOM,尽量写在一起,不要混杂。不要读取一个 DOM 节点,然后立刻写入,接着再读取一个 DOM 节点。
  2. 缓存 DOM 信息。
  3. 不要一项一项地改变样式,而是使用 CSS class 一次性改变样式。
  4. 使用documentFragment操作 DOM
  5. 动画使用absolute定位或fixed定位,这样可以减少对其他元素的影响。
  6. 只在必要时才显示隐藏元素。
  7. 使用window.requestAnimationFrame(),因为它可以把代码推迟到下一次重流时执行,而不是立即要求页面重流。
  8. 使用虚拟 DOM(virtual DOM)库。

ex:

// 重绘代价高
function doubleHeight(element) {
  var currentHeight = element.clientHeight;
  element.style.height = (currentHeight * 2) + 'px';
}

all_my_elements.forEach(doubleHeight);

// 重绘代价低
function doubleHeight(element) {
  var currentHeight = element.clientHeight;

  window.requestAnimationFrame(function () {
    element.style.height = (currentHeight * 2) + 'px';
  });
}

all_my_elements.forEach(doubleHeight);

 
 
 
 

原型 原型链

 

原型

原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。

通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
ex:

function Cat(name, color) {
  this.name = name;
  this.color = color;
  this.meow = function () {
    console.log('喵喵');
  };
}
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');

cat1.meow === cat2.meow
// false

上面代码中,cat1和cat2是同一个构造函数的两个实例,它们都具有meow方法。由于meow方法是生成在每个实例对象上面,所以两个实例就生成了两次。也就是说,每新建一个实例,就会新建一个meow方法。这既没有必要,又浪费系统资源,因为所有meow方法都是同样的行为,完全应该共享。

这个问题的解决方法,就是 JavaScript 的原型对象(prototype)

JavaScript 规定,每个函数都有一个prototype属性,指向一个对象。
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
ex:

function Animal(name) {
  this.name = name;
}
Animal.prototype.color = 'white';

var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');

cat1.color // 'white'
cat2.color // 'white'

构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象。原型对象上添加一个color属性,结果,实例对象都共享了该属性。

原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
ex:

Animal.prototype.color = 'yellow';

cat1.color // "yellow"
cat2.color // "yellow"

总结:

  • 当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。这就是原型对象的特殊之处。但是如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
  • 原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象
原型链

JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型

如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。

ps:Object.prototype的原型是null,null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。

总结:

  • 读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
  • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)

ps:一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大

 
 
 
 

AJAX跨源通信

 

JSONP (只能发送get请求)

JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单易用,没有兼容性问题,老式浏览器全部支持,服务端改造非常小。

流程:

  • 第一步,网页添加一个<script>元素,向服务器请求一个脚本,这不受同源政策限制(同样的还有img以及href等属性),可以跨域请求。
  • 第二步,服务器收到请求后,拼接一个字符串,将 JSON 数据放在函数名里面,作为字符串返回
  • 第三步,客户端会将服务器返回的字符串,作为代码解析,因为浏览器认为,这是<script>标签请求的脚本内容。这时,客户端只要定义了回调函数,就能在该函数体内,拿到服务器返回的 JSON 数据。

ex:

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于 JSONP 是必需的.同时作为参数的 JSON 数据被视为 JavaScript 对象,而不是字符串,因此避免了使用JSON.parse()的步骤。

WebSocket

WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

下面是一个例子,浏览器发出的 WebSocket 请求的头信息

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。

正是因为有了Origin这个字段,所以 WebSocket 才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
CORS

CORS 是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。相比 JSONP 只能发GET请求,CORS 允许任何类型的请求。它允许浏览器向跨域的服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制。

CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能

整个 CORS 通信过程,都是浏览器自动完成,对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。

因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信。

CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为“预检”请求。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

只要同时满足以下两大条件,就属于简单请求。反之则属于非简单请求。

(1)请求方法是以下三种方法之一。

  • HEAD
  • GET
  • POST

(2)HTTP 的头信息不超出以下几种字段。

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

简单请求流程:
对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个Origin字段。

ex:

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来说明,本次请求来自哪个域(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。这种错误无法通过状态码识别

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与 CORS 请求相关的字段,都以Access-Control-开头。

(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求

(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送 Cookie。默认情况下,Cookie 不包括在 CORS 请求之中

(3)Access-Control-Expose-Headers
该字段可选。CORS 请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个服务器返回的基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader(‘FooBar’)可以返回FooBar字段的值。

与JSONP比较

CORS 与 JSONP 的使用目的相同,但是比 JSONP 更强大。JSONP 只支持GET请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。

非简单请求自行查阅

 
 
 
 

.native修饰符

官方对.native修饰符的解释为:

有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

简单理解为:.native修饰符是告诉编译器,前面的事件为原生的事件,不是自定义的事件,按照原生的方法解析便可。
 
 
 
 

css伪类伪元素
  • CSS3 规范中,为了区分伪类和伪元素,大多数浏览器都支持这两种表示方式。单冒号(:)用于 CSS3 伪类,双冒号(::)用于 CSS3 伪元素
  • 伪类本质上是为了弥补常规CSS选择器的不足,以便获取到更多信息;
  • 伪元素本质上是创建了一个有内容的虚拟容器
  • 可以同时使用多个伪类,而只能同时使用一个伪元素;
伪类

伪类存在的意义是为了通过选择器找到那些不存在与DOM树中的信息以及不能被常规CSS选择器获取到的信息。

常见的状态伪类主要包括:

  • :link 应用于未被访问过的链接;
  • :hover 应用于鼠标悬停到的元素;
  • :active 应用于被激活的元素;
  • :visited 应用于被访问过的链接,与:link互斥。
  • :focus 应用于拥有键盘输入焦点的元素。

执行时记忆顺序:love 并且 hate(link -> visited -> hover -> active)

常见结构性伪类:是css3新增选择器

:first-child 选择某个元素的第一个子元素;
:last-child 选择某个元素的最后一个子元素;
:nth-child() 选择某个元素的一个或多个特定的子元素;
:nth-last-child() 选择某个元素的一个或多个特定的子元素,从这个元素的最后一个子元素开始算;
:nth-of-type() 选择指定的元素;
:nth-last-of-type() 选择指定的元素,从元素的最后一个开始计算;
:first-of-type 选择一个上级元素下的第一个同类子元素;
:last-of-type 选择一个上级元素的最后一个同类子元素;
:only-child 选择的元素是它的父元素的唯一一个子元素;

伪元素

常见的伪元素选择器:

  • ::first-letter 选择元素文本的第一个字(母)。
  • ::first-line 选择元素文本的第一行。
  • ::before 在元素内容的最前面添加新内容。
  • ::after 在元素内容的最后面添加新内容。
  • ::selection匹配用户被用户选中或者处于高亮状态的部分
  • ::placeholder匹配占位符的文本,只有元素设置了placeholder属性时,该伪元素才能生效
     
     
     
     
组件中的data为什么是一个函数而不是一个对象

首先官方是这么解释的
在这里插入图片描述
通俗的讲就是:

因为对象是一个引用数据类型,如果data是一个对象的情况下会造成所有组件共用一个data。而当data是一个函数的情况下,每次函数执行完毕后都会返回一个新的对象,这样的话每个组件都会维护一份独立的对象(data)

 
 


本文持续更新
博文参考
https://wangdoc.com/javascript/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值