web前端知识总结(HTML、css、js)

原创 minsong 随笔 面试 299阅读 2017-06-30 14:15:47 举报

HTML 篇

1、Web语义化 和 SEO
html 常规标签有html,head,body,div,span,table,ul,ol,dl,p,b,h1~h6,strong,form,input,img,em,i 等等,另外html5 还新增了很多语义化的标签,比如header,acticle,aside,section,footer,audio,radio 等等。
Web语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解。
SEO是指在了解搜索引擎自然排名机制的基础之上,对网站进行内部及外部的调整优化,改进网站在搜索引擎中关键词的自然排名,获得更多的展现量,吸引更多目标客户点击访问网站,从而达到互联网营销及品牌建设的目标。
搜索引擎通过爬虫技术获取的页面就是由一堆html标签组成的代码,,人可以通过可视化的方式来判断页面上哪些内容是重点,而机器做不到。 但搜索引擎会根据标签的含义来判断内容的权重,因此,在合适的位置使用恰当的标签,使整个页面的语义明确,结构清晰,搜索引擎才能正确识别页面中的重要内容,并予以较高的权值。比如h1~h6这几个标签在SEO中的权值非常高,用它们作页面的标题就是一个简单的SEO优化。

2、页面渲染机制
页面渲染就是浏览器的渲染引擎将html代码根据CSS定义的规则显示在浏览器窗口中的过程。大致工作原理如下:

  1. 用户输入网址,浏览器向服务器发出请求,服务器返回html文件;
  2. 渲染引擎开始载入html代码,并将HTML中的标签转化为DOM节点,生成DOM树;
  3. 如果<head>中引用了外部css文件,则发出css文件请求,服务器返回该文件;
  4. 如果<head>中引用了外部js文件,则发出js文件请求,服务器返回该文件后开始运行;
  5. 渲染引擎继续载入html中的<body>部分的代码,并开始解析前面返回的css文件,然后根据css选择器计算出节点的样式,创建渲染树;
  6. 从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标;
  7. 如果body中的<img>引用了图片资源,则立即向服务器发出请求,此时渲染引擎不会等待图片下载完毕,而是继续渲染后面的代码;
  8. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排版,因此引擎需要回过头来重新渲染这部分代码;
  9. 如果此时js脚本中运行了style.display="none", 布局被改变,引擎也需要重新渲染这部分代码;
  10. 直到</html>为止,页面渲染完毕。

3、重绘和回流
当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流。比如上面的img文件加载完成后就会引起回流,每个页面至少需要一次回流,就是在页面第一次加载的时候。
当渲染树中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
从上面可以看出,回流必将引起重绘,而重绘不一定会引起回流。
会引起重绘和回流的操作
添加、删除元素(回流+重绘)
隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)
移动元素,比如改变top,left,transform的值,或者移动元素到另外一个父元素中。(重绘+回流)
对style的操作(对不同的属性操作,影响不一样)
还有一种是用户的操作,比如改变浏览器大小,改变浏览器的字体大小等(回流+重绘)

4、本地存储
本地存储最原始的方式就是 cookie,cookie 是存放在本地浏览器的一段文本,数据以键值对的形式保存,可以设置过期时间。 但是 cookie 不适合大量数据的存储,因为每请求一次页面,cookie 都会发送给服务器,这使得 cookie 速度很慢而且效率也不高。因此cookie的大小被限制为4k左右(不同浏览器可能不同,分HOST),如下所示:
Firefox和Safari允许cookie多达4097个字节,包括名(name)、值(value)和等号。
Opera允许cookie多达4096个字节,包括:名(name)、值(value)和等号。
Internet Explorer允许cookie多达4095个字节,包括:名(name)、值(value)和等号。
在所有浏览器中,任何cookie大小超过限制都被忽略,且永远不会被设置。
html5提供了两种在客户端存储数据的新方法:localStorage 和 sessionStorage, 它们都是以key/value 的形式来存储数据,前者是永久存储,后者的存储期限仅限于浏览器会话(session),即当浏览器窗口关闭后,sessionStorage中的数据被清除。
localStorage的存储空间大约5M左右(不同浏览器可能不同,分 HOST),这个相当于一个5M大小的前端页面的数据库,相比于cookie可以节约带宽,但localStorage在浏览器隐私模式下是不可读取的,当存储数据超过了localStorage的存储空间后会抛出异常。
此外,H5还提供了逆天的websql和indexedDB,允许前端以关系型数据库的方式来存储本地数据,相对来说,这个功能目前应用的场景比较少,此处不作介绍。

