基础真的很重要

还记得之前写过的一篇博客,egret游戏引擎入门(六) 在说到其中的一个参数userID的位数为18位,在传输过来的时候丧失精准度的问题。当时我跟几个小伙伴对这个问题纠结了一晚上,其实这个问题在犀牛书中就有提到过(第6版,p34,3.1数字)。

按照JavaScript中的数字格式,能够表示的整数范围是从 -9007199254740992 ~ 9007199254740992,包含边界值。如果使用了超过此范围的整数,则无发保证低位数字的精准度。

从上面这段文字中我们可以看到,JavaScript语言只能保证数字的长度在16位以内,如果超过16位,则超出的部分会丧失精准度。

从这里可以看出,基础真的好重要呀,所以近期内会重读犀牛书、高程之类的。

es6变量声明的6种方法

ES5只有两种变量声明的方法,分别是varfunction关键字。ES6相比ES5多了letconstimportclass这四个关键字。
最早的ES5使用varfunction这两个关键字声明的变量会触发变量声明提前,这个大家都很熟悉。但是ES6新增的letconst这两个块级作用域的变量声明关键字则不会。

let

在代码块内,使用let关键字声明变量之前,该变量都是不可使用的,也就是在这个代码块内,只要声明的该变量,但是在该变量声明之前调用了,就会报错。这在语法上称为“暂时性死区(参照阮一峰的ES6入门,见下例:)。”

{
    console.log(b); //ReferenceError
    let b = 123;
}

const

使用const关键字声明变量的作用域也是块级作用域,但是constlet还是有着非常明显的区别的:使用let关键字声明的变量,它的值可以改变;使用const关键字声明的变量,它的值可以改变,但是变量所指向的内存中的地址是不可改变的。

{
    const a = {
        p: 123,
        d: 234
    }

    a.f = 345;
}

上述代码是不会出错的。但是如下操作是会报错的:

{
    const a = {
        a: 123
    }

    a = { // TypeError: Assignment to constant variable
        b: 234
    }
}

这个就是改变了常量a在内存中的地址。

import

import 是用于在一个模块中加载另一个含有export的模块。写法如下:

import React from 'react';
或
import React, { Component } from 'react';

前面的这个React实际是自己定义的一个要引入文件的名称,也就相当于声明变量。这个就是引入react模块并命名为React,从react中引入React以及Component。

class

es6引入了class(类)这个概念,使其看起来更加像传统的面向对象的语言例如java或者C++。通过class关键字,可以定义类(声明或定义了一个对象)。

class Person() {

}

类里面还有构造方法(constructor),这个就不在这里描述了。

HTTP请求的GET与POST

最近跟公司后端的小伙伴们沟通才知道,原来后端在面试的时候,也经常会遇到GET、POST这样的问题。
HTTP请求GET方法和POST方法有什么区别?
感觉把区别都说了出来,但是当问题在深入一点的时候,发现自己只是知道了结果,但是不知道原理。看来以后还要在知识的深度上狠下功夫。不都说了,下面就深入了解一下GET方法和POST方法的区别吧。

HTTP的请求类型

GET方法与POST方法都是HTTP的请求类型,另外还有两种平常用的不多的PUT(更新)、DELETE(删除)类型。

区别一:

GET方法是从指定的资源请求数据,POST方法是向指定的资源提交要处理的数据。

区别二:

GET方法请求有长度限制,POST方法请求没有长度限制。
这个理解起来比较简单,因为在发送数据时,GET方法是在url的末尾拼接数据,而url的长度是有限的,最长2048个字符,这个限制要根据不同的浏览器厂商而定。而POST方法是在HTTP的消息主体(request body)中发送的,所以没有限制。

区别三:

GET方法因为请求的数据是拼接在url中的,所以存书签的时候能够储存。而POST方法则不行。

区别四:

GET方法不如POST方法安全。
GET方法发送的数据是拼接在url上的,所以发送的信息都是可见的,并且参数会保留在浏览器的历史中,可以被缓存,所以不安全。而POST方法请求的参数不会被保存在浏览器历史或者web服务器日志中。

区别五:

GET方法点击后退或者刷新按钮时不会有操作。而POST方法的数据会重新提交。

区别六:

编码类型不一样:
GET方法使用的编码类型是:application/x-www-form-urlencoded;POST方法使用的编码类型是:application/x-www-form-urlencodedmultipart/form-data,为二进制数据使用多重编码。

