概述
http://ife.baidu.com/ 这个网站是百度前端技术学院,从知乎上找到的,可以用来学学WEB前端基础知识。
https://codepen.io/ 在这个网站上可以写html+css+js代码,并实时显示网页效果。
HTML, CSS, JS与Web Services
https://www.zhihu.com/question/22689579
网站访问的过程

浏览器端是通过HTTP协议与知乎的服务器通信的,在这个过程中,浏览器端不断发送请求,可能是一个页面,也可能是一个地址,然后服务器端发回一个应答,之后浏览器端根据这个应答再去请求,可能是图片,音频,视频等。
HTML
类似我写的markdown文本,所以markdown可以转换为HTML代码,但是HTML有更多复杂的内容。浏览器按照默认的样式显示出列表,图片,超链接,输入框,按钮等。

CSS
我们可以不用浏览器默认的样式,可以用CSS写一些定义样式的代码,然后在 html 文件里用一个<link>标签把这些规定样式的 CSS 代码与表达内容语义的 HTML 代码关联起来。

JS
给页面添加动态效果。比如知乎问题的标签,鼠标移上去会弹出一个小窗口,这个就是 JS 实现的效果。

- 鼠标悬停到标签上时创建一个新的
<div>小窗口 - 用 JS 向知乎服务器发送一个请求,得到这个小窗口应该显示的数据,放在这个小窗口里(这就是所谓的AJAX,不用刷新就能与服务器进行交互,更新页面的一小部分~)
Web Service
要让这些形形色色的机器能够通过网络进行交互,我们就需要指明一种协议(比如 HTTP/HTTPS)和一种数据封装格式(比如 HTML/XML),Web Server 提供的 Web Service,指的就是这种协议+格式的交流体系。不过 Web Service 的生态系统和 HTML 的标准不一样,用户可以选择的协议和数据封装格式更多,普通的网站访问用的 HTTP + HTML 只是其中一种,一些封闭系统内的交流还可以自己定义一个协议和格式来用(比如 QQ)。
服务器脚本与web framework
普通网站的访问过程
- 用户操作浏览器访问,浏览器向服务器发出一个 HTTP 请求;
- 服务器接收到 HTTP 请求,Web Server 进行相应的初步处理,使用服务器脚本生成页面;
- 服务器脚本(利用Web Framework)调用本地和客户端传来的数据,生成页面;
- Web Server 将生成的页面作为 HTTP 响应的 body,根据不同的处理结果生成 HTTP header,发回给客户端;
- 客户端(浏览器)接收到 HTTP 响应,通常第一个请求得到的 HTTP 响应的 body 里是 HTML 代码,于是对 HTML 代码开始解析;
- 解析过程中遇到引用的服务器上的资源(额外的 CSS、JS代码,图片、音视频,附件等),再向 Web Server 发送请求,Web Server 找到对应的文件,发送回来;
- 浏览器解析 HTML 包含的内容,用得到的 CSS 代码进行外观上的进一步渲染,JS 代码也可能会对外观进行一定的处理;
- 用户与页面交互(点击,悬停等等)时,JS 代码对此作出一定的反应,添加特效与动画;
- 交互的过程中可能需要向服务器索取或提交额外的数据(局部的刷新,类似微博的新消息通知),一般不是跳转就是通过 JS 代码(响应某个动作或者定时)向 Web Server 发送请求,Web Server 再用服务器脚本进行处理(生成资源or写入数据之类的),把资源返回给客户端,客户端用得到的资源来实现动态效果或其他改变。
HTML
head标签
标签,<title>,<link>, <meta>, <script>, <style>, <base> 这几个标签可以用于head标签中。head标签中必须要有title标签
link标签
作用是链接外部css文件和收藏夹图标。最常用的用法是链接外部样式表,也就是css文件。
1 | <link href="https://static.zhihu.com/heifetz/main.app.216a26f4.4a0d53a7197b32815d96.css" rel="stylesheet" /> |
script标签
用在头部head标签内,作用是调用外部js文件。该标签是一个封闭标签,写法和div标签一样。另外,该标签不仅仅可以在头部head标签内使用,在body标签内部任何位置都可以使用。最终实现的效果都是一样的,通常是用在head标签内。
meta标签
标签<meta> 的属性定义了与文档相关联的名称/值对
http-equiv属性和name属性
见 https://blog.csdn.net/p3118601/article/details/89670933
style标签
div标签
div嵌套一个元素时,会出现一个问题,如果外层div没有设置border或者padding-top,那么默认,内层元素的border会和外层div的border重合,这导致一个问题,如果内层元素有margin-top,则这个margin-top的区域会在外层div的外面。
html元素
HTML 元素指的是从开始标签(start tag)到结束标签(end tag)的所有代码。
1 | <body> |
1 |
|
html格式化
就是加粗,斜体之类的。
html css
用style标签定义html中的样式
1 |
|
head标签中必须要有title标签
| 标签 | 描述 |
|---|---|
| style | 定义样式,比如字体,对齐 |
| link | 定义资源引用 |
| div | 定义文档中的节或区域 |
| span | 定义文档中的行内的小块或区域 |
外部样式表
1 |
|
html块级元素
html的<div>元素是块级元素,它是可用于组合其他 HTML 元素的容器。如果与 CSS 一同使用,<div> 元素可用于对大的内容块设置样式属性。<div>元素的另一个常见的用途是文档布局。
HTML <span> 元素是内联元素,可用作文本的容器。当与 CSS 一同使用时,<span> 元素可用于为部分文本设置样式属性。
html类
为相同的类设置相同的样式,或者为不同的类设置不同的样式。
1 |
|
每个块级元素如<div>和行内元素如<span>,可以设置class 属性,然后在html head标签中用style标签将所有这个class的的块级元素和行内元素设置样式。
1 |
|
如上面这个.cities 就是一个选择器,可以选择所有class为”.cities”的元素,然后执行样式,我做csp时,有听说过标签选择器,id选择器等,如果要选择class为”cities”的div块级元素执行样式,则可以写
1 | <style> |
这就是一个标签选择器+类选择器。我记得id选择器是这样写的#id1。
html布局
设一个有两个div,一大一小,小的div在大的div里面du,而小的div和大div直接的距离就zhi叫外边距,用daomargin、margin-left、margin-right、margin-top、margin-bottom来设置距离,如margin:10px。而小div和小DIV里面的文字之间的距离就叫内边距,用padding来设置,如同margin一样。
Bootstrap(响应式设计)
js脚本
下面是使用js的简单例子。
1 |
|
当鼠标在画布内移动时,会触发事件onmousemove,这个事件接着触发js方法cnvs_getCoordinates(e),这个方法就是读取鼠标所在的坐标,然后写成html格式,放在id=”xycoordinates”的div中。
CSS
当同一个 HTML 元素被不止一个样式定义时,会使用哪个样式呢?
一般而言,所有的样式会根据下面的规则层叠于一个新的虚拟样式表中,其中数字 4 拥有最高的优先权。
- 浏览器缺省设置
- 外部样式表
- 内部样式表(位于 标签内部)
- 内联样式(在 HTML 元素内部)
很多属性,比如clear,应该写在css文件中,而不要内联在html中。
CSS框模型