5、浏览器缓存机制
浏览器缓存机制是指通过 HTTP 协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制。
Cache-Control 用于控制文件在本地缓存有效时长。最常见的,比如服务器回包:Cache-Control:max-age=600 表示文件在本地应该缓存,且有效时长是600秒(从发出请求算起)。在接下来600秒内,如果有请求这个资源,浏览器不会发出 HTTP 请求,而是直接使用本地缓存的文件。
Last-Modified 是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过 If-Modified-Since 字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。
Cache-Control 通常与 Last-Modified 一起使用。一个用于控制缓存有效时间,一个在缓存失效后,向服务查询是否有更新。
Cache-Control 还有一个同功能的字段:Expires。Expires 的值一个绝对的时间点,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在这个时间点之前,缓存都是有效的。
Expires 是 HTTP1.0 标准中的字段,Cache-Control 是 HTTP1.1 标准中新加的字段,功能一样,都是控制缓存的有效时间。当这两个字段同时出现时,Cache-Control 是高优化级的。
Etag 也是和 Last-Modified 一样,对文件进行标识的字段。不同的是,Etag 的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过 If-None-Match 字段把特征字串发送给服务器,由服务器和文件最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。Etag 和 Last-Modified 可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。
另外有两种特殊的情况:
手动刷新页面(F5),浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。
强制刷新页面(Ctrl+F5),浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或 Pragma:no-cache),发包向服务重新拉取文件。

6、History操作
用户访问网页的历史记录通常会被保存在一个类似于栈的对象中,即history对象,点击返回就出栈,跳下一页就入栈。 它提供了以下方法来操作页面的前进和后退:
window.history.back() 返回到上一个页面
window.history.forward() 进入到下一个页面
window.history.go([delta]) 跳转到指定页面
HTML5 对History Api 进行了增强,新增了两个Api和一个事件,分别是pushState、replaceState 和 onpopstate
pushState是往history对象里添加一个新的历史记录,即压栈。
replaceState 是替换history对象中的当前历史记录。
当点击浏览器后退按钮或 js调用history.back都会触发onpopstate事件。
与其类似的还有一个事件: onhashchange,onhashchange是老API, 浏览器支持度高, 本来是用来监听hash变化的, 但可以被利用来做客户端前进和后退事件的监听,而onpopstate是专门用来监听浏览器前进后退的, 不仅可以支持hash, 非hash的同源url也支持。

7、HTML5离线缓存
HTML5离线缓存又叫Application Cache,是从浏览器的缓存中分出来的一块缓存区,如果要在这个缓存中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源。
manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。manifest 文件可分为三个部分:
  - CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存
  - NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存
  - FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)
离线缓存为应用带来三个优势:
离线浏览 - 用户可在应用离线时使用它们
速度 - 已缓存资源加载得更快
减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源。

8、Canvas 和 SVG
Canvas 通过Javascript 来绘制 2D 图形。Canvas 是逐像素进行渲染的。在 Canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
SVG 是一种使用 XML 描述 2D 图形的语言。SVG 基于 XML,这意味着 SVG DOM 中的每个元素都是可用的。你可以为某个元素附加 JavaScript 事件处理器。在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
Canvas和SVG相比,canvas更依赖于分辨率,不支持事件处理器,文本渲染能力弱,比较适合密集型游戏,其中的许多对象会被频繁绘制,而svg则比较适用于类似谷歌地图带有大型渲染区域的应用程序。

CSS 篇

1、选择器
css的选择器有很多种,常用的有类选择器、标签选择器、ID选择器、后代选择器、群组选择器、伪类选择器(before/after)、兄弟选择器(+~)、属性选择器等等。

2、定位 position
定位一般有相对定位(relative)、绝对定位(absolute)、固定定位(fixed),relative和absolute在移动端用的最多,fixed 在移动端有兼容性问题,因此不推荐使用,在移动端替代fixed的方案是 absolute+内部滚动。

3、浮动 float
设置float为left或right,就能使该元素脱离文档流,向左或向右浮动。一般在做宫格模式布局时会用到,如果子元素全部设置为浮动,则父元素是塌陷的,这时就需要清除浮动,清除浮动的方法也很多,常用的方法是在元素末尾加空元素设置clear:both, 更高级一点的就给父容器设置before/after来模拟一个空元素,还可以直接设置overflow:auto/hidden。除过浮动可以实现宫格模式,行内盒子(inline-block)和table也可以。

4、盒子模型 Box
盒子模型是css最重要的一个概念,也是css布局的基石。 常见的盒子模型有块级盒子(block)和行内盒子(inline-block),盒子最关键的几个属性包括margin、border、padding和content,这几个元素可以设置盒子和盒子之间的关系以及盒子和内容之间的关系。还有一个问题是计算盒子的大小,需要注意的是,box-sizing属性的设置会影响盒子的width和height。只有普通文档流中块框的垂直外边距才会发生外边距合并。行内框、浮动框或绝对定位之间的外边距不会合并。