区别七:

数据类型不一样:
GET方法只允许ASCII字符。POST方法没有限制,也允许二进制数据。

区别八:

GET方法是幂等的,POST方法是非幂等的。
再引入幂等的概念

在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现.

区别九:

GET方法无副作用,POST方法有副作用。
副作用是指,在发送完一个请求后,网站上的资源状态没有发生修改。比如注册新用户,发生了改变,就是有副作用。而请求用户数据,数据没有发生改变,就是没有副作用。

参考

  1. HTTP head请求
  2. post和get请求的区别

js作用域

作用域

引:Engine/Scope Conversation

Engine/Scope Conversation
from You Don’t Know JS: Scope & Closures
这一章节,生动详细的向我们描述了js解析引擎是如何运行的,这对理解我们的作用域非常有帮助,有兴趣的可以瞅一眼。下面通过几个简单的题来巩固一下。

1.下面代码alert显示的内容是什么?
function a() {
    var foo = 1;
    b();
}

function b() {
    alert(foo);
}

function c() {
    var foo = 1;
    d();
    function d() {
        alert(foo);
    }
}

a();
c();

这道题主要考察的是js中变量的作用域的问题。运行a(),得到的结果是foo is not defined,且程序停止,不会再执行c(),如果把a()注释掉的话,会alert(1)
function a(){}中声明的变量foo是局部变量,无法被外界访问,所以function b(){}会报错。

function d(){}中的foo虽然也是局部变量,但是foo的作用域恰好包括了function d(){},所以这个foo可以找到。

2.下面代码console显示的内容是什么?
var scope="global";  
function t(){  
    console.log(scope);  
    var scope = "local";
    console.log(scope);  
}  
t();

有些童鞋想当然的认为,因为代码还没有执行到var scope = "local",所以第一个显示的内容是global,第二个是local
然而事实却不是这样的,第一个显示的内容是undefined。如果按照js解析引擎去解读这段代码,应该可以这样去理解:

var scope; //只是知道有这个变量,还没有进行赋值
function t() {} //函数声明提前
t(); //执行这个方法
function t() { //开始观察方法的内部
    var scope; //这个是局部变量,变量声明提前
    console.log(scope); //没有赋值,所以为undefined
    scope = "local"; //对局部变量进行赋值
    console.log(scope; //显示为 local
}
3.es5跟es6的作用域区别

在es5中,是没有块级作用域这个概念的,只有函数作用域,下面的这个例子就可以说明:

var name="global";  
if(true){  
    var name="local";  
    console.log(name)  
}  
console.log(name);

这里的两个console显示的内容都是local,因为如果有块级作用域的话,第二个console出来的内容应该是global,但是name这个变量被if中的name给覆盖了。
es6中,多了let这个声明变量的关键字,使用let声明变量的作用域是块级作用域。还是上面es5中的代码,我们将if中的var变为let看一下:

var name="global";  
if(true){  
    let name="local";  
    console.log(name)  
}  
console.log(name);  

这时,console出来的内容就是

local
global

这就证实了,使用let声明变量的作用域是块级作用域。

4.为下面html中每一个li添加点击事件,点击alert出自己为ul中的第几个。
<ul>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
</ul>

下面代码中是否有问题?如果有应该如何改善?

var liList = document.getElementsByTagName('li');
for(var i = 0, li; li = liList[i]; i++) {
    li.addEventListener('click', function() {
        alert(i);
    }, false);
}

这道题有两个问题,第一个是for循环的写法上存在问题,没有说明i的最大值是多少;第二个问题是根据js中变量的作用域链来看,i在这个匿名函数中没有声明,所以会去外面找,但是这个i因为没有最大值,一直++,所以也不会知道i是多少。
应该使用如下方法去写:
方法一:

var liList = document.getElementsByTagName('li');
for(var i = 0, len = liList.length; i < len; i++) {
    (function (i) {
        liList[i].addEventListener('click', function () {
            alert(i);
        });
    })(i);
}

这种方法使用闭包的方式,将i传入。不会出现每次调用因为匿名函数中找不到i,去外部找,i已经加到最大值的情况。
方法二:

for(let i = 0, len = liList.length; i < len; i++) {
    liList[i].addEventListener('click', function () {
        alert(i);
    })
}

使用es6的块级作用域解决。