词法作用域
作用域链是根据函数定义时候的位置确定的而不是在调用时。–这就是“词法”作用域
CSS优先级
!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
<style type="text/css">
span {
color: green;
}
.red {
color: red;
}
#blue {
color: blue;
}
</style>
<span id="blue" class="red" style="color:black;">Hello World</span>
结果为:black
img标签
-
img标签中的alt属性的作用是提供替代图片的信息,使屏幕阅读器能获取到关于图片的信息
-
title是鼠标一上去之后显示的文本
i标签和em标签异同
- i标签只是单纯的样式标签,表现斜体的样式,但是语义上与普通文本无异;
- em标签在样式上表示为斜体,同时在语义上也表示为斜体。
- em标签可以被设备识别,而i标签不能被识别。
编码格式
-
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。UTF-8用1到6个字节编码UNICODE字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。
-
GBK是汉字编码,是双字节码,可表示繁体字和简体字。
-
ISO8859-2 字符集,也称为 Latin-2,收集了 东欧 字符。
栅格系统
.col-xs-超小屏幕 手机 (<768px),
.col-sm-小屏幕 平板 (≥768px),
.col-md-中等屏幕
.col-lg-桌面显示器 (≥992px)(栅格参数)
浏览器在一次 HTTP 请求中,需要传输一个 4097 字节的文本数据给服务端,可以采用POST方式
原因:
IndexdDB 是 HTML5 的本地存储,把一些数据存储到浏览器(客户端)中,当与网络断开时,可以从浏览器中读取数据,用来做一些离线应用。
Cookie 通过在客户端 ( 浏览器 )记录信息确定用户身份,最大为 4 kb 。
url 参数用的是 get方法,从服务器上获取数据,大小不能大于 2 kb 。
Session 是服务器端使用的一种记录客户端状态的机制 。
post 是向服务器传送数据,数据量较大。
local Storage 也是 HTML5的本地存储,将数据保存在客户端中(一般是永久的)。
innerHTML
<div id="info" style="display:block">
<p>请填写</p>
</div>
<script>
console.log(document.getElementById("info").innerHTML);
</script>
结果:
<p>请填写</p>
typeof
typeof Symbol() //"symbol"
typeof Number() //"number"
typeof String() //"string"
typeof Function() //"function"
typeof Object() //"object"
typeof Boolean() //"boolean"
typeof null //"object"
typeof undefined //"undefined"
如何正确判断 this?箭头函数的 this 是什么?
function foo() {
console.log(this.a)
}
var a = 1
foo()
const obj = {
a: 2,
foo: foo
}
obj.foo()
const c = new foo()
1.对于直接调用 foo 来说,不管 foo函数被放在了什么地方,this 一定是 window
2.对于 obj.foo()来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象
3.对于 new 的方式来说,this 被永远绑定在了 c 上面,不会被任何方式改变 this
箭头函数中的this
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())
首先箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this。在这个例子中,因为包裹箭头函数的第一个普通函数是 a,所以此时的 this 是 window。另外对箭头函数使用 bind 这类函数是无效的。
this 的规则
首先,new 的方式优先级最高,接下来是 bind 这些函数,然后是 obj.foo() 这种调用方式,最后是 foo 这种调用方式,同时,箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。
层级显示优先级: frameset > 表单元素 > 非表单元素
MVC
-
Model(模型) 是应用程序中用于处理应用程序数据逻辑的部分。
通常模型对象负责在数据库中存取数据。
-
View(视图) 是应用程序中处理数据显示的部分。
通常视图是依据模型数据创建的。
-
Controller(控制器) 是应用程序中处理用户交互的部分。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC模型:是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离。
- 首先让我们了解下MVC(Model-View-Controller)三元组的概念:
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作,。
- 在标准的MVC中模型能主动推数据给视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图),但在Web开发中模型是无法主动推给视图(无法主动更新用户界面),因为在Web开发是请求-响应模型。
Browser 对象
history Location navigator screen
关于Javascript中数字的部分知识总结
- Javascript中,由于其变量内容不同,变量被分为基本数据类型变量和引用数据类型变量。基本类型变量用八字节内存,存储基本数据类型(数值、布尔值、null和未定义)的值,引用类型变量则只保存对对象、数组和函数等引用类型的值的引用(即内存地址)。
- JS中的数字是不分类型的,也就是没有byte/int/float/double等的差异。
- JavaScript内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。
判断输出结果
console.log(1+ "2"+"2");
做加法时要注意双引号,当使用双引号时,JavaScript认为是字符串,字符串相加等于字符串合并。
因此,这里相当于字符串的合并,即为122.
console.log(1+ +"2"+"2");
第一个+"2"中的加号是一元加操作符,+"2"会变成数值2,因此1+ +“2"相当于1+2=3.
然后和后面的字符串“2”相合并,变成了字符串"32”.
console.log("A"- "B"+"2");
“A”-“B"的运算中,需要先把"A"和"B"用Number函数转换为数值,其结果为NaN,在剪发操作中,如果有一个是NaN,则结果是NaN,因此"A”-"B"结果为NaN。
然后和"2"进行字符串合并,变成了NaN2.
console.log("A"- "B"+2);
根据上题所述,“A”-"B"结果为NaN,然后和数值2进行加法操作,在加法操作中,如果有一个操作数是NaN,则结果为NaN。
var x=0;
switch(++x)
{
case 0: ++x;
case 1: ++x;
case 2: ++x;
}
console.log(x);
switch中,对x+1,此时x为1,然后进入case 1 中,又执行++ x,此时x变为2;由于case 1中没有break,然后继续执行 case 2,执行++x,所以x变成3
var m = 1, j = k = 0;
function add(n) {
return n = n + 1;
}
y = add(m);
function add(n) {
return n = n + 3;
}
z = add(m);
console.log(y);
console.log(z);
- js里面没有函数重载的概念,在其他语言中(如java)java中,可以存在同名函数,
只要传入的参数数量或者类型不同即可。在js中,定义了两个同名函数后,
后面的函数会覆盖前面定义的函数。结合这道题来说,由于函数声明提升,
所以函数声明会提前,由于存在同名函数,后面的add函数将覆盖第一个add函数,
所以两次调用add()返回的值是相同的。也就是y,z都为4.
假设 output 是一个函数,输出一行文本。下面的语句输出结果是什么?
output(typeof (function() {output(“Hello World!”)})());
Hello World! undefined
1.先立即执行匿名函数,输出Hello World!
2.函数执行后无返回值,则输出未定义
运算符优先级
假设val已经声明,可定义为任何值。则下面js代码有可能输出的结果为:
console.log('Value is ' + (val != '0') ? 'define' : 'undefine');
- define
- 加号优先级高于 三目运算。低于括号。 所以括号中无论真假 加上前边的字符串都为 TRUE 三目运算为TRUE是 输出 define
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | 空字符串 |
Number | 任何非零数字值(包括无穷大) | 0和Null |
Object | 任何对象 | null |
Undefined | Undefined |
JavaScript的全局函数
setTimeout是window的一个方法,如果把window当做全局对象来看待的话,它就是全局函数。严格来讲,它不是。全局函数与内置对象的属性或方法不是一个概念。全局函数它不属于任何一个内置对象。JavaScript 中包含以下 7 个全局函数escape( )、eval( )、isFinite( )、isNaN( )、parseFloat( )、parseInt( )、unescape( )。
ES6
function * gen() {
yield 1;
yield 2;
yield 3;
}
function*声明 (function关键字后跟一个星号)定义了一个 生成器函数 ( generator function ),它返回一个 Generator 对象。
promise
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致 - then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
执行顺序
console.log('one');
setTimeout(() => {
console.log('two');
}, 0);
console.log('three');
- 回调时,被回调的函数会被放在event loop里,等待线程里的任务执行完后才执行event loop里的代码。 因此,上述代码会先把线程里的执行完后,再执行event loop里的setTimeout函数.。
- setTimeout的方式(注册事件):有两个参数,第一个参数是函数,第二参数是时间值。调用setTimeout时,把函数参数,放到事件队列中。等主程序运行完,再调用。
- one第一个执行就不用说了,而后面的函数用了settimeout,这个函数是指定毫秒数后调用函数或者是计算表达式的,而settimeout设置为0s,你以为他会马上执行?其实他被js放在队列中了,要等别人执行完了,他才会执行。所以如果你想让后面的语句先执行在执行本身的话就用settimeout(0)吧。 ps:中间的函数没注意大小写
也可以定义 生成器函数 使用构造函数 GeneratorFunction 和一个 function* expression
Javascript异步编程的4种方法
1. 回调函数
这是异步编程最基本的方法。
-
回调函数的优点是简单、容易理解和部署。
-
缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
例子:
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
2. 事件监听
采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
- 这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。
- 缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
例子:
以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。
f1.on('done', f2);
上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}
f1.trigger(‘done’)表示,执行完成后,立即触发done事件,从而开始执行f2。
3. 发布/订阅
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。这个模式有多种实现,下面是一个小例子。
首先,f2向"信号中心"jQuery订阅"done"信号。
jQuery.subscribe("done", f2);
然后,f1进行如下改写:
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done");
}, 1000);
}
jQuery.publish(“done”)的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。
此外,f2完成执行后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
- 这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
4. Promises对象
-
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
-
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
例子
f1的回调函数f2,可以写成:
f1().then(f2);
f1要进行如下改写(这里使用的是jQuery的实现):
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
dfd.resolve();
}, 500);
return dfd.promise;
}
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
比如,指定多个回调函数:
f1().then(f2).then(f3);
再比如,指定发生错误时的回调函数:
f1().then(f2).fail(f3);
- 而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。、
DNS
- DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53。
- DNS是域名系统的缩写,他是由解析器和域名服务器组成的。域名服务器是保存有该网络中所有主机的域名和对应的ip地址。域名必对应一个ip地址,而ip地址不一定有域名。将域名映射为ip地址的过程就称为域名解析。域名虽便于人们记忆,但计算机只能互相认识ip地址。DNS就是进行域名解析的服务器。 DNS主要是UDP协议,但是当请求字节过长超过512字节时,是用TCP协议,它可以分割成多个片段。
blob对象介绍
一个 Blob对象表示一个不可变的, 原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式 blob对象本质上是js中的一个对象,里面可以储存大量的二进制编码格式的数据。
创建blob对象
创建blob对象本质上和创建一个其他对象的方式是一样的,都是使用Blob() 的构造函数来进行创建。 构造函数接受两个参数:
第一个参数为一个数据序列,可以是任意格式的值。
第二个参数是一个包含两个属性的对象{ type: MIME的类型, endings: 决定第一个参数的数据格式,可以取值为 “transparent” 或者 “native”(transparent的话不变,是默认值,native 的话按操作系统转换) 。 }
Blob()构造函数允许使用其他对象创建一个Blob对象,比如用字符串构建一个blob
var debug = {hello: "world"};
var blob = new Blob([JSON.stringify(debug, null, 2)],
{type : 'application/json'});
既然是对象,那么blob也拥有自己的属性以及方法
属性
-
Blob.isClosed(只读)
布尔值,指示Blob.close()是否在该对象上调用过。关闭的blob对象不可读。
-
Blob.size(只读)
Blob对象中所包含数据的大小(字节)。
-
Blob.type(只读)
一个字符串,表明Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串。
方法
-
Blob.close()
关闭Blub对象,以便能释放底层资源。
-
Blob.slice([start[,end[,contentType]]])
返回一个新的Blob对象,包含了源Blob对象中指定范围内的数据。其实就是这个blob中的数据进行切割,我们在对文件进行分片上传的时候需要使用到这个方法。
这些属性和方法在HTML5提供的File接口中也都有。其实File接口就是基于Blob,继承blob功能并将其扩展为支持用户系统上的文件,也就是说:File接口中的File对象就是继承自Blob对象。
blob对象的使用
分片上传
我们在进行文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器。
假如需要做到这一步,我需要解决两个问题:
- 怎么切割?
- 怎么得知当前传输的进度?
首先切割的问题:因为File文件对象是继承与Blob对象的因此File对象也拥有slice这个方法,我们可以使用这个方法将任何一个File文件进行切割。
var BYTES_PER_CHUNK = 1024 * 1024; // 每个文件切片大小定为1MB .
var blob = document.getElementById("file").files[0];
var slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
var blobs = [];
slices.forEach(function(item, index) {
blobs.push(blob.slice(index,index + 1));
});
通过上面的方法,我就得到了一个切割之后的File对象组成的数组blobs;接下来要做的事就是将这些文件分别上传到服务器。在HTTP1.1以上的协议中,有Transfer-Encoding这个编码协议,用以和服务器通信,来得知当前分片传递的文件进程。这样解决了两个问题,我们不仅可以对文件进行分片上传,并且能够得到文件上传的进度。
粘贴图片
blob还有一个应用场景,就是获取剪切板上的数据来进行粘贴的操作。例如通过QQ截图后,需要在网页上进行粘贴操作。
粘贴图片我们需要解决下面几个问题
- 监听用户的粘贴操作
- 获取到剪切板上的数据
- 将获取到的数据渲染到网页中
首先我们可以通过paste事件来监听用户的粘贴操作:
doucument.addEventListener('paste',function(e){
console.log(e);
});
然后通过事件对象中的clipboardData对象来获取图片的文件数据。
clipboardData对象介绍
clipboardData对象实际上是一个DataTransfer类型的对象,DataTransfer是拖动产生的一个对象,但实际上粘贴事件也是它。
clipboardData的属性介绍
属性 | 类型 | 说明 |
---|---|---|
dropEffect | String | 默认是none |
effectAllowed | String | 默认是uninitialized |
files | FileList | 粘贴操作为空List |
items | DataTransferItemList | 剪切板中的各项数据 |
types | Array | 剪切板中的数据类型 该属性在Safari下比较混乱 |
items介绍
items是一个DataTransferItemList对象,自然里面都是DataTransferItem类型的数据了。
属性
items的DataTransferItem有两个属性kind和type
属性 | 说明 |
---|---|
kind | 一般为string或者file |
type | 具体的数据类型,例如具体是哪种类型字符串或者哪种类型的文件,即MIME-type |
方法
方法 | 参数 | 说明 |
---|---|---|
getAsFile | 空 | 如果 kind 是 file ,可以用该方法获取到文件 |
getAsString | function(str) | 如果 kind 是 string ,可以用该方法获取到字符串str |
type介绍
一般types中常见的值有text/plain、 text/html、 Files。
值 | 说明 |
---|---|
text/plain | 普通字符串 |
text/html | 带有样式的html |
Files | 文件(例如剪切板中的数据) |
有了上面这些方法,我们可以解决第二个问题即获取到剪切板上的数据。
document.addEventListener('paste', function (e) {
console.info(e);
var cbd = e.clipboardData;
for(var i = 0; i < cbd.items.length; i++) {
var item = cbd.items[i];
console.info(item);
if(item.kind == "file"){
var blob = item.getAsFile();
if (blob.size === 0) {
return;
}
console.info(blob);
}
}
});
最后我们需要将获取到的数据渲染到网页上。
其实这个本质上就是一个类似于上传图片本地浏览的问题。我们可以直接通过HTML5的File接口将获取到的文件上传到服务器然后通过讲服务器返回的url地址来对图片进行渲染。也可以使用fileRender对象来进行图片本地浏览。
fileRender对象简介
从Blob中读取内容的唯一方法是使用 FileReader。
FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。
方法名 | 参数 | 描述 |
---|---|---|
readAsBinaryString | file | 将文件读取为二进制编码 |
readAsText | file,[encoding] | 将文件读取为文本 |
readAsDataURL | file | 将文件读取为二进制编码 |
abort | (none) | 终端读取操作 |
FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。
事件 | 描述 |
---|---|
onabort | 中断 |
onerror | 出错 |
onloadstart | 开始 |
onprogress | 正在读取 |
onload | 成功读取 |
onloadend | 读取完成,无论成功失败 |
通过上面的方法以及事件,我们可以发现,通过readAsDataURL方法及onload事件就可以拿到一个可本地浏览图片的DataURL。
最终代码如下:
document.addEventListener('paste', function (e) {
console.info(e);
var cbd = e.clipboardData;
var fr = new FileReader();
var html = '';
for(var i = 0; i < cbd.items.length; i++) {
var item = cbd.items[i];
console.info(item);
if(item.kind == "file"){
var blob = item.getAsFile();
if (blob.size === 0) {
return;
}
console.info(blob);
fr.readAsDataURL(blob);
fr.on<x>load=function(e){
var result=document.getElementById("result");
//显示文件
result.innerHTML='<img src="' + this.result +'" alt="" />';
}
}
}
});
这样我们就可以监听到用户的粘贴操作,并且将用户粘贴的图片文件实时的渲染到网页之中了。