5、弹性布局 Flex
Flex布局的容器是一个伸缩容器,首先容器本身会更具容器中的元素动态设置自身大小;然后当Flex容器被应用一个大小时(width和height),将会自动调整容器中的元素适应新大小。Flex容器也可以设置伸缩比例和固定宽度,还可以设置容器中元素的排列方向(横向和纵向)和是否支持元素的自动换行。有了这个神器,做页面布局的可以方便很多了。注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。

6、过渡 Transition 、旋转 Transform
应用transform可以对元素进行平移(translate)、旋转(rotate)、放大缩小(scale)、倾斜(skew)等处理,而transition使css属性值(包括transform)在一段时间内平滑的过渡。使用transition和transform就可以实现页面的滑动切换效果。

7、动画 Animation
Animation首先需要设置一个动画函数,然后以这个动画的方式来改变元素的css属性之的变化,动画可以被设置为永久循环演示。 和transition相比,animation设置动画效果更灵活更丰富,二者还有一个区别是:transition只能通过主动改变元素的css值才能触发动画效果,而animation一旦被应用,就开始执行动画。

8、精灵技术 sprite
对于大型站点,为了减少http请求的次数,一般会将常用的小图标排到一个大图中,页面加载时只需请求一次网络, 然后在css中通过设置background-position来控制显示所需要的小图标。

9、字体图标 iconfont
所谓字体图标就是将常用的图标转化为字体资源存在文件中,通过在CSS中引用该字体文件,然后可以直接通过控制字体的css属性来设置图标的样式,字体图标的好处是其不受屏幕分辨率的影响,并且可以任意修改图标的颜色。

JAVASCRIPT 篇

1、基础语法
Javascript基础语法包括:变量定义、数据类型、循环、选择、内置对象等。
数据类型有string,number,boolean,null,undefined,object等。其中,string,number和boolean是基础类型,null和undefined是JS中的两个特殊类型,object是引用类型。
Javascript可以通过typeof来判断基础数据类型,但不能够准确判断引用类型, 因此需要用到另外一个方法,那就是Object的toString。
Javascript中的数据类型有以下几种情况:
基本类型:string,number,boolean
特殊类型:undefined,null
引用类型:Object,Function,Date,Array,RegExp, ...
1、string
string类型的数据是由16位Unicode字符组成的字符串,用typeof检测其数据类型如下:
javascript 代码

在Javascript中,除过undefined和null之外的其他的数据类型都有toString()方法,因此这些数据类型都可以通过toString方法转化为对应的string类型。
javascript 代码

一般情况下,toString 不需要传递参数,而将数值转化为字符串时,通过传递一个radix参数,可以将数值转化为对应的二进制、八进制和十六进制的字符串表示。
javascript 代码

2、number
在Javascript中,没有int和float数据类型,而是用number来表示整数和浮点数值,除此之外,number还有一个特殊的数值,即NaN (Not a Number),NaN表示一个承诺返回数值类型数据但实际没有返回的情况。NaN有两个特点:一是任何涉及NaN的操作都会返回NaN,二是NaN不与任何数值相等,包括自己,但可以通过isNaN()方法来判断一个数值是否为NaN
javascript 代码

3、boolean
boolean类型只有两个字面值:true和false 。 但在Javascript中,所有类型的值都可以转化为与boolean等价的值,转化规则如下:
(1)所有对象都被当作 true,
(2)当字符串为空时,该字符串被当作false
(3)null 和 undefined 被当作 false
(4)当数字为0时,该数字被当作 false
javascript 代码

需要注意的是,平时我们看到的if(1) {...} ,实际上JS引擎在内部也对这些值做了boolean转化然后再进行运算的。
4、undefined
该类型只有一个值,即 undefined。 undefined意为未定义,即当使用var声明了变量但未进行复制时,这个变量的值就是undefined。undefined产生的原因有两种:
(1)访问对象不存在的属性或方法
(2)声明了变量但从未赋值
javascript 代码

5、null
null类型也只有一个值:null , 表示一个变量中没有包含有效数据。null在这里意为空值空对象的意思,更确切的说,一个被赋值为null的变量没有保存有效的数值、字符串、布尔、数组或对象等,可以通过给一个变量赋值为null来清空变量中的内容。产生null的原因只有一个:即对一个变量显式的赋值为null 。
javascript 代码

另外,需要注意的是,typeof null 应该返回null,但实际上返回的是object,这是一个历史遗留问题,并没有其他原因。
6、Object,Function,Array,Date,RegExp
这些对象在JS中都属于引用类型, 除Function之外,通过typeof检测其数据类型返回的都是object, 如果要判断对应的具体类型,则可以通过Object.prototype.toString来获取。
javascript 代码

