JavaScript闭包20171229

一 变量作用域

  • 2种作用域:全局&局部;
  • js链式作用域结构,函数内部可以直接读取全局变量;函数外部无法读取函数内的局部变量;
  • 函数内部声明变量,要用var,如果不用var,直接n=3,实际上是声明了一个全局变量;

二 如何从外部读取局部变量

  • 在函数A的内部,再定义一个函数B,函数B就可以引用函数A的局部变量(这有点像偷换概念啊。。)
function A(){
    var n=3;
    function B(){
        console.log(n);
    }
}
  • 既然B()可以读取A()中的局部变量,那么重要把B()作为返回值,就可以在A()外部,读取A的内部变量了;
function A(){
    var n = 3;
    function B(){
        console.log(n);
    }
    return B;
}
var re = A();
re();//3

三 闭包的概念

  • 上述,B函数,就是闭包;
  • 一个理解:闭包是 能够读取其他函数内部变量的 函数;——把函数内部和函数外部连接起来的一座桥梁;
  • 在JavaScript中,对于函数A,只有函数A内部的子函数(比如取名叫B)才能读取函数A内的局部变量(其实是函数B的外部变量);——简单理解:定义在一个函数内部的函数;

四 闭包用途-2个

  • 读取函数内部的变量;
  • 让这些变量的值始终保持在内存中;
    re,就是返回的闭包f2函数,一共运行了2次:第一次的值0,第二次的值1;这表示,函数f1中的局部变量n一直保持在内存中,没有在f1调用后自动清除;

    function f1(){
        var n=0;
        nAdd = function(){n+=1;}
        // 1 nAdd前面没有var,所以它是一个全局变量;
        // 2 nAdd的值,是一个匿名函数,这个匿名函数本身也是一个闭包----nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作;
        function f2(){
            console.log(n);
        }
        return f2;
    }
    var re = f1();
    re();//0
    nAdd();
    re();//1
    
    var name = "我的window";
    var object = {
        name:"my object",
        getNameFunc:function(){
            return function(){
                return this.name;
            };
        }
    };
    object.getNameFunc()()//"我的window"
    
    var name = "我的window";
    var object = {
        name:"my object",
        getNameFunc:function(){
            var that = this;
            return function(){
                return that.name;
            }
    
        }
    };
    object.getNameFunc()();//"my object"
    

python-notes

一 基础

1.1 安装

  • 安装完成后,命令行输入python,显示版本信息,安装并加入环境变量成功;安装官方下载的python,自动装上了解释器Cpython;
  • 交互模式 & 命令行模式
交互模式输入一行,执行一行,用来初学者调试学习,不是python真正的运行环境;

1.2 test-python

  • 换行格式:''' '''
print('''line1
line2
line3''')
  • 格式化字符
#这是注释
name=input('请输入你的名字:')
a=int(input('去年的成绩:'))
b=int(input('今年的成绩:'))
c=(b-a)/a*100
d=(a-b)/a*100
if a<b:
    print('%s 今年的成绩提升了:%.2f%%' % (name,c))
elif a>b:
    print('%s 今年的成绩下降了:%.2f%%' % (name,d))
else:
    print('%s 今年的成绩与去年持平' % name)

#下面这种是用format
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'
  • 条件
name=input('请输入你的名字:')
a=int(input('输入身高,单位是cm:'))
b=int(input('输入体重,单位是kg:'))
bmi = b/(a*a/10000);
if bmi>32:
    print('严重肥胖')
elif bmi>28:
    print('肥胖')
elif bmi>25:
    print('过重')
elif bmi>18.5:
    print('正常')
else:
    print('过轻')
  • 循环,注意:不要滥用break和continue,会造成代码执行逻辑分叉过多,容易出错;可以通过改写循环条件或者修改循环逻辑
# for in
sum = 0
for x in range(101):
    sum = sum+x
print(sum)
# while
sum = 0
n = 99
while n>0:
    sum = sum+n
    n = n-2
print(sum)
# break
n = 1
while n <= 100:
    if n > 10: # 当n = 11时,条件满足,执行break语句
        break # break语句会结束当前循环
    print(n)
    n = n + 1
