遗漏点

词法作用域

作用域链是根据函数定义时候的位置确定的而不是在调用时。–这就是“词法”作用域

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对象的使用

分片上传

我们在进行文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器。

假如需要做到这一步,我需要解决两个问题:

  1. 怎么切割?
  2. 怎么得知当前传输的进度?

首先切割的问题:因为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截图后,需要在网页上进行粘贴操作。

粘贴图片我们需要解决下面几个问题

  1. 监听用户的粘贴操作
  2. 获取到剪切板上的数据
  3. 将获取到的数据渲染到网页中

首先我们可以通过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="" />';
                }
            }
        }
});

这样我们就可以监听到用户的粘贴操作,并且将用户粘贴的图片文件实时的渲染到网页之中了。

猜你喜欢

转载自blog.csdn.net/Maomengdie1998/article/details/87346182