月度归档:2020年04月

JS 学习(二)

函数

定义与使用

function name() { ... }

  • 函数内部使用 arguments 变量,获取所有的参数
  • function name(a, b, ...rest) { ... }
    • 使用 rest 变量,获取已指明参数的后面所有的参数

return 与其要返回的值应在同一行,否则 js 执行时自动在 return 后面添加 ; ,导致返回 undefined

作用域与解构赋值

使用 var 声明的变量是有作用域的,如果是在函数内部定义,则变量的作用域就是在函数内部。如果不在函数内部定义,变量的作用域就是在全局。全局变量都是作为 window 对象的一个属性。JS 中函数可以嵌套,子函数可以使用父函数的变量,但是如果子父函数声明了相同的变量,那么子函数将使用自身声明的变量。

全局作用域:window 对象

  • 变量、对象、函数都是 window 对象的一个属性。

局部作用域:函数内部

变量提升:函数中声明的变量会提升到函数顶部,提升的是声明,而不是赋值

  • 如:console.log(x);// undefined
    var x = 2;
  • 输出 undefined ,而不是报错

块级作用域:{}

  • let 关键字声明块级作用域的变量
  • const 声明常量,也具备块级作用域

解构赋值:将数组或对象的数据为多个变量赋值

  • var [a, b, c] = ['hello', 'world', 'ni']
    • var [a, [b, c]] = ['hello', ['world', 'ni']]
  • var {name, age} = {name:'kangkang', age: 12}
    • var {name, {age}} = {name:kangkang, defail: {age: 12}}

方法

在函数内部使用 this

  • 以对象的方式调用函数,this 指向当前调用对象
  • 单独调用函数,this 指向 window 对象
    • 使用 strict 模式,this 指向 undefined

可以用一个 that 保存 this 的指向

var obj = {
   name: 'xiaoming',
   birth: 1994,
   age: function () {
       var that = this;
       function getAge() {
           var y = new Date().getFullYear();
           return y - that.birth;
      }
       return getAge();
  }
}

apply

通过 apply 函数调用修改 this 指向,apply 与 call 类似,区别是 apply 调用时函数本身的参数是一个数组,call 是一个个单独的参数。

function getAge() {
   var y = new Date().getFullYear();
   return y - this.birth;
}
var obj = {
   name: 'xiaoming',
   birth: 1994,
   age: getAge
}
console.log(obj.age());
console.log(getAge.apply(obj, []));

对普通函数调用一般将 this 指向 null。Math.max.apply(null, [3, 5, 4])。

装饰器

利用 apply 可以动态改变函数的行为。

统计代码调用了多少次 parseInt()

'use strict';

var count = 0;
var oldParseInt = parseInt; // 保存原函数

window.parseInt = function () {
   count += 1;
   return oldParseInt.apply(null, arguments); // 调用原函数
};

高阶函数

就是将函数作为函数的参数。

map / reduce

map

  • 将数组中的每一个元素经函数处理后返回,形成一个新的数组arr.map(function (x) {
       return x * x;
    });
  • 不会修改原数组,会生成一个新的数组

reduce

  • 将函数的结果与下一个元素作累积计算arr.reduce(function (x, y) {
       return x * 10 + y;
    })

filter

过滤数组中的元素。为数组中的每个元素调用函数,函数返回真时保留,返回假时删除。

// 过滤数组中重复元素
arr.filter(function (element, index, self) {
   return self.indexOf(element) === index;
});

sort

排序,对于两个元素,如果 x<y,返回 -1,如果 x == y,返回0,如果 x>y,返回1

  • 默认排序是按元素的 ASCII 排序,如果是数字,先把数字转成字符
// 按数值大小排序
arr.sort(function (x, y) {
   if (x < y) {
       return -1;
  }
   if (x == y) {
       return 0;
  }
   if (x > y) {
       return 1;
  }
});
// 字符串不区分大小写排序
srr.sort(function (x, y) {
   x = x.toUpperCase();
   y = y.toUpperCase();
   if (x < y) {
       return -1;
  }
   if (x == y) {
       return 0;
  }
   if (x > y) {
       return 1;
  }
})

其它高阶函数

  • every,判断数组中的元素是否全部满足某一条件
  • find,返回符合条件的第一个元素,未找到返回 undefined
  • findIndex,返回符合条件的第一个元素的索引,未找到返回 -1
  • forEach,与 map 类似,但不会返回新的数组。一般用于遍历数组

闭包

函数作为返回值,返回的函数在其内部使用了局部变量

function lazy_sum(arr) {
   var sum = function () {
       return arr.reduce(function (x, y) {
           return x + y;
      });
  }
   return sum;
}

返回闭包不要引用循环变量,或者后续会发生变化的变量。这里 i 是 4

function count() {
   var arr = [];
   for (var i = 1; i <= 3; i++) {
       // 返回闭包不要引用循环变量,或者后续会发生变化的变量。这里 i 是 4
       arr.push(function () {
           return i * i;
      });
  }
   return arr;
}

如果需要使用循环变量,可以包裹一个立即执行的闭包

...
arr.push(function (n) {
   return function() {
       return n * n;
  };
}(i));
...

闭包实现私有变量

function create_counter(initial) {
   var x = initial || 0;
   return {
       inc: function () {
           x += 1;
           return x;
      }
  }
}

箭头函数

(…)=> {…}

  • 箭头函数中的 this 永远指向调用它的对象,所以使用箭头函数,不再需要用 that = this 保存 this 指向。

generator

generator 是 ES6 新出的数据结构,在函数中每次通过 yield 返回一个数,通过调用 next() 获取下一个值

function* next_id() {
   var current_id = 0;
   while (true) {
       current_id ++;
       yield current_id;
  }
}
// 一定要赋值
var next = next_id();
console.log(next.next());

可以使用 for … of 迭代 generator 结构数据