print('END')
# continue
n = 0
while n < 10:
    n = n+1
    if n%2==1:
        continue
    print(n)
  • range
# 计算任意两个整数之间所有数字的和
sum = 0
num1 = int(input('请输入第一个整数:'))
num2 = int(input('请输入第二个整数:'))
min=0
max=0
if num1>num2:
    min=num2
    max=num1
elif num1<num2:
    min=num1
    max=num2
else:
    min=num1
    max=num1
for x in range(min,max+1):
    sum=sum+x
print('这两个数之间所有整数的和为:%d' % sum)

1.3 语法基础

  • 数据类型:整数;浮点数;字符串;布尔值;空值;变量;常量
>>> 10 // 3
3
>>> 10 / 3
3.3333333333333335
  • python-动态语言:变量类型不固定;
a = 123 # a是整数
print(a)
a = 'ABC' # a变为字符串
print(a)
  • 字符串的编码问题:ASCII,GB2312,Unicode,UTF-8;注意:如果没有特殊要求,牢记使用UTF-8;
1、ASCII(1个字节) : 
8个比特bit 1个字节byte;
一个字节能表示的最大整数255;
最早只有127个字符编码--ASCII编码;
要处理中文,至少要2个字节,而且还不能和ASCII编码冲突,
所以,中国制定了GB2312编码;
2、GB2312;
但各国有各国的标准了,
比如日文Shift_JIS,韩文Euc-kr;
多语言混合的文本里,不可避免会冲突,乱码;
3、Unicode:所以有了Unicode,它把所有语言都统一到一套编码里;
Unicode(2个字节)最常用的是两个字节标识一个字符;
统一成Unicode,乱码问题是解决了,
但是如果文本基本上是英文的话,
用Unicode编码比ASCII编码需要多一倍的存储空间;
所以,出现了把Unicode编码转化为“可变长编码”的UTF-8编码;
4、UTF-8:把一个Unicode字符根据不同的数字大小编码成1-6个字节,
常用的英文字母被编码成1个字节,汉字通常是3个字节,
很生僻的字符才会4-6个字节;
并且,ASCII编码可以被看成是UTF-8编码的一部分,
所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作;

python的2种内置数据类型:list(列表)和tuple(元组)

  • list-有序集合;list里面元素的数据类型可以不同;list元素可以使另一个list
classmates = ['Michael', 'Bob', 'Tracy']
len(classmates)
classmates[2]
#索引2'Tracy'
classmates[-1]
#倒数第一个'Tracy'
classmates[-2]
#倒数第二个'Bob'
#添加到末尾,或插入到指定位置
classmates.append('Adam')
classmates.insert(1, 'Jack')
#['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
#删除末尾,或删除指定位置
classmates.pop()
#'Adam'
classmates.pop(1)
#'Jack'
#替换元素
classmates[1]='Sarah'
#['Michael', 'Sarah', 'Tracy']

  • tuple-一旦初始化就不能修改;因为不可变,代码更安全;能用tuple代替list就尽量用tuple;
#注意:定义只有一个元素的tuple时,【必须】加一个逗号,,来消除歧义(()括号可以表示数学公式中的小括号,python规定,按小括号计算,结果变成了一个数)
t = (1,)
#python在显示只有1个元素的tuple时,也会加一个逗号,以免误解;

# 来看一个“可变的”tuple
t = ('a', 'b', ['A', 'B'])
t[2][0] = 'X'
t[2][1] = 'Y'
t
('a', 'b', ['X', 'Y'])
# 表面上,tuple好像变了,但其实变的不是tuple的元素,而是list的元素;
# tuple一开始指向的list并没有改;
# tuple的每个元素,指向永远不变;
# 指向'a',就不能指向'b',指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的;
# 要确保tuple不能改变,要保证tuple的每一个元素本身也不能变;