判断JS数据类型的四种方法
基本类型:string,number,boolean
特殊类型:undefined,null
引用类型:Object,Function,Function,Array,RegExp,Date,...
很多时候我们都需要通过判断变量的数据类型来进行下一步操作,下面我们介绍常用的4种方法:
1、typeof
typeof 返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、object、undefined、function等6种数据类型。
javascript 代码

typeof 可以对JS基础数据类型做出准确的判断,而对于引用类型返回的基本上都是object, 其实返回object也没有错,因为所有对象的原型链最终都指向了Object,Object是所有对象的祖宗。 但当我们需要知道某个对象的具体类型时,typeof 就显得有些力不从心了。
2、instanceof
instanceof 是用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 在这里需要特别注意的是:instanceof检测的是原型,我们用一段伪代码来模拟其内部执行过程:
javascript 代码

从上述过程可以看出,当 A 的 proto 指向 B 的 prototype 时,就认为A就是B的实例,我们再来看几个例子:
javascript 代码

我们发现,虽然 instanceof 能够判断出 [] 是Array的实例,但它认为 [] 也是Object的实例,为什么呢? 我们来分析一下[]、Array、Object 三者之间的关系: 从instanceof 能够判断出 [].proto 指向 Array.prototype, 而 Array.prototype.proto 又指向了Object.prototype,Object.prototype.proto 指向了null,标志着原型链的结束。因此,[]、Array、Object就形成了如下图所示的一条原型链:

web前端知识总结(HTML、css、js)
从原型链可以看出,[] 的 proto 直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。当然,类似的new Date()、new Person() 也会形成这样一条原型链,因此,instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。
3、constructor
当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。如下所示:

web前端知识总结(HTML、css、js)
当执行 var f = new F() 时,F被当成了构造函数,f是F的实例对象,此时F原型上的constructor传递到了f上,因此f.constructor == F

web前端知识总结(HTML、css、js)
可以看出,JS在函数F的原型上定义了constructor,当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型,使得新对象有名有姓,可以追溯。
同理,JS中的数据类型也遵守这个规则:

web前端知识总结(HTML、css、js)
细节问题:
null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

web前端知识总结(HTML、css、js)
为什么变成了Object?
prototype被重新赋值的是一个{}, {}是new Object()的字面量,因此new Object()会将Object原型上的constructor传递给{},也就是Object本身。
因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写。
4、Object.prototype.toString
toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。
javascript 代码

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。

JS常用的内置对象有Date、Array、JSON,RegExp等。 一般来讲,Date和Array用的最频繁,JSON可以对对象和数组进行序列化和反序列化,还有一个作用就是实现对象的深拷贝。
RegExp即正则表达式,是处理字符串的利器。正则基础知识
ES5对数组增强的9个API
为了更方便的对Array进行操作,ES5规范在Array的原型上新增了9个方法,分别是forEach、filter、map、reduce、reduceRight、some、every、indexOf 和 lastIndexOf,本文将对这几个方法进行详细的讲解,并对每一个方法进行原型扩展,以兼容不支持ES5的浏览器。
1、forEach(callback[,thisArg])
在ES5之前,我们可以通过for和for in 两种方式来遍历数组,而ES5引入了一个新方法forEach,使数组遍历更加简洁,forEach需要传递2个参数,第一个参数是回调函数,是必选参数,第二个参数是一个对象,用来改变callback中的this指向,是可选参数。
javascript 代码

从输出的结果可以看出,callback中传入了3个参数v,i,r 分别表示当前元素、当前位置、数组对象。再看看使用 thisArg 的例子:
javascript 代码

不传thisArgs时,callback中的 this 默认指向 window 对象,当传递thisArg时,callback中的this就指向了thisArg,因此这个参数的目的就是为了改变回调函数中的this指向。
对于不支持ES5的浏览器,我们可以对forEach进行简单的扩展来兼容老的浏览器:
javascript 代码

2、filter(callback[,thisArg])
filter是过滤的意思,所以这个方法的作用就是返回一个匹配过滤条件的新数组,其接收两个参数callback和thisArg, callback也是回调函数,主要用于对元素进行条件匹配,thisArg和forEach中的thisArg作用一样,在这里就不重复了,看下面示例:
javascript 代码

代码很简单,一看就明白,没有filter的时候,要实现这个功能,我们事先要创建一个空的数组,把匹配到的元素再push进去,现在就不需要那么麻烦了,我们再看看对filter的扩展:
javascript 代码

3、map(callback[,thisArg])
map的作用是对原数组进行加工处理后并将其作为一个新数组返回,该方法同样接收两个参数,callback是回调函数用于对数组进行加工处理,thisArg和上面的一样。先看一个简单的例子:
javascript 代码

