一.sort()
-
排序的核心?比较两个元素的大小
-
问题:
[1,10,5,45].sort();
//(4) [1, 10, 45, 5]
因为:Array的sort()方法默认把所有元素先转换为String再排序,同时4的ASCll码比5小。
- 解决
//常规方式
var arr = [1,10,45,5];
arr.sort(function(x,y){
if(x > y){
return 1;
}
if(x < y){
return -1;
}
return 0;
});
//(4) [1, 5, 10, 45]
//优雅的方式
var arr = [1,10,45,5];
arr.sort(function(a,b){
return a-b;
});
//(4) [1, 5, 10, 45]
sort()
sort()数值排序
- sort()方法会直接修改原数组Array,同时没有"另起炉灶"---copy,返回的结果仍然是当前Array。
var a1 = ['b','a','c'];
var a2 = a1.sort();
console.log(a1);//["a", "b", "c"]
console.log(a2);//["a", "b", "c"]
二. 闭包
1. 函数作为返回值
function parent(arr){
var child = function(){
return arr.reduce(function(a,b){
return a+b;
});
}
return child;
}
var f = parent([1,2,3,4,5]);
f();//15
-
More:该子函数可以引用父函数中的参数和局部变量;当从父函数中返回子函数时,相关的参数和变量仍保存在返回的子函数内。
-
注意:当我们调用父函数时,每次调用都会返回一个新的函数,即使传入相同的参数:
var f1 = parent([1,2,3,4,5]);
var f2 = parent([1,2,3,4,5]);
f1 === f2;//false
2. 返回的函数并没有立刻执行
- 什么意思?
function count(){
var arr = [];
for(var i = 1;i <=3;i++){
arr.push(function(){
return i*i;
});
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//16
console.log(f2());//16
console.log(f3());//16
- 变量result是一个指向函数count执行结果arr的引用,该数组中包含了三个函数:
ƒ (){
return i*i;
}
-
这三个函数都引用了父函数count中的局部变量 i,但这三个返回的子函数并没有立即执行。当这三个函数都返回时,它们所引用的变量i已经变成了4,所以三次结果均为16。
-
返回闭包时要牢记一点:返回的函数不要引用任何循环变量,或者后续会发生变化的变量。
-
这里你想要的结果是:1 4 9,可以用以下方法实现:
var arr = [1,2,3];
function square(arr){
return arr.map(function(a){
return a*a;
});
}
square(arr);//[1, 4, 9]
- 如果你非要用嵌套函数的方式
//创建一个匿名函数并立即执行
function count(){
var arr = [];
for(var i = 1;i <=3;i++){
arr.push((function(a){
return function(){
return a*a;
}
})(i));
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//1
console.log(f2());//4
console.log(f3());//9
//优雅点的---let
function count(){
var arr = [];
for(let i = 1;i <=3;i++){
arr.push(function(){
return i*i;
});
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//1
console.log(f2());//4
console.log(f3());//9
3. 闭包的真正威力
-
模拟私有变量:
-
设计一个计数器,执行一下,加1,而不是人工加1:
function counter(i){
return i++;
}
counter(0);
//0
counter(1);
//1
counter(2);
//2
counter(3);
//3
//自动化
function counter(initial){
var x = initial || 0;//防止initial = undefined
return {
inc : function(){
return x++;
}
};
}
var c1 = counter();
c1.inc();//0
c1.inc();//1
c1.inc();//2
c1.inc();//3
闭包就是携带状态的函数,并且它的状态可以对外完全隐藏。
4. 使用闭包将多参数的函数变成单参数的函数。
- 比如:x^y 可以使用Math.pow(x,y)函数,但对于x^2 或x^3有点大材小用了,使用闭包弄个简洁版的。
function make_pow(y){
return function(x){
return Math.pow(x,y);
};
}
var pow2 = make_pow(2);
var pow3 = make_pow(3);
pow2(5);//25
pow3(3);//27
三. 箭头函数(Arrow Function)
1.箭头函数 & 匿名函数 区别?
箭头函数内部的this是词法作用域,由上下文决定。
//匿名函数
var obj = {
birth : 1996,
getAge : function(){
var b = this.birth;
var fn = function(){
return (new Date().getFullYear() - this.birth);
}
return fn();
}
}
obj.getAge();//NaN
2017 - undefined;//NaN
//箭头函数
var obj = {
birth : 1996,
getAge : function(){
var fn = () => new Date().getFullYear() - this.birth;
return fn();
}
}
obj.getAge();//21
//由于箭头函数中的this已绑定了词法作用域,
//因此call()或者apply()调用箭头函数时,传入的第一个参数无效。
var obj = {
birth : 1996,
getAge : function(year){
var f = (y) => y - this.birth;//this.birth仍为1996,而非2000
return f.call({birth: 2000},year);
}
}
obj.getAge(2017);//21
四.generator(生成器)
1.调用函数:传入参数,返回结果
//常规方法
function fib(count){
var a = 0,
b = 1,
temp,
arr = [0,1];
while(arr.length < count){
temp = a + b;
a = b;
b = temp;
arr.push(temp);
}
return arr;
}
fib(10);
>>>
(10) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
-
调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,都会返回一个带有value和done两个属性的对象。value属性表示当前的内部状态的值,是yield或者return后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
-
return & yield
1.相似处:都返回紧跟在语句后面的那个表达式的值。
2.区别:在一个函数中,只能执行一个return语句,执行后,就结束该函数了。而每个yield表达式都能通过next()方法在该函数中执行。在一个函数中,每次遇到yield语句,函数暂停执行,下一次再从该位置继续往后执行,因此,它具有位置记忆的能力。
3.next()方法会执行Generator函数中的yield表达式和return语句;但当使用for...of时,仅会执行yield表达式。
4.开发者角度:通过next方法,Generator函数依次遍历yield表达式。
5.Generator函数角度:依次生成了一系列的值,也就是Generator(生成器)名字的来源。
next() & for...of
///next()
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
var f = fib(5);
f.next();
//{value: 0, done: false}
f.next();
//{value: 1, done: false}
f.next();
//{value: 1, done: false}
f.next();
//{value: 2, done: false}
f.next();
//{value: 3, done: true}
//for...of
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
for(var i of fib(5)){
console.log(i);
}
>>>
0
1
1
2
- 如果在普通函数中使用yield表达式,会产生语句错误。
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function* (a) {
//普通函数
a.forEach(function (item) {
if (typeof item !== 'number') {
yield* flat(item);
} else {
yield item;
}
});
};
for (var f of flat(arr)){
console.log(f);
}
//Uncaught SyntaxError: Unexpected identifier
//解决:使用for循环替代内部的普通函数
var arr = [1,[[2,3],4],[5,6]];
var flat = function* (a){
var length = a.length;
for(var i = 0;i < length;i++){
var item = a[i];
//将数组中的嵌套数组中的每个元素依次输出
if(typeof item !== 'number'){
yield* flat(item);
}else{
yield item;
}
}
};
for(var f of flat(arr)){
console.log(f);
}
>>>
1
2
3
4
5
6
- yield表达式如果用在另一个表达式中,必须用圆括号括起来:
function* demo() {
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError
}
//Uncaught SyntaxError: Unexpected identifier
function* demo() {
console.log('Hello ' + (yield)); // OK
console.log('Hello ' + (yield 123)); // OK
}
var f = demo();
f.next();
//{value: undefined, done: false}
f.next();
>>>
Hello undefined
{value: 123, done: false}
f.next();
>>>
Hello undefined
{value: undefined, done: true}
- yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号
function* demo(){
foo(yield 'a',yield 'b');
let input = yield;
}
网友评论