dict和set

  • dict, python内置的字典,在其他语言中称为map,使用键-值(key-value)存储,极快的查找速度;在存进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value;
  • 注意:dict内部存放的顺序和key放入的顺序没有关系
  • a.查找和插入的速度极快,不会随着key的增加而变慢;b.需要占用大量的内存,内存浪费多
  • dict的key必须是 不可变对象
  • 通过key计算位置的算法,叫做hash哈希算法;python中,字符串、整数都不可变,可以作为key,list是可变的,不能作为key
d={'michael':98,'bob':85,'tracy':93}
print(d['michael'])
'thomas' in d
False
d.get('thomas',-1)
# 如果key不存在,返回自己指定的value
-1

d.pop('bob')#删除一个key
85
  • set ,是一组key的集合,但不存储value,里面的key不能重复
s = set([1,2,3,3,4,4,5])
s
{1,2,3,4,5}
s.add(8)
s
{1,2,3,4,5,8}
s.remove(3)
s
{1,2,4,5,8}
# set可以做交集、并集
s1=set([1,2,3])
s2=set([2,3,4])
s1&s2
{2,3}
s1|s2
{1,2,3,4}
  • 不可变对象
# list内容是会变化的,比如
a=['c','b','a']
a.sort()
a
['a','b','c']
# str不可变
a = 'abc'
b = a.replace('a','A')
'Abc'
a
'abc'#没有变化

# a是变量,'abc'才是字符串对象;a本身是一个变量,它指向的对象的内容是'abc';
# replace创建了一个新的字符串'Abc'并返回
# 变量a仍指向字符串'abc',但变量b却指向新字符串'Abc'了

原生JavaScript语法(一)

20171213-1218

1基本

  • js原型数据类型:Boolean,null,undefined,Number,String,Symbol(ECMAScript6) ;
//Symbols在for...in迭代中不可枚举;
var obj = {};
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";
for (var i in obj) {
   console.log(i); // logs "c" and "d"
}
//当永JSON.stringify()时,以symbol作为键的属性辉被忽略;
JSON.stringify({[Symbol("foo")]: "foo"});                 
// '{}'
  • Object
  • js {},可视为其他语言中Map或者Dictionary的数据结构——一组键值对;
js中的 键 必须是  字符串(这是js中对象的一个小问题,实际上用Number或者其他数据类型做键也是合理的);
为了解决这个问题,最新的ES6规范引入了:Map;

  • Map-极快的查找速度;
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael');
或者
var m = new Map();
m.set("Adam",77);m.set("Bob",99);
m.get("Bob");
m.delete("Adam");
  • Set是一组key的集合,key不能重复
var s = new Set([1,2,3,'3']);
s.add(4);
s.delete(2);
  • iterable - Array,Map,Set都属于iterable类型
具有iterable类型的集合可以通过新的 for of来遍历;
var a = [1,2,3];
for(var x of a){}
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
    console.log(x);
}
for (var x of s) { // 遍历Set
    console.log(x);
}
for (var x of m) { // 遍历Map
    console.log(x[0] + '=' + x[1]);
}
  • for…of 和 for…in
//for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
  • forEach() ES5.1
var s = new Set(['a','b','c']);
s.forEach(function(element){
    console.log(element);
})

2函数

  • 定义和调用
  • 变量作用域
function foo(){
    var x = 1;
    function bar(){
        var x = "A";
        console.log("x in bar() = "+x);//A
    }
    console.log("x in foo() = "+x);//1
    bar();
}
//调用foo()
foo();
//结果
x in foo()  = 1
x in bar() = A

  • 变量提升,值不提升
function foo(){
    var x = "hello,"+y;
    console.log(x);
    var y = "bob";
}
//调用foo()
foo();
//结果
hello,undefined
//它被提升成了
function foo(){
    var y;
    var x = "hello,"+y;
    console.log(x);
    y = "bob";
}

  • 由于JavaScript提升声明,不提升值;所以,在函数内部定义变量,严格遵守,在函数内部首先申明所有变量;
function foo() {
    var
        x = 1, // x初始化为1
        y = x + 1, // y初始化为2
        z, i; // z和i为undefined
    // 其他语句:
    for (i=0; i<100; i++) {
        ...
    }
}
  • 全局作用域