可以看出,newArr返回的是增加了area属性的对象数组。这个方法非常实用,一般情况下,当一个ajax请求返回时,我们都要对其结果集进行过滤和校验等操作,这时map就派上用场了。我们再看看如果对map进行兼容性扩展:
javascript 代码

4、reduce (callback[,initialValue])
reduce在这里有减少的意思,那reduce到底是干什么用的呢?看看比较官方的解释:The method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value. 自己慢慢体会吧,我们先看看怎么使用吧,用的多了自然就明白了:
javascript 代码

从运行结果可以看出,reduce实现了数组元素的累加功能,reduce接收4个参数,previousValue存放的是上一次callback返回的结果,currentValue是当前元素,currentIndex是当前元素位置,array是当前数组。previousValue 初始值为数组的第一个元素,数组从第2个元素开始遍历。我们再来看看initialValue 究竟是什么鬼:
javascript 代码

从运行结果看,initialValue参数指定了previousValue的初始值,更重要的是,这次数组是从第1个位置开始遍历,而不再是从第2个位置开始了。 现在回过头来,对照这两个例子,我相信你一定能够理解reduce的作用了。下面对于reduce的扩展会巩固你对reduce的理解:
javascript 代码

5、reduceRight (callback[,initialValue])
和reduce的作用完全相同,唯一的不同是,reduceRight是从右至左遍历数组的元素。
6、some (callback[,thisArg])
some是某些、一些的意思,因此,some的作用是检测数组中的每一个元素,当callback返回true时就停止遍历,并返回true,这样的描述似乎有些抽象,看代码,一切尽在代码中:
javascript 代码

从运行结果看,some检测整个数组,只要当arr中有一个元素符合条件item>2 就停止检测和遍历,并返回true,以表示检测到目标。这和我们在for循环中使用break语言的作用有点类似,这会儿你应该明白some的作用了吧! 下面对于some的扩展会有助于你对some的理解:
javascript 代码

7、every (callback[,thisArg])
every是每一个的意思,相比some来讲,every对元素的检测更加严格,那every到底是干什么的呢,看代码就知道了:
javascript 代码

从运行结果看,当检测第3个元素时,item<3为false, 停止检测,并返回false,这说明every在检测元素时,要求每一个元素都要符合条件item<3,如果有一个不符合就停止检测,并返回false,(ps:你可以测试item<5时的运行结果,返回值一定是true)。那every到底有什么用武之地呢? 当一个for循环使用了break语句后,我们想知道for循环是否正常的执行完时, 我们一般会通过检测for中的索引i==arr.length来判断,因此every的作用就体现在这里。 我们再看看对于every方法的扩展:
javascript 代码

8、indexOf 和 lastIndexOf
这两个方法和String类中indexOf和lastIndexOf作用类似,相信大家对这两个方法用的很熟了,因此这里不多做解释了。
数组常用的API
1、sort([compareFunction])
对数组做原地排序,并返回这个数组,默认按照字符串UNICODE的码位点排序,如果指明了compareFunction,则数组会按照调用函数的返回值排序:
javascript 代码

2、join([separator])
将数组中的所有元素连接成一个字符串。separtor 用于指定连接每个数组元素的分隔符。分隔符会被转成字符串类型;如果省略的话,默认为一个逗号。如果separtor 是一个空字符串,那么数组中的所有元素将被直接连接。
javascript 代码

3、concat(value1,...,valueN)
concat 方法将创建一个新的数组,然后将调用它的对象(this 指向的对象)中的元素以及所有参数中的数组类型的参数中的元素以及非数组类型的参数本身按照顺序放入这个新数组,并返回该数组. valueN允许是数组或非数组值.
javascript 代码

4、push(element1,...,elementN) 和 pop()
push添加一个或多个元素到数组的末尾,并返回数组新的长度,pop删除一个数组中的最后的一个元素,并且返回这个元素。
javascript 代码

注意:push和pop并不会改变原来的元素位置。
5、unshift(element1,...,elementN) 和 shift()
unshift添加一个或多个元素到数组的开头,并返回数组新的长度,shift删除一个数组中的第一个元素,并且返回这个元素。
javascript 代码

注意:unshift和shift都会改变原来的元素位置。
6、slice(begin[,end]) 和 splice(start,deleteCount[,value1,...,valueN])
slice方法从begin的索引位置开始提取数组元素,到end位置结束,但不包括end位置的元素,如果end被省略,则默认提取到数组的结尾。splice方法从一个数组中移除一个或多个元素,如果必要,在所移除元素的位置上插入新元素,返回所移除的元素。
javascript 代码