CSS定位
div、h1 或 p 元素常常被称为块级元素。这意味着这些元素显示为一块内容,即“块框”。与之相反,span 和 strong 等元素称为“行内元素”,这是因为它们的内容显示在行中,即“行内框”。
把一些文本添加到一个块级元素(比如 div)的开头。即使没有把这些文本定义为段落,它也会被当作段落对待,在这种情况下,这个框称为无名块框;块级元素的文本行也会发生类似的情况。假设有一个包含三行文本的段落。每行文本形成一个无名框。
1 | <head> |
我发现可以通过指定margin属性,padding属性,line-height属性等来给块定位。

CSS 浮动

左图出现了一个问题。因为浮动元素脱离了文档流,所以包围图片和文本的 div 不占据空间。
所以我们只能添加一个空元素并且清理它。
1 | .news { |
如何清除浮动
- 在父级元素的末尾添加clear类的空div,并设置其clear属性为both。清除浮动的原理是:clear类的div只能放在浮动元素的后面,因为浮动元素占据了空间,由于clear类的div不是浮动的,父级元素为了包含它,只能扩展到clear类的div所在的位置,这样就顺便包含了浮动元素。
- 父级元素定义overflow属性为hidden。为什么加入overflow:hidden即可清除浮动呢?那是因为overflow:hidden属性相当于是让父级紧贴内容,这样即可紧贴其对象内内容(包括使用float的div盒子),从而实现了清除浮动。
相对定位与绝对定位
绝对定位 absolute不占位置完全浮动,相对定位 relative会占有位置。
绝对定位是根据其定位不是static的祖先元素来定位的
所以我们在使用时通常设置父元素相对定位(有两个目的,其一是要让父元素占位置,其二是为了让子元素设置绝对定位时会根据父元素定位),子元素设置绝对定位.
CSS让div层悬浮在最上方
1 | div{ |
CSS选择器
类选择器还是 ID 选择器?
区别 1:只能在文档中使用一次
与类不同,在一个 HTML 文档中,ID 选择器会使用一次,而且仅一次。
区别 2:不能使用 ID 词列表
不同于类选择器,ID 选择器不能结合使用,因为 ID 属性不允许有以空格分隔的词列表。
属性选择器
当某个属性是某个值时,选择该元素。
1 | a[href="http://www.badu.com"]{ |
子代选择器
1 | div>span{} |
后代选择器
文档流
将窗体自上而下分成一行一行,并在每行中按从左至右依次排放元素,称为文档流,也称为普通流。HTML中全部元素都是盒模型,盒模型占用一定的空间,依次排放在HTML中,形成了文档流。
元素脱离文档流之后,将不再在文档流中占据空间,(但是元素内的内容依然占据着空间),而是处于浮动状态(可以理解为漂浮在文档流的上方)。脱离文档流的元素的定位基于正常的文档流,当一个元素脱离文档流后,依然在文档流中的其他元素将忽略该元素并试图填补其原先的空间,(当看到这部分空间有内容占据时,就自动向顺着文档流的方向移动本元素的位置,直到找到合适的位置)
注意:若没有设置脱离文档流,块级元素在文档流中都是从上到下排列的,即使设置了width,也是一样。
如何脱离文档流
- 元素设置float属性
- 元素的position属性设置为absolut
margin, padding
通过举出不同的关于margin, padding的例子,来理解它们
例1,两个div元素通过浮动横向放置

我设置div的width和height都是100px,设置了margin是10px,padding是10px,所以整个div是140长的正方形。两个div横向放置时并不会出现外边距合并
例2

1 | <head> |
上一层的div,背景为蓝色的那个,设置了padding=10px,然后里面的div跟例1一样。说明内层的div,包括margin部分,会严格在外层div的padding里面,内层div的margin和外层div的padding并不会合并。
例3,两个div纵向放置

两个div纵向放置时并会出现上面的div的下外边距和下面的div的上外边距合并的情况
例4,外层wrap和内层的block1都设置margin

1 | <head> |
可以发现,从左到右是body的margin-left,.wrap的margin-left,.block1的margin-left;但是,上面,.wrap的margin-top覆盖了body,.block1的margin-top。原因是,margin-left和margin-right会相对于水平方向的margin推开,而margin-top和margin-bottom会相对于垂直方向的border或者padding推开。
在这里,.wrap和.block1的border-top重叠了,这个问题我在宠物商店的制作中踩过坑(内层div的margin超出了外层的border范围),原因是,这里外层的.wrap没有设置border和padding的长度,而且外层的.wrap的margin默认为0,所以内层.block的margin-top覆盖了外层.wrap的长度为0的margin-top,所以显示出来就是,外层.wrap的border-top和内层的.block1的border-top重合了。解决方案就是,设置外层的padding或者border
比如,我设置,.wrap的padding是10px。

例5

1 | <head> |
当子元素都浮动或者display:inline-block时,外边距不再合并
JavaScript
基础
ECMAScript是JS的标准,各个浏览器厂商对ES有自己的实现,比如Chrome的v8,这个v8引擎很快,而且node.js用的也是v8引擎。
JavaScript包含:
- ECMAScripte
- DOM(Document Object Model)
- BOM(Browser Object Model)
JS的特点:
- 解释型语言
- 动态语言(变量可以保存任意类型数据,类似于python)
- 基于原型的面向对象
1 | /* |
1 |
|
1 | var a; //声明一个变量 |
1 | /* |
1 | /* |
1 | /* |
字符串
1 | var str = "abcd" |
Array
Array.prototype.shift函数表示删除第一个元素,并返回第一个元素
Array.prototype.indexOf表示寻找某个元素的下标
Array.prototype.map方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
1 | var arr = [1,2,3,4] |
对象
内建对象:Math String Number等
宿主对象
有js的运行环境提供的对象,主要由浏览器提供的对象:
比如 BOM DOM
自定义对象
1 | /* |
1 | /* |
1 | /* |
1 | /* |
1 | /* |
常见的六种继承方式
原型链继承
这种方式实现的本质是通过将子类的原型指向了父类的实例。子类的实例就可以通过__proto__访问到父类的实例,这样就可以访问到父类的私有方法,然后再通过__proto__指向父类的prototype就可以获得父类原型上的方法。
1 |
|
Person是一个对象,Person.prototype.constructor才是我们定义的那个f Person()函数;Person由Function.prototype.constructor构造而来,所以有prototype属性,同时Person也继承自Function,所以Person._proto_等于Function.prototype。

我们在子类中为父类添加新的方法或者重写父类的方法时,切记一定要先为prototype指定父类的实例。
1 | /* |
特点:
- 父类可以新增原型方法、原型属性,子类都能访问到
缺点:
- 无法实现多继承
- 来自原型对象的所有属性被所有实例共享
- 创建子类实例时,无法向父类构造函数传参
prototype的由来
参考:http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
若没有prototype,则每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。比如构造函数中设置了name和age, species属性,则每个实例对象改变了自己的属性,并不会影响到别的实例对象。
考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。这个属性包含一个对象(以下简称”prototype对象”),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。比如,species属性就可以放在prototype中。
1 | DOG.prototype = { species : '犬科' }; |
实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。而实例对象引用的属性和方法都放在__proto__中。

如上图所示,当你使用foo构造器构造了一个实例对象f1后,f1显然是通过function foo() 这个构造器(构造函数)创建的,所以f1实例对象中有一个指向function foo()的属性:constructor。但是如果直接把constructor放在实例对象里面,就像name属性一样,那么对于所有foo的实例对象,都会冗余地存储constructor,constructor是一样的,为什么要占用存储空间存储那么多次,所以就把constructor放在了foo.prototype中。
借用构造函数继承
在子类构造函数中调用父类的call()函数实现继承
1 |
|
特点:
- 解决了原型链继承中子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 只能继承父类的属性和方法,不能继承父类原型的属性和方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。
原型链+借用构造函数的组合继承
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
1 |
|

这是结果。我们可以看到,每个对象的构造函数是存在于它的__proto__中的。
如果每个Person也通过组合继承的方式继承自Object,那么Student也可以继承Object的属性且不是共享实例的。
特点:
- 经过这种继承方式,Student对象可以继承Person对象的属性和方法,且不是共享实例的,但是继承了Person对象的原型属性或方法的实例。
- 可以传参
- 函数可复用
缺点:
- 调用了两次父类构造函数
组合继承优化
1 |
|
Student继承了Person原型的所有属性和方法,这是最完美的继承方法。
总结
果然,组合继承优化才是最合适的继承方案。
把父类的非prototype属性作为子类的非prototype属性,这样就使得每个子类实例不会共享父类的非prototype属性,这就解决了原型链继承的一个缺点:子类实例共享父类属性。
通过在子类构造函数中调用
FatherClass.call(this)来实现1功能,这样就可以向父类构造函数中传参,解决了原型链继承的不能向父类构造函数传参的缺点。通过
ChildClass.prototype = Object.create(FatherClass.prototype)代码,得到这样的原型链:ChildClass.prototype(初始为空,通过ChildClass.prototype.func1 = function()可以添加属性)
ChildClass.prototype.__proto__(这个就是FatherClass.prototype)。这样的话,所有子类实例既可以共享父类prototye中的属性,又不用在每次实例化子类的时候两次实例化父类;可以方便地通过
ChildClass.prototype.func1 = function()代码扩充子类原型,而不影响父类原型,非常简洁。
还有一点,每次定义对象的时候,要把数据属性放在构造函数中,把函数属性放在prototype中,这样配合使用组合继承优化,非常方便。在我看vue源码的时候,就发现,很多对象的定义都是遵循上述原则的,原因是,函数可以共享使用,而数据在所有实例中不能共享。
看一个官网上组合继承优化的例子。
1 | // Shape - 父类(superclass) |
DOM
文档对象模型
查找HTML元素
通过id查找HTML元素
1 | document.getElementById('id名称'); |
通过标签名查找HTML元素
1 | document.getElementByTagName('tag') |
通过类名查找HTML元素
1 | document.getElementByClassName('class') |
DOM HTML
创建动态的HTML内容:
1 | document.write('Hello') |
改变HTML元素内容
1 | var a = document.getElementById('id') |
改变元素属性
1 | var a = document.getElementById('id') |
DOM CSS
改变CSS样式
1 | var a = document.getElementById('id') |
DOM事件
下面是一个使用DOM事件的例子
1 | <div id="coordiv" style="float:left;width:199px;height:99px;border:1px solid #c3c3c3" onmousemove="cnvs_getCoordinates(event)" onmouseout="cnvs_clearCoordinates()"></div><br /> |

DOM事件体现了浏览器端的交互。
BOM
浏览器对象模型
window: 浏览器窗口对象,其成员包括所有的全局变量,函数和对象
screen:屏幕对象
location:位置对象,用于获取当前页面的URL地址,还可以把浏览器重定向到新的指定页面

history
1
2
3
4
5
6
7
8
9
10<!--
获得历史记录信息
-->
<button onclick="history.back()">
back
</button>
<button onclick="history.forward()"
forward
</button>
navigator:
setTimeout()异步方法
1 | function func(){ |
setInterval()
与setTimeout()方法类似,但这是每隔一段时间就执行程序。
异步方法
异步方法一般要求回调函数
有个很重要的点:比如
1 | function getDogZhuliangProp() { |
我想通过http请求获取数据,然后赋值给res,返回,但是上面的代码是错的,
原因是,用到了axios用到了ajax请求,这是异步的,这意味着当执行axios.get()时
会并行地执行return res,这就导致res并没有数据,却直接返回了。
js中的class
js的class仅仅为一个语法糖,是在原先构造函数的基础上出现的class,仅仅如此。所以使用构造函数构造类,或者使用class语法糖构造类都是相同的。具体还是使用prototype和this来进行模拟类。
类声明
1 | class Rectangle { |
匿名类
1 | let Rectangle = class { |
static
为一个静态方法,该静态new出的来的对象不能进行使用。
1 | class Point { |
extends
类不可继承没有构造函数的对象
1 | class Animal { |
super
使用super调用超类
js中的跨域问题
什么是跨域
跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况下不能这么做,它是由浏览器的同源策略造成的。
所谓同源是指,域名,协议,端口均相同。
为什么要跨域
既然有安全问题,那为什么又要跨域呢? 有时公司内部有多个不同的子域,比如一个是location.company.com ,而应用是放在app.company.com , 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。
解决跨域问题
跨域资源共享(CORS)
CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
1 | //指定允许其他域名访问 |
jsonp
JSONP的原理:通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。(即用javascript动态加载一个script文件,同时定义一个callback函数给script执行而已。)
在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。

ajax是要求服务器发送回来一个json文件,但是jsonp是引用服务器的一个php代码,这个代码到了浏览器端后,然后浏览器端以自己的php代码中的数据为参数,来这执行这个回调函数。因此,要实现jsonp,浏览器端要指明回调函数,服务器端要在代码中体现数据。
jquery实现jsonp
$.ajax()方法
1
2
3
4
5
6
7
8
9$.ajax({
url:'http://外域.com/xxx.php',
dataType:"jsonp",
jsonp: "callback",
jsonpCallback:"ooo",
success:function(data){
console.log(data);
}
});其中,
jsonp: "callback"是设置路径里的参数名。你这里写callback,那么jQuery发送请求的时候路径里就用callback=还有,
jsonpCallback:"ooo"是设置函数名。你这里写ooo,那么php必须返回ooo为函数名的内容。$.get()方法
$.get()方法的基本用法是同域名抓数据,是真正的ajax原理。而高级用法就是抓jsonp数据。写法是:
1
2
3$.get('http://外域.com/xxx.php', {各种数据}, function(data) {
console.log(data);
}, 'jsonp');$.getJSON()方法
$.getJSON()方法跟$.get()方法类似,区别在于:
1、$.getJSON()的最后一个参数不用写,而$.get()方法的最后一个参数必须是’jsonp’。
2、$.getJSON()虽然省掉了最后一个参数,但这时候,你需要在路径中带上
callback=?或者abc=?这样的字眼,这样jQuery会自动判断,既然你带上了参数,而且参数值是问号,那么jQuery就认为你想搞jsonp勾当,如果你不加任何参数,或者参数值不是问号,那么jQuery就认为你不想搞jsonp勾当,那么这时候$.getJSON()方法就全等于$.get(…,…, ‘json’)方法。
jsonp的优缺点
优点:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制
缺点:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
js中的运行时上下文context,以及call,apply,bind
以前遇到过,当函数通过对象的方法执行的时候,this是这个对象,当函数作为全局函数的时候,this是window。这就是js中的运行时上下文。
apply, call
apply, call完全一样,但是语法稍有不同。
在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
1 | function fruits() {} |
但是如果我们有一个对象banana= {color : “yellow”} ,我们不想对它重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:
1 | banana = { |
类(伪)数组使用数组方法
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。
1 | var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*")); |
bind
bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
1 | var foo = { |
用js实现bind
1 | //bind源码实现 |
节流函数与防抖函数
1 | function throttle(fn,delay){ |
1 | debounce: function (fn, delay) { |
为什么经常用fn.apply(this)的写法
因为给事件加回调函数fn的时候,不知道调用这个函数的是window还是定义fn的对象,但是不管是哪个,fn函数内的this肯定都是定义fn的那个对象,所以直接使用fn.apply(this)肯定没有错。
注意:要注意词法作用域的问题,比如上面debounce函数第3行和第7行,要用箭头函数来使this按照词法作用域来绑定到外层的对象,防止在调用回调的时候,this指向window对象。
js实现排序
快排
1 | function quickSort(arr,begin,end){ |
node.js
用node.js开发web服务器。
https://www.bilibili.com/video/BV16E41137ZU?p=21
什么是node.js
node.js是一个js runtime built on chrome’s v8 js engine.
node.js不是一门语言
node.js不是库,不是框架
node.js是一个js运行时环境
node.js可以解析和执行js代码
现在的js可以脱离浏览器执行,归功于node.js
node.js中的js没有BOM, DOM, 只符合EcmaScript标准,也就是些语法
node.js提供了一些服务器级别的操作api: 文件读写,网络服务的构建,网络通信,http服务器,等。
node.js uses an event-driven non-blocking I/O model that makes it lightweight and efficient.
node.js’s package ecosystem , npm, is the largest ecosystem of open source libraries in the world.
B/S编程模型
任何服务端技术这种B/S编程模型都是一样的,与语言无关,NODE只是作为我们学习B/S编程模型的一个工具而已,
模块化编程
以前js只能通过script 标签来加载,但是在node中可以像@import()一样来引用加载js脚本
异步编程
回调函数
promise
async
generator
express web开发框架
es6
一种新的语法
学习资源
http://javascript.ruanyifeng.com
www.nodebeginner.org/index-zh-cn.html
https://github.com/alsotang/node-lessons
官方API
hello world
使用node [文件名]执行对应的.js文件
如果要用node执行.js文件,这个文件中不能有window和document对象,因为node中没有BOM和DOM
1 | /* |
http服务
0-1023是公认端口号,即已经公认定义或为将要公认定义的软件保留的,而1024-65535是并没有公共定义的端口号,用户可以自己定义这些端口的作用。
下面代码简单地创建一个服务器,当请求来了时,就在控制台输出信息。
1 | /* |
当请求到来时,网页有红色的hellow。
1 |
|
根据不同的请求,返回不同的页面
1 |
|
node中的js
ES
具名的核心模块
如
fsospath等模块第三方模块
用户自定义模块
模块系统
require
exports
1 | //1.js |
1 | //2.js |
输出:
1 | { foo: 'hello', add: [Function], age: 18 } |
响应内容类型
content-type
1 | var http = require("http"); |
发送文件中的内容
可以用于向浏览器中传送各种文件,比如.html文件。
1 | var http = require("http"); |
web服务器开发
请求对象Request
响应对象Response
在Node中使用模板引擎
模板引擎的基本思路就是字符串替换。根据html中的标记替换成自己想加入的html代码。
1 | data = data.toString() |
安装art-template包
在D:\documents\VSCode\WEB\node.js\下执行命令
1 | npm install art-template |
就可以把art-template安装到这个目录下了。在哪个文件夹下运行npm,就安装在哪。在这个目录下有一个node_modules文件夹,所有包就在这里面了。
在客户端中使用art-template
下面是使用art-template进行模板引擎的例子。
1 |
|
在node中使用art-template
1 | var http = require("http"); |
统一处理静态资源
为了方便地统一处理静态资源,所以我们约定把所有静态资源放在根目录下的public文件夹下。
处理表单
表单标签必须要有name属性。
表单的提交分为:
- 默认的提交方法
- 异步提交方式
当表单提交时,发送的http包是包含动态的表单数据的,非常复杂,所以要用到node.js中的一个包:url。只要知道请求的地址是/pinglun时,就知道是表单提交了。
<input>中有一个action和method属性很重要。action表示url地址,method有’get’和‘post’两种值。
1 | var pasedUrl = url.parse('/pinglun/?name=jack&message=eeee',true) |
表单提交重定向
1 | /* |
修改完代码自动重启
nodemon
tips
w3school
MDN