//JavaScript默认有一个全局对象window;
//全局作用域的变量,实际上是被绑定到window的一个属性;
var course = "learn";
alert(course);//learn
alert(window.course);//learn
  • 由于函数定义有两种方式,以变量方式var foo = function(){}定义的函数实际上也是一个全局变量;因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:
'use strict'
function foo(){
    alert("foo");
}
foo();//直接调用
window.foo();//通过window.foo()调用

//我们每次调用的alert()函数也是window的一个变量;
var old_alert = window.alert;
//给alert赋一个新函数
window.alert = function(){console.log("不alert了,打印");}
alert();
//结果
"不alert了,打印"
  • JavaScript只有一个全局作用域,任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找;最后如果在全局作用域中也没有找到,则报ReferenceError错误;
  • 名字空间;如果不同的JavaScript文件使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现;
//减少冲突的一个办法:把自己的所有变量和函数,全部绑定到一个全局变量中
var myapp = {};//唯一的全局变量
myapp.name = "myname";
myapp.version = 1.0;
myapp.foo = function(){
    return "lalala";
};
//许多JavaScript库都是这样做的:jQuery,YUI,underscore等

  • 局部作用域:函数内部;需要另外解决“块级作用域”的问题;
//ES6引入了新的关键字let,申明一个块级作用域
function foo() {
    var sum = 0;
    for (let i=0; i<100; i++) {
        sum += i;
    }
    // SyntaxError:
    i += 1;
}
  • 常量;ES6之前js只能申明变量;ES6引入新的关键字const定义常量;const和let都有块级作用域;
//ES6之前
var PI  =3.14;
//ES6
const PI = 3.14;
PI=3;//这样修改不了;某些浏览器不报错,但是不起作用
PI;//3.14

  • 解构赋值:ES6,同时对一组变量进行赋值;
var array = ['hello', 'JavaScript', 'ES6'];
var x = array[0];
var y = array[1];
var z = array[2];
//还可以嵌套赋值
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
//还可以忽略某些元素
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'
  • 若需要从一个对象中 取出 若干属性,也可以使用解构赋值;
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};
var {name, age, passport} = person;
// name, age, passport分别被赋值为对应属性:
console.log('name = ' + name + ', age = ' + age + ', passport = ' + passport);
//name = 小明, age = 20, passport = G-12345678

//如果 要使用的变量名  和 属性名不一致,可以用这样获取:
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};

// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // 'G-12345678'

var {hostname:domain, pathname:path} = location;
domain
"www.liaoxuefeng.com"
path
"/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014344993159773a464f34e1724700a6d5dd9e235ceb7c000"
hostname//VM642:1 Uncaught ReferenceError: hostname is not defined
    at <anonymous>:1:1

  • 可以利用解构赋值 传参:
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
    return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
buildDate({ year: 2017, month: 1, day: 1 });
buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 });
  • 方法:在一个对象中 绑定函数,称为这个对象的方法
var xiaoming = {
    name:"小明",
    birth:1991,
    age:function(){
        var y = new Date().getFullYear();
        return y-this.birth;
    }
};
xiaoming.age;
xiaoming.age();
  • 方法,在内部使用了this关键字;在一个方法内部,this始终指向当前对象,也就是xiaoming这个变量;所以,this.birth,可以拿到xiaoming的birth属性;
//要保证,this 的指向正确,必须用obj.xxx()的形式调用!
var fn = xiaoming.age;
fn();//NaN
  • ECMA:在strict模式下让函数的this指向undefined;避免不容易发现的错误;
  • 下面的写法有错:this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了(在非strict模式下,它重新指向的全局对象window)
'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); 
  • 正确的:用一个that变量首先捕获this;用var that = this,就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中;
'use strict';
var xiaoming = {
    name:"小明",
    birth:1991,
    age:function(){
        var that = this;//在方法内部一开始就捕获this
        function getAgeFromBirth(){
            var y = new Date().getFullYear();
            return y-that.birth;
        }
        return getAgeFromBirth();
    }
}
xiaoming.age();//26
  • apply:可以人为指定函数的this指向哪个对象,它接收2个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,标识函数本身的参数;