2、函数原型链
Javascript虽然没有继承概念,但Javascript在函数Function对象中建立了原型对象prototype,并以Function对象为主线,从上至下,在内部构建了一条原型链。
简单来说就是建立了变量查找机制,当访问一个对象的属性时,先查找对象本身是否存在,如果不存在就去该对象所在的原型连上去找,直到Object对象为止,如果都没有找到该属性才会返回undefined。
因此我们经常会利用函数的原型机制来实现JS继承。
JS原型对象和原型链
在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象Object 和 函数对象Function。
一般而言,通过new Function产生的对象是函数对象,其他对象都是普通对象。
举例说明:
javascript 代码

f1属于函数的声明,最常见的函数定义方式,f2实际上是一个匿名函数,把这个匿名函数赋值给了f2,属于函数表达式,f3不常见,但也是一种函数对象。
Function是JS自带的对象,f1,f2在创建的时候,JS会自动通过new Function()的方式来构建这些对象,因此,这三个对象都是通过new Function()创建的。
在Javascript中创建对象有两种方式:对象字面量和使用new表达式,o1和o2的创建恰好对应了这两种方式,重点讲一下o3, 如果用Java和C#的思路来理解的话,o3是f1的实例对象,o3和f1是同一类型,至少我以前这么认为,其实不然...
那么怎么理解呢? 很简单,看o3是不是通过new Function产生的, 显然不是,既然不是函数对象,那就是普通对象 。
通过对函数对象和普通对象的简单理解之后,我们再来了解一下Javascript中的原型和原型链:
在JS中,每当创建一个函数对象f1 时,该对象中都会内置一些属性,其中包括prototype和proto, prototype即原型对象,它记录着f1的一些属性和方法。
需要注意的是,prototype 对f1是不可见的,也就是说,f1不会查找prototype中的属性和方法。
javascript 代码

那么,prototype有什么用呢? 其实prototype的主要作用就是继承。 通俗一点讲,prototype中定义的属性和方法都是留给自己的“后代”用的,因此,子类完全可以访问prototype中的属性和方法。
想要知道f1是如何把prototype留给“后代”,我们需要了解一下JS中的原型链,此时,JS中的 proto 入场了,这哥们长的很奇特,隐藏的也很深,以致于你经常见不到它,但它在普通对象和函数对象中都存在, 它的作用就是保存父类的prototype对象,JS在通过new 表达式创建一个对象的时候,通常会把父类的prototype赋值给新对象的proto属性,这样,就形成了一代代传承...
javascript 代码

现在我们知道,obj中proto保存的是f的prototype, 那么f的prototype中的proto中保存的是什么呢? 看下图:

web前端知识总结(HTML、css、js)
如图所示,f.prototype的proto中保存的是Object.prototype,Object.prototype对象中也有proto,而从输出结果看,Object.prototype.proto 是null,表示obj对象原型链的终结。如下图所示:

web前端知识总结(HTML、css、js)
obj对象拥有这样一个原型链以后,当obj.foo执行时,obj会先查找自身是否有该属性,但不会查找自己的prototype,当找不到foo时,obj就沿着原型链依次去查找...
在上面的例子中,我们在f的prototype上定义了foo属性,这时obj就会在原型链上找到这个属性并执行。
最后,用几句话总结一下重点:
原型链的形成真正是靠proto 而非prototype,当JS引擎执行对象的方法时,先查找对象本身是否存在该方法,如果不存在,会在原型链上查找,但不会查找自身的prototype。
一个对象的proto记录着自己的原型链,决定了自身的数据类型,改变proto就等于改变对象的数据类型。
函数的prototype不属于自身的原型链,它是子类创建的核心,决定了子类的数据类型,是连接子类原型链的桥梁。
在原型对象上定义方法和属性的目的是为了被子类继承和使用。

3、函数作用域
函数作用域就是变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。在JS中没有会块级作用域,只有函数作用域,因此JS中还存在着另外一种怪异现象,那就是变量提升。
函数作用域和作用域链
1、作用域
所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
javascript 代码

(1)scope函数中定义的foo变量,除过自身可以访问以外,还可以在if语句、while语句和内嵌的匿名函数中访问。 因此,foo的作用域就是scope函数体。
(2)在javascript中,if、while、for 等代码块不能形成独立的作用域。因此,javascript中没有块级作用域,只有函数作用域。
但是,在JS中有一种特殊情况:
如果一个变量没有使用var声明,window便拥有了该属性,因此这个变量的作用域不属于某一个函数体,而是window对象。
javascript 代码

2、作用域链
所谓作用域链就是:一个函数体中嵌套了多层函数体,并在不同的函数体中定义了同一变量, 当其中一个函数访问这个变量时,便会形成一条作用域链。
javascript 代码

