-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 63.8 KB
/
content.json
1
[{"title":"url,enter后发生了什么","date":"2017-08-25T06:20:58.000Z","path":"2017/08/25/url-enter后发生了什么/","text":"一、浏览器解析URL  协议:eg:http 、https、 ftp  域名:eg:www.google.com.hk  端口:eg:80  …  浏览器会根据识别出的协议发送请求。 二、浏览器查询域名的IP地址  在发送请求前,浏览器会检查Web缓存,然后调用网络请求的方法。   DNS解析(负责将主机名称映射到相应的ip地址)  读取本地DNS缓存  浏览器会在DNS缓存当中查找网址映射关系,如果有,直接返回,完成域名解析。使用本地缓存,则无DNS查询,使用持久连接也是。要查看Chrome的DNS缓存,可以打开chrome://net-internals/#dns   读取本地hosts文件  如果DNS缓存没有这个域名,则在hosts文件中查找网址映射关系,如果有,直接返回,完成域名解析。   发送DNS解析请求  如果本地DNS缓存和hosts文件都没有相应的网址映射关系,则浏览器会向本地域名服务器发送DNS查询报文;  本地域名转发请求给根域名服务器,根域名服务器解析后,知道.com是顶级域名下的,就会返回com域中的NS记录(即.com域服务器的ip地址,一般来说是13个主机名和ip);  然后向其中一台再次发起请求,com域的服务器发现是请求baidu.com这个域的,将这个域的NS记录返回;  再向baidu.com这个域的权威服务器发送请求,发现有www这台主机,就把ip返回给客户端。 三、建立连接  1、三次握手  在应用层和传输层之间,有一个很重要的东西–套接字(Socket),可以把它理解为传输层向外暴露的一个编程接口,它由一个四元组(源IP地址、源端口号、目标IP地址、目标端口号)组成。TCP是面向连接的,在发送数据之前,客户端需要和服务器建立连接。建立的过程如下:    第一次握手(SYN=1,Seq=X):  1、客户端发送一个SYN标志位为1的包,表示建立连接  2、设置初始序列号ISN,假如为 X,保存在包头的序列号(Sequence number)字段里  第二次握手(SYN=1,Seq=Y,ACK=X+1):  1、服务器返回确认包ACK应答,即SYN标志位和ACK标志位均为1  2、设置序列号ISN=Y,保存在报头的序列号(Sequence number)字段里  3、将确认序列号ACK设置为X+1  第三次握手(SYN=0,Seq=X+1,ACK=Y+1):  1、客户端返回确认包ACK,ACK标志位为1,SYN标志位为0  2、设置序列号ISN=X+1,保存在包头的序列号(Sequence number)字段里  3、将确认序列号ACK设置为Y+1       2、三次握手的必要性:  两次握手不可靠。假如客户端发出的第一个请求报文段A没有丢失,而是因为网络原因滞留了。客户端认为A丢失了,又发了一个报文B给服务器,服务器收到请求,建立连接。两端通讯后,释放连接。之后,报文A到达服务器,服务器误以为是客户端的新的连接请求,向A发出确实报文段,同意建立连接。但是客户端拒绝连接,服务器就一直等待接受数据,浪费了许多资源。 四、发送HTTP请求  请求在“三次握手”的“第三次握手”就发送出去了。HTTP报文是包裹在TCP报文中发出去的,服务器收到TCP报文时,会解包提取出HTTP报文,如果HTTP报文时明文,被截取会有信息泄露危险。因此,可以在HTTP报文进入TCP报文之前,对HTTP报文进行加密。HTTP协议的本质是HTTP+SSL/TLS。  发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议发送到服务器指定端口(HTTP协议8080,https协议443)。HTTP请求报文包括三个部分:请求行,请求报头,请求正文。   请求行格式:Method Request-URL HTTP-Version CRLF   eg: get index.html HTTP/1.1  常用的方法:GET,POST,DELETE,PUT,HEAD,OPTIONS  常见的请求报头:Accept,Accept-Encoding,Accept-Languange,Connection,Cookie,User-Agent  请求正文:当使用post,put方法时,通常客户端需要向服务器传递数据,这些数据就在请求正文中。现在的Web一般采用rest风格,数据格式为json,需要设置Content-Type:application/json。   get和post区别  从HTTP规范来看:  发送机制不同,get用于从服务器获取数据,post用于向服务器提交数据。  TCP数据包的不同 :  get产生一个TCP数据包;post产生两个TCP数据包。即对于get请求,浏览器把http header和data一起发送给服务器,服务器响应200(返回数据);对于post请求,浏览器先发送http header,服务器响应100,continue,浏览器发送data,服务器响应200。但是,并不是所有浏览器都会在post请求中发送两次包,Firefox就只发送一次。  从表现来看:  1、get请求的数据会附在url之后,以?号分割url和请求数据,请求数据的参数用&符号链接。post则是把请求数据放在请求正文中。  2、HTTP没有对传输数据的大小进行限制,也没有对url长度进行限制。浏览器会对url长度进行限制,服务器会对get,post提交的数据进行限制,提交的数据过大,对服务器来说也是一种负担。  3、post请求的安全性相对来说比get高一些,因为get请求是可以缓存和存在于浏览器历史记录中的,post请求也并非安全,截获数据包也可以获得数据。 五、服务器处理请求并返回HTTP报文  HTTP响应报文也包括三个部分:状态码,响应报头,响应报文。   状态码由3位数字组成:  1XX:指示信息-表示请求已接收,进一步处理  2XX:成功-表示请求已被成功接收  3XX:重定向-表示要完成请求需要进一步操作  4XX:客户端错误-请求有语法错误或请求无法实现  5XX:服务器端错误-服务器未能实现合法的请求  600:表示服务器没有返回响应头部,只返回实体内容,也算做服务器错误状态码   常见状态码如下:  200:OK 表明请求被服务器正常处理,返回信息与请求方法有关  204:No Content 表明请求被服务器正常处理,但是没有内容返回(就应该没有内容返回的状况)。浏览器向服务器发送请求后收到了204,那么浏览器页面不会发生更新。使用惯例是,在 PUT 请求中进行资源更新,但是不需要改变当前展示给用户的页面,那么返回 204 No Content。如果新创建了资源,那么返回 201 Created 。如果页面需要更新以反映更新后的资源,那么需要返回 200 。  206:Partial Content 表明客户端进行了范围请求。客户端的请求中,必须包含range字段。服务器的响应报文中,必须包含Content-Range指定范围的实体内容。  301:Moved Permanently永久性重定向。表示请求的资源已经移动到了由Location 头部指定的 URL 上,是永久性的,根据请求的不同有不同的处理方式:    HEAD:必须在响应头部Location字段中指明新的永久性的URI。    GET:除了有Location字段以外,还需要在响应体中附上永久性URI的超链接文本。    POST:客户端在发送POST请求,受到301响应之后,不应该自动跳转URI,应当让用户确认跳转。  302:Found临时性重定向。表示请求的资源被暂时的移动到了由Location 头部指定的 URL 上。  304:Not Modified表示无需再次传输请求的内容,可以使用缓存的内容。如在GET 或HEAD 请求中附带了头部信息: If-None-Match 或If-Modified-Since。  307:Temporary Redirect临时重定向。307 与 302 之间的唯一区别在于,当发送重定向请求的时候,307 状态码可以确保请求方法和消息主体不会发生变化。当响应状态码为 302 的时候,一些旧有的用户代理会错误地将请求方法转换为 GET。对于 GET 请求来说,两种情况没有区别。  400:Bad Request表示该请求报文中存在语法错误,导致服务器无法理解该请求。客户端需要修改请求的内容后再次发送请求。  401: Unauthorized该状态码表示发送的请求需要有通过HTTP认证(Basic认证,Digest认证)的认证信息。返回含有401的响应,必须在头部包含WWW-Authenticate以指明服务器需要哪种方式的认证。当客户端再次请求该资源的时候,需要在请求头中的Authorization包含认证信息。  403:Forbidden 代表客户端错误,指的是服务器端有能力处理该请求,但是拒绝授权访问。如未获得文件系统的访问权限,访问权限出现某些问题,从未授权的发送源IP地址试图访问等情况都可能发生403响应。  404: Not Found代表客户端错误,指的是服务器端无法找到所请求的资源。  500 Internal Server Error该状态码表明服务器端在执行请求时发生了错误。也有可能是Web应用存在的BUG或某些临时的故障。  503: Service Unavailable该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。   六、浏览器接收并处理响应    1、开始解析 html  2、请求 css 和 js 资源  3、解析 css,构造 CSSOM  4、等到 CSSOM 构建完成,执行 js,停止 DOM 构建(CSSOM 构建阻塞 js 执行,JS阻塞页面加载)  5、继续构建 DOM  6、合并 DOM 和 CSSOM生成 Render Tree(渲染树)  7、计算样式,确定元素位置,长宽,生成盒模型,进行布局  8、绘制元素的样式,如颜色,阴影 七、关闭TCP连接或者继续保持连接  通过四次挥手关闭连接:    为什么需要进行四次挥手?  第一次挥手是浏览器发完数据后,发送FIN请求断开连接。第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN应该放在第三次挥手中。这样浏览器需要返回ACK表示同意,也就是第四次挥手。 【参考文章】1、在地址栏敲下回车之后都发生了什么?——浏览器工作原理浅析2、当你在浏览器地址栏输入一个URL后回车,将会发生的事情?3、从输入URL到页面加载发生了什么4、从输入 URL 到页面加载完成的过程中都发生了什么事情?5、在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤?6、DNS解析的过程是什么,求详细的?–知乎7、DNS解析过程详解8、GET和POST有什么区别?及为什么网上多数答案都是错的9、浅谈HTTP中Get与Post的区别10、get和post的区别11、Wireshark-TCP协议分析(包结构以及连接的建立和释放)12、HTTP状态码13、「理解HTTP」之常见的状态码14、浅析渲染引擎与前端优化","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"html5新特性","date":"2017-08-23T06:34:18.000Z","path":"2017/08/23/html5新特性/","text":"与HTML4的区别:文档类型声明:<!DOCTYPE HTML> 新增标签/元素:< header > < nav > < section > < article > < sidebar > < footer >< video > < audio >< mark >< datalist > input元素的新类型:search、date 、email 、url、number、color、tel 新的属性:ping(用于a)、charset(用于meta)、async(用于script) 新的全局属性:contenteditable、draggable、hidden、data-*(自定义数据) 移除元素:< font >、< center >、< big > 新的应用程序接口:HTML LocalStorageHTML Web WorkersHTML Canvas 游戏","tags":[]},{"title":"懒加载","date":"2017-08-22T02:48:56.000Z","path":"2017/08/22/懒加载/","text":"  懒加载,是网页性能优化的一种方式,不是将所有的图片显示,而是优先显示可视区图片。当需要显示更多图片的时候再请求资源,避免打开网页时加载过多资源。 懒加载原理不给img标签设置src属性,而是添加一个data-src属性,将图片的URL放入其中。 实现比如:lazyload.js.下面解读lazyload.js库。 HTML结构 <div id="container"> <div> <img class="img1" alt="loading" data-src="img/image1.jpg"> </div> <div> <img class="img2" alt="loading" data-src="img/image2.jpg"> </div> <div> <img class="img3" alt="loading" data-src="img/image1.jpg"> </div> <div> <img class="img4" alt="loading" data-src="img/image2.jpg"> </div> </div>","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"},{"name":"网页性能优化","slug":"网页性能优化","permalink":"http://yoursite.com/tags/网页性能优化/"},{"name":"lazyload.js","slug":"lazyload-js","permalink":"http://yoursite.com/tags/lazyload-js/"}]},{"title":"es6","date":"2017-08-21T07:51:14.000Z","path":"2017/08/21/es6/","text":"","tags":[{"name":"es6","slug":"es6","permalink":"http://yoursite.com/tags/es6/"}]},{"title":"js继承","date":"2017-08-20T05:08:56.000Z","path":"2017/08/20/js继承/","text":"  较为常用的js继承有原型链继承、借用构造函数、组合式继承、继承组合式继承以及ES6继承。 一、原型链继承function Parent(name){ this.name = name; } Parent.prototype.sayName = function() { console.log('parent name is ' + this.name + '!'); }; function Child(name) { this.name = name; } // 使用原型链继承Parent构造函数 Child.prototype = new Parent('father'); var child1 = new Child();   缺点:1、子类型无法给超类传递参数;     2、引用类型的属性被所有实例共享。 二、借用构造函数function Parent(name) { this.name = name; this.friends = ['a','b']; } function Child(name) { // 通过call,apply 改变对象的this指向来继承 Parent.call(this, name); // Parent.apply(this, arguments); } var child = new Child('son'); child.friends.push('c');   优点:1、避免了引用类型的属性被所有实例共享     2、可以在child中向Parent传参  缺点:没有原型,方法都在构造函数中定义,每次创建实例都会创建一遍方法。 三、组合继承(原型链继承+借用构造函数继承)/* 使用原型链实现对原型属性和方法的继承 使用借用构造函数实现对实例属性的继承 */ function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log('parent name is ' + this.name + '!'); }; function Child(name) { // 通过call,apply 改变对象的this指向来继承 Parent.call(this, name); // 第二次调用 // Parent.apply(this, arguments); } Child.prototype = new Parent('father'); // 第一次调用 Child.prototype.constructor = Child; Child.prototype.sayName = function() { console.log('child name is ' + this.name + '!'); }; var child = new Child('son');   优点:融合了原型链和借用构造函数的优点,是常用的继承模式。  缺点:超类构造函数会被调用2次:一次是在创建子类型原型的时候,另一次是在子类型构造函数的内部。  注意:Chid.prototype.getName要放在Child.prototype = new Parent()之后。 四、原型式继承/* 基于一个对象上,将这个对象作为原型。 */ var ob = { name: 'son', friends: ['a', 'b'] }; function object(obj) { /** * 创建一个构造函数F */ function F() { // 空构造函数F } F.prototype = obj; return new F(); } var ob1 = object(ob); console.log(ob1.name); //son ob1.name = 'ob1'; ob1.friends.push('c'); console.log(ob1.name); // ob1 console.log(ob1.friends); //['a','b','c']   注意:在未给ob1对象添加name属性时,ob1.name实际上引用的ob.name。之后给ob1对象添加了name属性,但并未修改原型ob上的name。 五、寄生式继承/* 在函数内部以某种方式增强对象 */ var ob = { name: 'son', friends: ['a', 'b'] }; // 原型式继承再ECMAScript5 有了一新的规范写法,Object.create(ob) 效果是一样的 function createOb(o) { var newob = Object.create(o); // 创建对象 newob.sayname = function() { // 增强对象 console.log(this.name); }; return newob; // 指定对象 } var ob1 = createOb(ob); ob1.sayname(); // son 六、寄生组合式继承function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log('parent name is ' + this.name + '!'); }; function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } // 实现继承 Child.prototype = Object.create(Parent.prototype); Child.prototype.construtor = Child; Child.prototype.sayName = function() { console.log('child name is ' + this.name + '!'); }; var parent = new Parent('father'); parent.sayName(); // parent name: father var child1 = new Child('son', 'father'); child1.sayName(); // child name: son 七、ES6继承class Parent { constructor(name) { this.name = name; } sayName() { console.log(`parent name is ${this.name}!`); } } class Child extends Parent { constructor(name, parentName) { // 调用基类的构造方法 super(parentName); this.name = name; } sayName() { console.log(`child name is ${this.name}!`); } } const child = new Child('son', 'father'); child.sayName(); // child name: son const parent = new Parent('father'); parent.sayName(); // parent name: father 【参考文章】1、小白式 - 让你快速理解 JS 中的继承方式2、读书笔记–对象、实例、原型、继承3、ES6探秘-Classes4、Class 的基本语法","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"js创建对象","date":"2017-08-19T11:22:49.000Z","path":"2017/08/19/js创建对象/","text":"  js创建对象的方法:  除了普通那个的对象字面量和new Object外,还有如下方法: 一、工厂模式function Person(name) { var o = new Object(); o.name = name; o.say = function() { alert(this.name); } return o; } var person1 = Person('per');   缺点:1、无法识别对象的类型,以为都来自Object,无法得知来自Person。     2、say方法可以共享,但是却每次都存储,浪费资源。(即每个方法都要在每个对象上重新创建一遍)。 二、构造函数模式function Person(name) { this.name = name; this.say = function() { alert(this.name) } } var person1 = new Person('per');   构造函数与其他函数的区别:构造函数是通过new操作符来调用的。  优点:可以通过instanceof或constructor识别对象的类型。  缺点:每次创建对象实例每个方法都要被创建一次。  注意:如果不使用new,即var person1 = Person(‘per’);此时this指向window,会将属性和方法添加到window对象上。如: var person1 = new Person('per'); console.log(window.name); //per   改进:可以把函数定义放到构造函数外面 function Person(name){ this.name = name } function sayName(){ console.log(this.name); } var person1 = new Person('person1);   缺点:毫无封装性。 三、原型模式function Person() {} Person.prototype.name = 'kevin'; Person.prototype.say = function() { console.log(this.name); } var person1 = new Person();   优点:方法不会重新创建,它们是共享的。  缺点:1、所有的属性和方法都共享     2、不能初始化参数。  注意:通过对象字面量给Person.prototype赋值会导致constructor改变。如下面的改进:  改进:上述方法要每次都写Person.prototype,可改用原型语法的简写: function Person(){} Person.prototype = { name: 'kevin', sayName: function(){ console.log(this.name); } }; var person1 = new Person(); //再次改进: function Person(){} Person.prototype = { constructor: Person, name: 'kevin', sayName: function(){ console.log(this.name); } } 四、构造函数和原型组合模式function Person(name) { this.name = name } Person.prototype.say = function() { console.log(this.name) } var person1 = new Person('per')   优点:该共享的共享,该私有的私有,是使用最广泛的方式。  改进:有人看到独立的构造函数和原型时,会非常困惑。因此,创建了动态原型模式。   动态原型模式function Person(name){ this.name = name; if(typeof this.say != "function"){ Person.prototype.say = function(){ console.log(this.name); } } } var person1 = new Person('per');   注意:不能用对象字面量修改原型链。 五、寄生构造函数模式function Person(name){ var o = new Object() o.name = name; o.say = function(){ console.log(this.name); } return o; } var person1 = new Person('per');   所谓的寄生构造模式就是比工厂模式在创建对象的时候多了一个new,实际上两者的结果是一样的。  在可以使用其他模式的情况下,不要使用这种模式。 六、稳妥构造函数模式function Person(name) { var o = new Object() o.say = function() { console.log(name) //name: 变量,闭包,作用域 } } var person1 = Person('per'); person1.name // undefined person1.say() //per person1.name="kevin" person1.name:属性 person1.say() //per console.log(person1.name) //kevin   所谓稳妥对象就是没有公共属性,而且其方法也不引用this的对象。  与寄生构造函数的两点不同:  1、新创建的实例方法不使用this  2、不使用new操作符调用函数  优点:安全  缺点:无法识别对象所属类别 【参考文章】JavaScript 创建对象的 7 种方法JavaScript深入之创建对象的多种方式以及优缺点","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"原型及原型链","date":"2017-08-18T07:34:36.000Z","path":"2017/08/18/原型及原型链/","text":"一、创建对象1、对象字面量 var obj = {a:1}; 2、Object构造函数 var obj= new Objcet({a:1});   但是,一般采用对象字面量语法。 二、原型链  js不像其他语言,它没有传统的继承方法,它是通过原型继承的。  在js中,每个构造函数都有一个prototype属性指向原型对象,每个通过构造函数创建的对象也有一个proto属性指向对象的原型。原型也是一个对象,因此原型的proto指向原型的原型。直到一个 对象的proto为null,这样就形成了原型链。  原型链的形成是靠proto,而非prototype。    注意几点:  1、函数有prototype属性,指向原型对象。也有proto属性,指向函数自身的原型,一般是Function.prototype。  2、对象没有prototype属性,有proto属性,指向对象的原型。  3、在原型对象上,指向构造函数。  4、原型链的顶端为null,即Object.prototype.proto = null.5、当使用Obj.proto时,可以理解为返回了Object.getPrototypeOf(obj); 三、prototype对象  所有实例对象需要共享的属性和方法放在prototype对象里,不需要共享的放在构造函数里。prototype对象实现数据共享,减少资源的浪费。 四、原型链的使用方式–继承  我们在实现继承时,会将一个函数的prototype属性指向另一个函数的实例对象,而不是原型对象。因为这将导致两个对象共享同一个原型对象,更改其中一个对象的原型,会改变另一个。这是不希望发生的。 【参考文章】原型继承JS中new到底发生了什么Javascript继承机制的设计思想","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"正则表达式","date":"2017-08-16T07:51:58.000Z","path":"2017/08/16/正则表达式/","text":"","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"},{"name":"正则表达式","slug":"正则表达式","permalink":"http://yoursite.com/tags/正则表达式/"}]},{"title":"算法--排序","date":"2017-08-15T02:24:31.000Z","path":"2017/08/15/算法-排序/","text":"  选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,  冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。 1、插入排序算法/* 插入排序,在前K个元素有序排列的情况下,将第K+1个元素与前K个元素比较, 最终将第K+1个元素插入到合适的位置,使这K+1个元素保持有序。 时间复杂度O(n^2) */ function insertSort(arr){ for(let i = 1,len = arr.length; i<len; i++){ let temp = arr[i]; for(let j = i; j>0; --j){ if(arr[j-1]>temp){ arr[j] = arr[j-1]; }else{ arr[j] = temp; break; } } } return arr; } /*简化代码*/ function insertSort(arr){ for(let i = 1,len = arr.length; i<len; i++){ let temp = arr[i]; let j = i; for(; j>0 && arr[j-1]>temp; --j){ arr[j] = arr[j-1]; } arr[j] = temp; } return arr; }   时间复杂度O(n^2)  注意:如果没有返回值,函数默认返回undefined。这应该与java不同。 2、简单选择算法/* 简单选择排序,每次遍历选出最小的min并与相应位置交换(第一次遍历 同第一个元素交换,依次类推),每次遍历可找出最小值或最大值。 时间复杂度O(n^2) */ function selectSort(arr){ let len = arr.length, temp; for(let i=0; i<len-1; i++){ let minIndex = i; for(let j=i+1; j<len; ++j){ if(arr[minIndex]>arr[j]){ minIndex = j; } } temp = arr[minIndex]; arr[minIndex] = arr[i]; arr[i] = temp; } return arr; }   时间复杂度O(n^2) 3、冒泡排序算法/* 冒泡排序,与相邻元素比较大小并交换,每一轮会找出最大值或者最小值。 时间复杂度O(n^2) */ function bubbleSort(arr){ let len = arr.length, temp; for(let i=len-1;i>0;--i){ for(let j=0;j<i;j++){ if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } return arr; }   时间复杂度O(n^2) 4、归并算法/* 归并排序将元素平均划分为2组,再将每组元素继续平均划分为2组,直到不能划分。 归并排序先划分,在合并。 时间复杂度O(nlogn) */ function mergeSort(arr){ if(arr.length < 2){ return arr; } let mid = parseInt(arr.length/2); let left = arr.slice(0,mid); let right = arr.slice(mid); return merge(mergeSort(left),mergeSort(right)); } function merge(left,right){ let temp = []; while(left.length && right.length){ if(left[0]<right[0]){ temp.push(left.shift()); }else{ temp.push(right.shift()); } } return temp.concat(left,right); }   时间复杂度O(nlogn)  但是mergeSort()函数会导致很频繁的自调用。一个长度为n的数组最终会调用mergeSort() 2*n-1次,这意味着如果需要排序的数组长度很大会在某些栈小的浏览器上发生栈溢出错误。 /* 改进方法*/ function mergeSort(arr){ if(arr.length === 1){ return arr; } let newArr = [], len = arr.length; for(let i=0;i<len;i++){ //例如:newArr=[[1],[2],[3],[4],[5],[6]] //newArr中的每一个元素都是数组 newArr.push([arr[i]]); } if(newArr.length%2 !== 0){ newArr.push([]); //保证arrLen是偶数 } var arrLen = newArr.length; for(let i=arrLen;i>1;i=i/2){ for(var j=0,k=0;j<i;j+=2,k++){ newArr[k] = merge(newArr[j],newArr[j+1]); } if(k%2!==0){ newArr[k] = []; } } return newArr[0]; } function merge(left,right){ //left,right均为数组 let temp = []; while(left.length && right.length){ if(left[0] < right[0]){ temp.push(left.shift()); }else{ temp.push(right.shift()); } } return temp.concat(left,right); } 5、快速排序算法/* 1、在数据集之中,选择一个元素作为"基准"(pivot) 2、所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。 3、对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。 */ /*方法一:容易理解,占用内存大*/ function quickSort(arr){ if(arr.length <= 1 ){ //arr.length<=1不是===1,否则,报错,栈溢出。 //因为left或者right可能为空。 return arr; } let pivotIndex = Math.floor(arr.length/2), //“基准” pivot = arr.splice(pivotIndex,1)[0],//splice返回被删除元素组成的数组,同时原数组被改变。 left = [], right = []; for(let i=0;i<arr.length;i++){ if(arr[i]<pivot){ left.push(arr[i]); }else if(arr[i]>pivot){ right.push(arr[i]); } } return quickSort(left).concat([pivot],quickSort(right)); } /*方法二:快速排序思想*/ /* 每次都以left作为“基准”,并且能够确定其在数组中的位置。 根据left的位置,将数组分为两部分,对着两部分继续采用上述方法。 */ function quickSort(arr,left,right){ var left = typeof left !=='number'?0:left; var right = typeof right !=='number'?arr.length-1:right; if(left >= right){ return; } if(left<right){ let midIndex = quick(arr,left,right); quickSort(arr,left,midIndex - 1); quickSort(arr,midIndex + 1,right); } return arr; } function quick(arr,left,right){ let temp = arr[left]; while(left < right){ for(;left<right && arr[right]>=temp;right--){ } if(left<right){ arr[left++] = arr[right]; } for(;left<right && arr[left]< temp;left++){ } if(left<right){ arr[right--] = arr[left]; } } arr[left] = temp; return left; } 6、二分查找算法/* 二分查找算法比较的前提是数组是一个有序数组,采用折中的方法查找 */ function binarySearch(arr,target){ let left = 0; let right = arr.length-1; while(left<=right){ let middle = (left+right)/2; let midValue = arr[middle]; if(midValue > target){ right = middle - 1; }else if(midValue < target){ left = middle + 1; }else{ return middle; } } return -1; }    【参考文章】1、数据结构与算法-算法基础二2、【前端也要学点算法】 归并排序的JavaScript实现3、JS实现快速排序算法的详细解释4、快速排序(Quicksort)的Javascript实现5、常用排序算法稳定性、时间复杂度分析(转,有改动)","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"},{"name":"算法","slug":"算法","permalink":"http://yoursite.com/tags/算法/"}]},{"title":"js引擎","date":"2017-08-14T10:01:26.000Z","path":"2017/08/14/js引擎/","text":"  javascript是一种解释型语言,不需要编译,边执行边解析。编译型语言是在执行之前将源代码编译成目标代码,不需要解释器,直接在目标代码的平台上运行。 一、js引擎的作用和优缺点  作用  javascript引擎的主要作用是读取网页中的javascript代码,对其处理后运行。   优缺点  优点:运行和修改方便,刷新页面重新解释。  缺点:每次运行都需要运行解释器,系统开销大,运行速度慢于编译型语言。  由于javascript是在前端运行的,需要即时响应用户的需求,这就要求js能够快速的解析和执行。 二、js引擎解释器  javascript引擎通常包含4个组成部分:  ● 词法分析器(Lexical Analyser)  ● 语法分析器(Syntax Parser)  ● 字节码生成器(Bytecode generator)  ● 字节码解释器(Bytecode interpreter)   1、词法分析器读取源代码,将代码一行行进行词法分析,即将代码解析成“词元”;   2、语法分析器对词元进行语法分析,按照一定规则,解析成抽象语法生成树(Syntax tree),如果有语法错误,则报错。例如:将this赋值(var this = {}),少些括号等。这个阶段仅仅是解析语法。   3、字节码生成器通过“翻译器”,将字节码转换为字节码。   3、字节码解释器  3将字节码转换为机器码。  3逐行将字节码转换为机器码,是很耗时的,为了提高效率,引入了“即时编译”(JIT)。谷歌浏览器直接将源代码编译为机器码。  3现在JavaScript引擎的执行过程大致是:  3源代码-→抽象语法树-→字节码-→JIT-→本地代码(V8引擎没有中间字节码)。  (在 V8 的 5.9 版本中,新增了一个 Ignition 字节码解释器,TurboFan 和 Ignition 结合起来共同完成JavaScript的编译,此后 V8 将与 JavaScriptCore 有大致相同的流程。) 【参考文章】1、浏览器环境概述2、认识 V8 引擎","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"this解析","date":"2017-08-14T06:55:27.000Z","path":"2017/08/14/this解析/","text":"一、默认绑定  最常用的函数调用类型:独立函数调用。  非严格模式下:this—> window;    函数调用时,应用了this的默认绑定,因此this指向全局对象。 二、隐式绑定  这个规则需要考虑的是调用位置是否有上下文对象,或者说是否被某个对象“拥有”或者“包含”。  在分析隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this隐式绑定到这个对象上。    但是,无论直接在obj中定义还是先定义在添加为引用属性,这个函数严格来说都不属于obj对象。   对象属性引用链中只有最顶层或者说最后一层会影响调用位置。例如:     this隐式绑定问题 :  1、一个最常见的this绑定问题就是隐式绑定的函数会丢失绑定对象。也就是他会应用默认绑定。     2、还有一种情况是发生在传入回调函数时:  将函数的引用作为参数传入另一个函数,也会应用默认绑定。   三、new绑定  在js中,构造函数只是一些使用new操作符时被调用的函数。  使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:  1、创建(或者说构造)一个全新的对象  2、这个新对象会被执行[[原型]]连接  3、这个新对象会绑定到函数调用的this (this指向这个对象)  4、如果函数没有其他返回对象,那么new表达式中的函数调用会自动返回这个新对象。  伪代码表示如下: 1、var o = new Object(); 2、o._proto = A.prototype; 3、A.call(o); 4、如果函数没有其他返回对象,那么new表达式中的函数调用会自动返回o这个对象. 四、显示绑定  使用函数的call()和apply()方法。它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用函数时指定这个this。因为可以直接指定this的绑定对象,所以称之为显示绑定。    如果传入了一个原始值(字符串类型、数值类型、布尔类型)来当作this的绑定对象,这个原始值会被转换为它的对象形式(new String()、new Number()、new Boolean()),通常称为“装箱”。解决绑定丢失方法(如闭包中子函数this丢失):   call和apply方法  直接使用call和apply方法。  call方法:    apply方法:     bind方法    由于bind绑定是一种非常常用的模式,在ES5中提供了内置的方法Function.prototype.bind,它的用法如下:   五、优先级  New绑定 > 显示绑定 > 隐式绑定 > 默认绑定 六、判断this  函数是否是在new中调用(new绑定)?如果是,this绑定的是新创建的对象  var bar = new foo()   函数是否通过call、apply(显示绑定)?如果是,this绑定的是指定的对象  var bar = foo.call(obj)   函数是否在某个上下文对象中调用(隐式绑定)?如果是,this绑定的是那个上下文对象  var bar =obj.foo()   如果都不是,使用默认绑定。  var bar = foo()  严格模式下默认绑定的this值为undefined,其值不会转换为window,而在非严格模式下则会转化为window。另外,全局模式下的this指向window,不属于默认绑定。严格模式除了默认绑定,其他规则都适应。例如: "use strict"; //全局对象 ---window console.log(this); //new ---new出来的对象 function Animal(){ console.log(this); } let animal = new Animal(); //obj.foo() --- obj function fun(){ console.log(this); //console.log(this.a); //2 } var obj = { a:2, fun:fun } obj.fun(); //foo --- undefined,默认绑定失效 function foo(){ console.log(this); } foo(); 七、绑定例外  1、被忽略的this  如果把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际上应用的是默认绑定。  foo.call(null);   2、间接引用  间接引用最容易发生在赋值时。创建函数的间接引用,调用这个函数会应用默认绑定。     3、箭头函数  箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。    如果将箭头函数改为一般函数   八、this其他应用  1、DOM 事件回调中的this  this绑定的是绑定该事件的DOM元素。   2、HTML中的this  this指代该HTML元素。   3、无法重写this  无法重写this,因为它是一个关键字。     4、数组forEach中的this  如果给forEach传递了thisArg参数,当调用时,它将被传给callback 函数,作为它的this值。否则,将会传入 undefined 作为它的this值。    注意:如果使用箭头函数表达式传入函数参数,thisArg 参数会被忽略,因为箭头  函数在词法上绑定了this值。   对象复制函数  下面的代码会创建一个给定对象的副本。   【参考文章】1、了不起的javascript2、详解this","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"执行上下文","date":"2017-08-11T00:32:37.000Z","path":"2017/08/11/执行上下文/","text":"一、可执行代码  ES可执行代码(executable code)分为3种:   全局代码—javascript代码首次进入的环境   函数代码—函数被调用时,进入函数执行环境   eval代码 二、可执行上下文  当控制器转到可执行代码时,会进入一个执行上下文(Execution Content,EC)。进入全局代码时,会创建全局环境执行上下文;调用函数时,会创建函数执行上下文。处于活动状态的执行上下文环境只会有一个。  JS引擎创建了执行上下文栈(Execution Content Stack,ECS)管理执行上下文。每个执行上下文都有3个重要属性:  ● 变量对象(Variable Object,VO)  ● 作用域链(Scope Chain)  ● this   1、变量对象  变量对象是与执行上下文相关的数据作用域,存储了函数的参数、变量和函数声明。它是一个抽象的概念。  当进入执行上下文时,VO的初始化过程如下:  函数的形参(如果是函数上下文)— 变量对象的属性:  由属性名和值组成的键值对,属性名就是形参的名称,属性值就是形参的值。如果没有实参,其值为undefined。  函数声明 — 变量对象的属性:  由属性名和值组成的键值对,属性名就是函数的名称,属性值就是函数对象。如果变量对象已经存在相同的名称的属性,替换这个属性。  变量声明 — 变量对象的属性:  由属性名和值组成的键值对,属性名就是变量的名称,属性值为undefined。如果变量名和已声明的函数或者函数的参数名相同,变量声明不会影响已存在的属性。  注意:初始化阶段变量并没有执行赋值语句。   全局上下文的变量对象  在javascript中,可以用关键字this引用全局对象。在全局上下文中,变量对象也是全局对象自身。   函数上下文的变量对象  函数被激活时,用活动对象(Activation Object)表示变量对象。活动对象是在进入函数上下文时被创建的,它通过函数的arguments属性初始化。arguments属性值是Arguments对象。   2、作用域链  由多个执行上下文的变量对象构成的链表叫作用域链。   函数创建和执行过程  在一个函数定义的时候,会保存所有父变量对象(父作用域链)到函数的[scope]属性(每个函数有一个内部属性[scope])。   调用函数,创建函数执行上下文,函数执行上下文被压入执行上下文栈。   函数不立刻执行,开始准备工作,首先将函数上下文中的作用域链连接到函数[scope]属性,接着用arguments创建活动对象,随后初始化活动对象,加入形参、函数声明、变量声明,最后,将活动对象压入上下文的作用域链顶端。   准备工作做完,开始执行函数,随着函数的执行,修改AO的属性值。   找到变量,返回后函数执行完毕,函数上下文从执行上下文栈中弹出。   3、this【参考文献】1、了解JavaScript的执行上下文2、JavaScript深入之执行上下文栈3、深入理解JavaScript执行上下文、函数堆栈、提升的概念4、理解执行环境与作用域链","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"作用域和闭包","date":"2017-08-10T07:20:04.000Z","path":"2017/08/10/作用域和闭包/","text":"一、作用域是什么?  作用域是根据名称查找变量的一种规则,也就是确定当前执行代码对变量的访问权限。  对程序“var a = 2; ”进行处理的的重要“演员表”:  1、引擎:负责整个javascript程序的编译和执行过程。  2、编译器(解释器):负责语法分析及代码生成等。  3、作用域:负责搜集并维护由所有声明的标识符组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。(即负责当前执行的代码对标识符的访问权限)   js代码在执行时由编译器(解释器)进行编译(解释)   1、编译(解释)  遇到var a,编译器(解释器)会询问作用域是否已有一个该名称的变量存在于当前作用域中,如果是,则忽略该声明;否则会在当前作用域下声明一个新的变量,并命名为a;  接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2 这个操作。  编译(解释):声明变量和函数,把代码变成机器指令   2、运行  引擎首先会问作用域,当前作用域中是否存在一个叫a的变量,如果是,引擎会将2赋值给变量a;否则,引擎会沿着作用域链查找该变量。如果找到了会将2赋值给变量a,如果没有找到则会抛出一个异常。  引擎在查找变量a的时候,会进行LHS/RHS查询。  LHS—赋值操作的左侧,RHS—赋值操作的右侧    在非严格模式下,当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域就会创建一个具有改名称的变量,并将其返还给引擎。  如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出ReferrenceError异常。如果RHS查询到了一个变量,但是对这个变量进行了不合理的操作,若引用undefined或者null的属性,则会抛出TypeError异常。(注:ReferenceError同作用域判别失败有关,TypeError代表作用域判别成功了,但是进行了不合理、非法的操作。)  在严格模式下,禁止自动或隐式的创建全局变量,LHS查询失败时,并不会创建并返回一个全局变量,引擎会抛出同RHS查询失败时类似的ReferenceError异常。  (运行:执行机器指令,查询变量,并进行一些操作) 二、词法作用域  作用域主要有两种模型:词法作用域(静态作用域)和动态作用域。js采用的是词法作用域。  词法作用域是在函数定义时的环境中查找,动态作用域是在函数运行时的环境中查找。即词法作用域是定义时确定的,动态作用域是运行时确定的。 三、函数作用域  函数作用域就是定义在函数中的变量和参数在函数外部不可见。js没有块级作用域。  JS并不支持块级作用域,它只支持函数作用域,而且在一个函数中的任何位置定义的变量在该函数中的任何地方都是可见的。 四、提升  只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。函数表达式也不会被提升。  每个作用域都会进行提升操作。   函数声明会提升     函数表达式不会提升    即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用。     函数优先  函数声明和变量声明都会被提升,但是是函数首先被提升,然后才是变量。    函数提升后,var foo是重复的声明,var foo会被忽略掉。 五、闭包  当函数可以记住并访问所在的词法作用域,即使函数是在当前作用域之外执行,这时就产生了闭包。  当一个函数返回它内部的一个函数时,就产生了闭包。如:    Js特殊之处:可以在函数内部读取全局变量,但是不能再函数外部读取函数内部的局部变量。由于种种原因,我们需要在函数外面获取函数内部的局部变量,通过闭包的方法可以实现。即在函数内部在定义一个函数。  闭包就是能访问另一个函数作用域中的变量的函数。创建闭包的方式,就是在一个函数内部创建另一个函数。本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。   闭包的优点  1、可以在函数外部读取函数内部的变量。  2、可以将变量保存在内存中,避免使用全局对象。  3、封装对象的私有属性和方法。  4、在循环中使用。   闭包的缺点  1、由于闭包都保存在内存中,使得内存消耗很大,不能滥用闭包。  2、由于回收机制问题,可能导致内存泄露。解决办法,程序退出前,将不用的变量设置为null。  3、增加了代码的复杂度,给维护和调试带来了不变。 【参考文章】1、了不起的javascript2、深入理解javascript作用域系列第二篇——词法作用域和动态作用域3、JavaScript的作用域和块级作用域概念理解","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"操作符","date":"2017-08-09T01:20:02.000Z","path":"2017/08/09/操作符/","text":"相等(==)操作符  相等操作符的最终结果是将其他非数值类型转化为数值类型。相等操作符转换规则如下:    左右两边类型相等:  1、NaN != NaN    -0 == +0  2、两边都是对象比较的是地址  左右两边类型不相等:  1、undefined == null  2、有 null/undefined 参与的 == 运算是不进行隐式转换。    0 == null; // false    null == false; // false    ”undefined” == undefined; // false  3、一个是number,一个是string,string将调用toNumber()转换为number  4、一个是boolean,一个是number,boolean将调用toNumber()转换为number  5、一个是boolean,一个是string,boolean和String将调用toNumber()转换为number  6、一个是object,另一个是其他(string/number),object将调用toPrimitive()   toNumber方法即Number转换规则:     toPrimitive方法如下:    原始值指的是[‘Null’,’Undefined’,’String’,’Boolean’,’Number’]五种基本数据类型之一   valueOf返回值:  注意:Number、Boolean、String有属于自身的原型valueOf方法,不是直接从Object.prototype上继承下来,归纳如下:     toString返回值:     ==总结   一元加操作符  var num = 25;  num = +num;  改操作符会像Number()函数一样对非数值类型进行转换。 布尔操作符  操作符转换规则:     ! 取反  !x 将表达式x转换成布尔值(Boolean),之后在将结果取反。  !!x 则表示取 x 表达式的运行结果的布尔值。    var obj = {};    var a = !obj // false;    var a = !!obj // true;   && 逻辑与  x && y 如果 x 表达式的运行结果转换成 Boolean 值为 false 则不运行表达式 y 而直接返回 x 表达式的运行结果。相反,如果 x 表达式的运行结果转换成 Boolean 值为 true 则运行表达式 y 并返回 y 表达式的运行结果。   || 逻辑或  x || y 如果 x 表达式的运行结果转换为 Boolean 值为 true,则不运行 表达式 y 而直接返回表达式 x 的运算结果。(与 && 方式相反) 【参考文章】1、从 []==![] 为 true 来剖析 JavaScript 各种蛋疼的类型转换2、toString 方法 (Object) (JavaScript)3、valueOf 方法 (Object) (JavaScript)4、表达式与运算符","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"javascript基础----引用类型","date":"2017-08-07T01:20:15.000Z","path":"2017/08/07/javascript基础---引用类型/","text":"  javascript 类型系统可以分为标准类型和对象类型,进一步标准类型又可以分为原始类型和引用类型,而对象类型又可以分为内置对象类型、普通对象类型、自定义对象类型。   标准内置对象构造器对象ObjectBooleanStringNumberFunctionArrayRegExpDateError其他对象 MathJSON全局对象 类型识别  typeof  Object.prototype.toString  constructor  instanceof   typeof:  可以是标准类型(Null 除外)  不可识别具体的对象类型(Function 除外)   Object.prototype.toString:  可以识别标准类型  可是识别标准类型及内置对象类型(例如,Object, Date, Array)  不能识别自定义对象类型   constructor:  可以识别标准类型(Undefined/Null 除外)  可识别内置对象类型  可识别自定义对象类型   instanceof:  不可判别原始类型  可判别内置对象类型  可判别自定义对象类型  ","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"javascript基础---基本数据类型","date":"2017-08-04T14:11:50.000Z","path":"2017/08/04/javascript基础---基本数据类型/","text":"一、Javascript简介   在上个世纪1995年,Netscape公司凭借其Navigator浏览器成为第一代互联网公司。之后,Netscape公司希望能在静态HTML页面上添加一些动态效果,于是Brendan Eich在两周之内设计出了JavaScript语言。由于当时java很火,Netscape公司希望借java热风推广,便取名为javascript。   之后,微软模仿javascript开发了Jscript,此时,相当于有了两个JavaScript版本。为了让Javascript成为国际标准,几个公司联合ECMA组织制订了Javascript语言的标准,被称为ECMAScript标准。   ECMA就是对标准规定的各个方面内容的语言的描述,可以理解为ECMA仅仅是一个描述,定义了脚本语言的所有属性、方法和对象。其他的语言可以实现ECMAScript,来作为功能的基准,javascript就是这样。   web浏览器只是ECMAScript实现可能的宿舍环境之一,宿主环境不仅提供基本的ECMAScript实现,同时也会提供语言的扩展。可以理解为每个浏览器都有自己的ECMAScript接口,然后这个实现又被扩展,包含了BOM和DOM以及其他扩展。  一个完整的javascript实现应该由下列三个不同的部分组成:  ● ECMAScript(核心) ECMAScript描述了该语言的语法和基本对象;  ● DOM(文档对象模型)DOM 描述了处理网页内容的方法和接口;  ● BOM(浏览器对象模型)BOM描述了与浏览器进行交互的方法和接口。 二、Javascript数据类型  ECMAScript中有6种简单数据结构(基本数据类型):Undefined、Null、Boolean、Number、String、Symbol。还有一种复杂结构类型(引用类型)Object。  基本数据类型保存在内存的栈区,复制变量时会创建其值的一个副本。基本数据类型可以使用typeof区分。  引用类型的存储是由内存的栈区和堆区共同完成,引用类型的值是对象,保存在堆内存中,栈区内存保存变量标识符和指向堆内存中该对象的指针,也就是该对象在堆内存的地址。 1、Undefined类型  使用var声明但是未初始化的变量其值为undefined。使用未声明的变量会报错。如:      但是,对未初始化的变量执行typeof操作符会返回undefined值,对未声明的变量执行typeof操作符也会返回undefined。     2、Null类型  如果定义的变量将来准备用于保存变量,那么最好将该变量初始化为null。   null和undefined的区别  undefined派生自null,用相等操作符(==)它们是相等的。    在if语句中,null和undefined都会被转换为false。但是,它们都不等于0,false或””    null转为数值时值为0,undefined转为数值时值为NaN.  typeof null 返回object, typeof undefined 返回undefined.    undefined表示“不存在的值”,应用场景:  1、变量声明了,但是没有赋值,会有一个undefined的默认值;  2、调用函数时,函数没有赋值的参数,默认为undefined;  3、试图访问不存在的对象属性时,会返回undefined值;  4、函数没有返回值,默认返回undefined。  null表示“没有对象”,应用场景:  1、作为函数的参数,表示该函数的参数不是对象;  2、作为原型对象链的终点;  3、通过分配null值,有效的清除引用,并假设对象没有引用其他代码,指定垃圾回收,确保回收内存。  在ES5中,Object.prototype.toString()方法,已经成为实际的类型检验标准。 3、Boolean类型  Boolean类型有两个值:true和false。  要将一个值转换为Boolean值,可以调用转型函数Boolean()。各种数据类型极其对应的转换规则:   4、Number类型  数值字面量可以是十进制整数,八进制整数,十六进制整数。其中八进制字面量的第一位必须是零(0),数字序列为(0-7);十六进制字面量的前两位必须是0x,数字序列(0-9及A-F),字母可大写可小写,超出范围报错。   (1)数值范围  Number.MAX_VALUE 最大数值  Number.MAX_VALUE 最小数值,代表的并不是负最小,而是最接近0的一个数  -Number.MAX_VALUE 负最小   (2)NaN  任何数除以0都会返回NaN,其次,NaN与任何值都不相等,包括NaN本身。   (3)数值转换  有3个函数可以把非数值转换为数组,Number()、parseInt()、parseFloat()。  Number()可以用于任何数据类型,而另外两个专门用于把字符串转换为数组。   Number函数转换规则  如果是Boolean值,true和false将分别被转换为1和0。  如果是数字值,只是简单的传入和返回。  如果是undefined,返回NaN。  如果是null,返回0。  如果是字符串,    若只包含数字,则将其转化为十进制数值。如”1”->1,”123”->123,而”011”->11。    如果字符串包含有效的十六进制格式,如”0xf”,则将其转化为相同大小的十进制。    如果字符串包含有效的浮点格式,如”1.1”,则将其转化为对应的浮点数值。    如果字符串是空的或者只包含空格字符串,则将其转化为0。  如果是对象,则调用对象的valueOf()方法,然后按照前面的规则转换。如果转换的结果是NaN,则调用对象的toString()方法,然后按照前面的规则转换。   parseInt函数转换规则—针对字符串  parseInt()函数在转换字符串时,会忽略字符串前面的空格,直到找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt()就会返回NaN,即parseInt会将空的字符串转化为NaN。  parseInt可以指定基数,如:  var num1 = parseInt(“10”,2);  var num1 = parseInt(“10”,10);  var num1 = parseInt(“10”,16);   parseFloat函数转换规则—针对字符串  parseFloat()函数与parseInt类似,解析遇到一个无效的浮点数字字符为止。也就是说,第一个小数点有效,第二个小数点无效。  注意:parseFloat在解析十六进制的字符串时,会始终将其转换为0。parseFloat只解析十进制,没有第二个参数(基数)的用法。 5、String类型  字符串可以由单引号’’或者双引号””表示。字符串是不可变的,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,如:  var lang = “Java”;  lang = lang + “Script”;  首先创建一个能容纳10个字符的新字符串,然后在这个字符串中填充”Java”和”Script”,最后是销毁原来的字符串”Java”和字符串”Script”。   转换为字符串  第一种是几乎每个值都有的toString()方法,但null和undefined值没有这个方法。  第二种:在不知道要转换的值是不是null或undefined的情况下,还可以使用转型函数String(),这个函数能将任何类型的值转换为字符串。转换规则如下:  如果有toString()方法,则调用并返回相应的结果;  如果值是null,则返回”null’;  如果值是undefined,则返回’undefined’; 6、Symbol类型  symbol是程序创建并且可以用作属性键的值,并且它能避免命名冲突的风险。  var mySymbol = Symbol();  obj[mySymbol] = “ok!”; // 保证不会冲突  console.log(obj[mySymbol]); // ok!  symbol被创建后就不可变更,你不能为它设置属性(在严格模式下尝试设置属性会得到TypeError的错误)。他们可以用作属性名称,这些性质与字符串类似。  另一方面,每一个symbol都独一无二,不与其它symbol等同,即使二者有相同的描述也不相等;你可以轻松地创建一个新的symbol。这些性质与对象类似。 6、Object类型对象其实就是一组数据和功能的集合。引用类型下一篇文章总结。","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"}]},{"title":"认识vue.js","date":"2017-07-28T07:45:17.000Z","path":"2017/07/28/认识vue.js/","text":"我们首先了解一下MVX模式MVX模式:MVC、MVP、MVVM MVCMVC一般分为Model(模型)、View(视图)和Controller(控制器)。 View一般通过Controller来和View进行联系。Controller是View和Model的协调者。基本联系都是单向的。1.View传送指令到Controller2.Controll接收指令处理后,要求Model改变状态3.Model将新的数据传送给View。 MVPMVP一般分为Model(模型)、View(视图)和Presenter。Presenter把View和Model进行了分离,而且,Presenter与具体的View没有直接联系,是通过定义好的接口进行联系的。 MVVMMVVM分为Model(模型)、View(视图)和ViewModel。View的变化会自动更新到ViewModel,viewModel的变化也会同步到View上。MVVM采用双向绑定(data-binding)","tags":[{"name":"vue.js","slug":"vue-js","permalink":"http://yoursite.com/tags/vue-js/"},{"name":"前端框架","slug":"前端框架","permalink":"http://yoursite.com/tags/前端框架/"}]},{"title":"Hello World","date":"2017-02-27T03:08:12.227Z","path":"2017/02/27/hello-world/","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","tags":[]}]