function getAge(){
    var y = new Date().getFullYear();
    return y-this.birth;
}
var xiaoming = {
    name:'小明',
    birth:1991,
    age:getAge
};
xiaoming.age();//26
getAge.apply(xiaoming, []);//26
  • call: 类似于apply,区别:apply()把参数打包成Array再传入;call()把参数按顺序传入;
Math.max.apply(null,[2,5,4]);
Math.max.call(null,3,5,4);
//对普通函数调用,通常把this绑定为null
  • 装饰器:利用apply(),还可以动态改变函数的行为;JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt():
'use strict'
var count = 0;
var oldParseInt = parseInt;
window.parseInt = function(){
    count += 1;
    return oldParseInt.apply(null,arguments);//调用原函数
}
//测试
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3

3 高阶函数

  • 一个函数可以接收另一个函数作为参数;
function add(x,y,f){
    return f(x)+f(y);
}
add(-5,6,Math.abs);//11

3.1 map/reduce

  • map()的方法定义在JavaScript的Array中;
'use strict';
function pow(x){
    return x * x;
}
var arr = [1,2,3,4,5,6,7,8,9];
var results = arr.map(pow);

var arr = [1,3,5,7,9];
arr.reduce(fucntion(x,y){
    return x+y;
});//25
  • 使用map/reduce
//将字符串'12468'变成整数12468,不使用parseInt
var ori = '12468';
function string2int(mystr){
    var result = mystr.split("").map(function(x){return +x;}).reduce(function(x,y){return x*10+y;});
    return result;
}
string2int(ori);//12468
  • 注意事项之一
var arr = ['1', '2', '3'];
var r;
r = arr.map(parseInt);
//结果r,是!:1,NaN,NaN
//因为,map()接收的回调函数可以有3各参数callback(currentValue,index,array),通常仅需要第一个参数,而忽略了传入的后面两个参数;但是,parseInt(string,radix),没有忽略第二个参数,导致实际上:
parseInt('0',0);//按十进制转换
parseInt('1',1);//NaN,没有一进制
parseInt('2',2);//NaN,按二进制转换不允许出现2
//可以改为
r = arr.map(Number);
//因为Number(value)函数仅接收一个参数
function normalize(arr){
    return arr.map(function(x){var a = x.toLowerCase();
    return a.slice(0,1).toUpperCase()+a.slice(1);})
}
//入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']。

3.2 filter-筛选作用

  • filter(),接收一个函数;把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素;
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
    return x % 2 !== 0;
});
r;//1,5,9,15
//去掉一个Array元素中的空字符串
var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
    return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
});
r;//["A", "B", "C"]

  • filter接收的回调函数,可以有多个参数,通常,只使用第一个参数(Array的某个元素);还可以接收另外两个函数,表示元素的位置和数据本身;
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次打印'A', 'B', 'C'
    console.log(index); // 依次打印0, 1, 2
    console.log(self); // self就是变量arr
    return true;
});
//筛选素数
function get_primes(arr){
    arr.filter(function(x){
        if(x==1){return false;}
        var i = 2;
        while(i < x){
           if(x % i == 0){return false;}
           i++;
        }
        return true;
    });
}

3.3 sort-排序-sort默认按字符串排序,按ASCII;

var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1; // ['A', 'B', 'C']
a2; // ['A', 'B', 'C']
a1 === a2; // true, a1和a2是同一对象
//sort()可接收函数,自定义大小比较方法
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
    return 0;
}); // [20, 10, 2, 1]

3.4 闭包

  • 函数作为返回值
  • 注意,返回的函数不立即执行的问题;
  • 创建一个匿名函数让它立即执行;
function count(){
    var arr = [];
    for(var i=1;i<=3;i++){
        arr.push((function(n){
        return function(){
        return n*n;
        }})(i));
    }
    return arr;
}
var re = count();
var f1=re[0];
var f2=re[1];
var f3=re[2];
f1();//1
f2();//4
f3();//9
//由于JavaScript语法解析的问题,要用括号把整个函数定义括起来,否则会报SyntaxError错误;
(function (x) { return x * x }) (3);
  • 通过闭包,封装一个私有变量; 在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x;
  • 闭包,就是携带状态的函数,并且它的状态可以完全对外隐藏起来;