当执行second时,JS引擎会将second的作用域放置链表的头部,其次是first的作用域,最后是window对象,于是会形成如下作用域链:
second->first->window, 此时,JS引擎沿着该作用域链查找变量foo, 查到的是 second
当执行third时,third形成的作用域链:third->first->window, 因此查到的是:frist
3、作用域的延长:with 和 catch
with和catch语句主要用来临时扩展作用域链, 将语句中传递的变量对象添加到作用域的头部。语句结束后,原作用域链恢复正常。
javascript 代码

在执行third()时,传递了一个obj对象,obj 中有属性foo, 在执行with语句时,JS引擎将obj放置在了原链表的头部,于是形成的作用域链如下:
obj->third->first->window, 此时查找到的foo就是obj中的foo,因此输出的是 obj
而在with之前和之后,都是沿着原来的链表进行查找,从而说明在with语句结束后,作用域链已恢复正常。
4、this 关键字
在一个函数中,this总是指向当前函数的所有者对象,this总是在运行时才能确定其具体的指向, 也才能知道它的调用对象。
javascript 代码

在执行f()时,此时f()的调用者是window对象,因此输出 window
f.call(obj) 是把f()放在obj对象上执行,相当于obj.f(),此时f 中的this就是obj,所以输出的是 obj
5、实战应用
demo1
javascript 代码

demo2
javascript 代码

6、demo解析
javascript 代码

4、函数指针 this
this 存在于函数中,它指向的是该函数在运行时被调用的那个对象。在实际项目中,遇到this的坑比较多,因此需要对this作深入的理解。
Function对象还提供了call、apply和bind等方法来改变函数的this指向,其中call和apply主动执行函数,bind一般在事件回调中使用,而call和apply的区别只是参数的传递方式不同。
js中继承的几种用法总结(apply,call,prototype,bind)

5、构造函数 new
JS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。
普通函数的创建有:显式声明、匿名定义、new Function() 等三种方式。
当通过new来创建一个新对象时,JS底层将新对象的原型链指向了构造函数的原型对象,于是就在新对象和函数对象之间建立了一条原型链,通过新对象可以访问到函数对象原型prototype中的方法和属性。
JS构造函数及new运算符
1、认识new运算符
javascript 代码

2、代码解读
1-3行创建了一个函数Animal,并在其this上定义了属性:name,name的值是函数被执行时的形参。
第4行在Animal对象(Animal本身是一个函数对象)上定义了一个静态属性:color,并赋值“black”
5-7行在Animal函数的原型对象prototype上定义了一个say()方法,say方法输出了this的name值。
第8行通过new关键字创建了一个新对象cat
10-14行cat对象尝试访问name和color属性,并调用say方法。
16-20行Animal对象尝试访问name和color属性,并调用say方法。
3、重点解析
第8行代码是关键:
javascript 代码

Animal 本身是一个普通函数,但当通过new来创建对象时,Animal就是构造函数。
JS引擎执行这句代码时,在内部做了很多工作,用伪代码模拟其工作流程如下:
javascript 代码

(1)创建一个空对象obj;
(2)把obj的proto 指向构造函数Animal的原型对象prototype,此时便建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null
(3)在obj对象的执行环境调用Animal 函数并传递参数“cat”。 相当于var result = obj.Animal("cat")。
当这句执行完之后,obj便产生了属性name并赋值为"cat"。
(4)考察第3步返回的返回值,如果无返回值或者返回一个非对象值,则将obj返回作为新对象;否则会将返回值作为新对象返回。
理解了其运行机制以后,我们知道cat其实就是过程(4)的返回值,因此我们对cat对象的认知就多了一些:
cat的原型链是:cat->Animal.prototype->Object.prototype->null
cat上新增了一个属性:name
分析完了cat的产生过程,我们再看看输出结果:
cat.name -> 在过程(3)中,obj对象就产生了name属性。因此cat.name就是这里的obj.name
cat.color -> cat会先查找自身的color,没有找到便会沿着原型链查找,在上述例子中,我们仅在Animal对象上定义了color,并没有在其原型链上定义,因此找不到。
cat.say -> cat会先查找自身的say方法,没有找到便会沿着原型链查找,在上述例子中,我们在Animal的prototype上定义了say,因此在原型链上找到了say方法。
另外,在say方法中还访问this.name,这里的this指的是其调用者obj,因此输出的是obj.name的值。
对于Animal来说,它本身也是一个对象,因此,它在访问属性和方法时也遵守上述查找规则,所以:
Animal.color -> "black"
Animal.name -> "Animal" , Animal先查找自身的name,找到了name, 但这个name不是我们定义的name,而是函数对象内置的属性。
一般情况下,函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象)。
Animal.say -> Animal在自身没有找到say方法,也会沿着其原型链查找,话说Animal的原型链是什么呢?