function create_count(initial){
    var x = initial || 0;
    return {
        inc:function(){
            x+=1;
            return x;
        }
    }
}
var c1 = create_count();
c1.inc();//1
c1.inc();//2
c1.inc();//3
var c2 = create_count(10);
c2.inc();//11
c2.inc();//12
c2.inc();//13
  • 闭包,还可以把多惨呼的函数,变成单参数的函数;比如 计算x的y次方,可以用Math.pow(x,y),考虑到经常用x平方和x三次方,可以利用闭包创建新的函数pow2和pow3;
function make_pow(n){
    return function(x){
        return Math.pow(x,n);
    }
}
//创建两个新函数
var pow2 = make_pow(2);
var pow3 = make_pow(3);

3.5 箭头函数

  • ES6标准新增了一种新的函数,Arrow Function箭头函数;
x => {
    if(x>0){
        return x*x;
    }
    else{
        return -x*x;
    }
}

//如果参数不是一个,就要用括号()括起来:
(x,y) => x*x + y*y;

//无参数
() => 3.14

// 可变参数
(x,y,...rest) => {
    var i,sum = x+y;
    for(i=0;i<rest.length;i++){
        sum+=rest[i];
    }
    return sum;
}

// 如果要返回一个对象
x => ({foo:x})
  • this; 使用箭头函数,this总是指向词法作用域,就是外层调用者obj;
var obj = {
    birth:1991,
    getAge:function(){
        var b = this.birth;
        var fn = () => new Date().getFullYear() - this.birth;//可以正确指向obj的birth
        return fn();
        //var fn = function () {
            //return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
    }
}
obj.getAge();//27
  • 由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定——传入的第一个参数被忽略;
var obj = {
    birth: 1990,
    getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth; // this.birth仍是1990
        return fn.call({birth:2000}, year);
    }
};
obj.getAge(2015); // 25
'use strict'
var arr = [10, 20, 1, 2];
arr.sort((x, y) => {
   if(x<y){return -1;}
   if(x>y){return 1;}
   return 0;
});
console.log(arr); // [1, 2, 10, 20]

3.5 generator生成器ES6

function*  fib(max){
    var
        t,
        a=0,
        b=1,
        n=0;
    while(n<max){
        yield a;
        [a,b]=[b,a+b];
        n++;
    }
    return;
}
for(var x of fib(10)){
    console.log(x);
}
  • generator可以在执行过程中多次返回,所以看上去就像一个可以记住记住执行状态的函数;
  • 这样,写一个generator就可以实现需要用面向对象才能实现的功能;
  • 还有一个好处:把异步回调代码变成“同步”代码;回调越多,代码越难看;有了generator,用AJAX可以这么写:(看上去是同步的代码,实际上是异步的)
try{
    r1 = yield ajax("http://url-1",data);
    r2 = yield ajax("http://url-2",data);
    r3 = yield ajax("http://url-3",data);

}catch(err){
    handle(err);
}
// 自增函数
function* next_id(){
    var current_id=1;
    while(true){
        yield current_id;
        current_id++;
    }
}

var x;
var pass = true;
var g = next_id();
for(x=1;x<100;x++){
    console.log(g.next().value);
}

4 标准对象

  • typeof
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
  • 包装对象
number Number
boolean Boolean
string String

// 注意就行了
123..toString();//注意是2个点!
(123).toString();
var n = Number("456");
typeof n;
"number"
var m = new Number("333");
typeof m
"object"
//typeof操作符可以判断出number、boolean、string、function和undefined
//判断Array要使用Array.isArray(arr);
//判断某个全局变量是否存在用typeof window.myVar === 'undefined';
//函数内部判断某个变量是否存在用typeof myVar === 'undefined'。
//用parseInt()或parseFloat()来转换任意类型到number;
//用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
//通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
  • Date

  • RegExp

// \d可以匹配一个数字,\w可以匹配一个字母或数字;
// . 可以匹配任意字符
// * 表示任意个字符(包括0个),
// + 表示至少一个字符
// ? 表示0个或1个字符
// {n}表示n个字符
// {n,m}表示n-m个字符
var reg = /\d{3}\s+\d{3,8}/;//可以匹配任意个空格隔开的带区号的电话号码
// \d{3},匹配3个数字
// \s匹配一个空格(可包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' ','\t\t'等 
// \d{3,8}表示3-8个数字,例如'12345'
// 如果要匹配'010-12345',
var reg2 = /\d{3}\-\d{3,8}/
  • JSON-JavaScript Object Notation,一种数据交换格式
  • 最开始设计的JSON是JavaScript的一个子集,在JSON中,一共就几种数据类型:number,boolean,string,null,array,object;
  • JSON定死了字符集必须是UTF-8,这样表示多语言就没有问题了;
  • 为了统一解析,JSON的字符串规定必须用双引号"",Object的键也必须用双引号""
  • 序列化 JSON.stringify()
'use strict'
var xiaoming = {
    name:'小明',
    age:16,
    gender:true,
    height:1.60,
    grade:null,
    'middle-school':'清苑',
    skill:['JavaScript','java','python','lisp']
};
var s = JSON.stringify(xiaoming);
console.log(s);
// 要输出好看一些,可以加上参数,按缩进输出:
JSON.stringify(xiaoming,null,' ');
// 上面第二个参数,用于控制如何筛选对象的键值,如果只想输出指定的属性,可以传入Array;
JSON.stringify(xiaoming,['name','skill'],' ');
// 还可以传入一个函数,这样,对象的每个键值对都会被函数先处理
function convert(key,value){
    if(typeof value === 'string'){
        return value.toUpperCase();
    }
    return value;
}
JSON.stringify(xiaoming,convert,' ');
// 如果还想【更精确控制】如何序列化,可以给xiaoming定义一个toJSON()方法,直接返回JSON应该序列化的数据:
var xiaoming = {
    name:'小明',
    age:16,
    gender:true,
    height:1.60,
    grade:null,
    'middle-school':'清苑',
    skills:['JavaScript','java','python','lisp'],
    toJSON:function(){
        return {
            'Name':this.name,
            'Age':this.age,
            'Height':this.height
        };
    }
}
JSON.stringify(xiaoming);
  • 反 序列化 JSON.parse()变成一个JavaScript对象
JSON.parse('[1,2,3,true]');//[1,2,3,true]
JSON.parse('{"name":"小明","age":16}');//Object {name: "小明", age: 16}
JSON.parse('true');//true
JSON.parse('123.45');//123.45

// JSON.parse()还可以接收一个函数,用来转换解析出的属性
var obj = JSON.parse('{"name":"小明","age":15}',
function(key,value){
    if(key === 'name'){
        return value+'同学';
    }
    return value;
});
console.log(JSON.stringify(obj));//{"name":"小明同学","age":15}
// 访问API获取JSON
var url = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json';
$.getJSON(url,function(data){
    var city = data.query.results.channel.location.city;
    var forecast = data.query.results.channel.item.forecast;
    var result = {
        city:city,
        forecast:forecast
    };
    console.log(JSON.stringify(result,null,'  '));
})

从今天起,多吃水果和蔬菜

1 吃的:维生素C,蛋白,大豆异黄酮,蛋白质,维生素,果胶……

水果:

苹果;樱桃;柠檬;豆浆;牛奶(晚上喝);新鲜枣;杏仁;桃果核;草莓;紫葡萄;猕猴桃;桔子;火龙果;柚子;石榴(抗氧化);杏;桑葚;

蔬菜:

鸡蛋;鱼肉;西兰花;胡萝卜;白萝卜;芦笋;甘薯;蘑菇;黄瓜;冬瓜;丝瓜;大豆;西红柿;三文鱼;莲藕;豌豆;洋葱;海带;鲑鱼;燕麦;地瓜(适合早餐)水;

薏米莲子红枣粥;薏米绿豆百合粥;柑橘银耳薏米羹;薏米杏仁瘦肉汤;

2 用的