web前端知识总结(HTML、css、js)
从测试结果看:Animal的原型链是这样的:
Animal->Function.prototype->Object.prototype->null
因此Animal的原型链上没有定义say方法!
4、new存在的意义
认识了new运算符之后,我们再回到开篇提到的问题:JS中万物皆对象,为什么还要通过new来产生对象?
要弄明白这个问题,我们首先要搞清楚cat和Animal的关系:
通过上面的分析,我们发现cat继承了Animal中的部分属性,因此我们可以简单的理解:Animal和cat是继承关系。
另一方面,cat是通过new产生的对象,那么cat到底是不是Animal的实例对象? 我们先来了解一下JS是如何来定义“实例对象”的?
A instanceof B
如果上述表达式为true,JS认为A是B的实例对象,我们用这个方法来判断一下cat和Animal
cat instanceof Animal; //true
从执行结果看:cat确实是Animal实例,要想证实这个结果,我们再来了解一下JS中instanceof的判断规则:
javascript 代码

如果A的proto 等价于 B的prototype,就返回true
在new的执行过程(2)中,cat的proto指向了Animal的prototype,所以cat和Animal符合instanceof的判断结果。
因此,我们认为:cat 是Animal的实例对象。
5、总结
在Javascript中, 通过new可以产生原对象的一个实例对象,而这个实例对象继承了原对象的属性和方法。因此,new存在的意义在于它实现了Javascript中的继承,而不仅仅是实例化了一个对象!

6、闭包
闭包其实是一个主动执行的代码块,这个代码块的特殊之处是可以永久保存局部变量,但又不污染全局变量,可以形成一个独立的执行过程,因此我们经常用闭包来定义组件。
参考:闭包的理解

7、单线程和异步队列
setTimeout和setInterval是JS内置的两个定时器,使用很简单,但这两个方法背后的原理却不简单。
我们知道,JS是单线程语言,在浏览器中,当JS代码被加载时,浏览器会为其分配一个主线程来执行任务(函数),主线程会形成一个全局执行环境,执行环境采用栈的方式将待执行任务按顺序依次来执行。
但在浏览器中有一些任务是非常耗时的,比如http请求、定时器、事件回调等,为了保证其他任务的执行效率不被影响,JS在执行环境中维护了一个异步队列(也叫工作线程),并将这些任务放入队列中进行等待,这些任务的执行时机并不确定,只有当主线程的任务执行完成以后,才会去检查异步队列中的任务是否需要开始执行。这就是为什么setTimeout(fn,0) 始终要等到最后执行的原因。
关于单线程和异步队列问题请参考:setTimeout(0)

8、异步通讯 Ajax技术
Ajax是浏览器专门用来和服务器进行交互的异步通讯技术,其核心对象是XMLHttpRequest,通过该对象可以创建一个Ajax请求。为了防止XSS攻击,浏览器对Ajax做了限制,不允许Ajax跨域请求服务器,就是只能访问当前域名下的url。
当然,如果确信你的站点不存在跨域的风险,可以在服务端主动开启跨域请求。 也可以直接通过CORS或JSONP来实现。
JSONP是利用脚本(script)跨域能力来模拟Ajax请求。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
关于CORS的介绍请参考:跨域资源共享 CORS 详解

9、DOM对象 document
document对象里保存着整个web页面dom结构,在页面上所有的元素最终都会映射为一个dom对象。 document也提供了很多api来查找特定的dom对象,比如getElementById,querySelector等等。

10、事件系统 Event
事件是用户与页面交互的基础,到目前为止,DOM事件从PC端的 鼠标事件(mouse) 发展到移动端的 触摸事件(touch) 和 手势事件(guesture)
由于DOM结构可能会多层嵌套,因此也衍生出了两种事件流:事件捕获和事件冒泡,后者最常用。利用事件冒泡机制可以实现很多功能,比如页面点击统计。关于两种事件流的介绍请参考:事件冒泡和捕获
除此之外,在页面初始化、滚动、隐藏、返回等操作时分别内置了onload/onDOMContentLoaded、onscroll、onvisibility和onhashchange等事件,如果想要捕获这些事件,需要通过addEventLisener/attachEvent来进行绑定。

11、全局对象 window
在JS中,当一段JS代码在浏览器中被加载执行,JS引擎会在内存中构建一个全局执行环境,执行环境的作用是保证所有的函数能按照正确的顺序被执行,而window对象则是这个执行环境中的一个全局对象,window对象中内置了很多操作api和对象,document对象就是其中一个。关于JS执行环境的介绍请参考博客:深入理解JS执行细节

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复