学习笔记

0129小结

Posted on 2022-01-29,10 min read

大纲

  • filter去重
  • filter筛选数组中素数
  • sort()函数复习
  • Array对象
  • 函数闭包
  • 箭头函数
  • generator对象
  • 正则表达与Date对象
  • Jason

filter去重

var r,
arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
r = arr.filter(function (element, index, self) {
    return self.indexOf(element) === index;});
//PS:element, index, self只是形式?不知道能不能换!

filter筛选素数

简单的方法可以考虑素数只有1和本身两个因数,麻烦的可以依据定义写函数

//获得素数函数,可以利用素数只有两个因数,下面的是麻烦的,从定义写的函数!
function get_primes(arr) {
    var brr = arr.filter(function(ss){ 
    var jsw = 0;
    if (ss == 1) {jsw =1}
    else {
    for (var i=2; i<ss; i++) {
    if( ss%i==0 ){
        jsw = jsw +1;
        break;}
    else{ continue; }
    }
} 
     return !jsw;
 });
return brr;
}
//依据因数是否只有2个
arr = arr.filter(function(element, index, self){
    var count = 0;//记录因数的数量
    for(var i=1;i<=element;i++){
       if(element%i===0){
          count++;
        }
    }
    if(element===1){
      return false;
    }
   return count<3;
});
console.log(arr)

sort函数

在3w网站学过,快速排序,按照-1,0,1的顺序,也可以排列有属性的对象

//数字小->大排序;
points.sort(function(a, b){return a - b}); 
//随机排序数组;
points.sort(function(a, b){return 0.5 - Math.random()});
//排序有属性数组,按照字母排序对象
cars.sort(function(a, b){return a.year - b.year});;
function myFunction() {
	var cars = [{type:"BMW", year:2017},{type:"Audi", year:2019},{type:"porsche", year:2018}];
  cars.sort(function(a, b){
    var x = a.type.toLowerCase();
    var y = b.type.toLowerCase();
    if (x < y) {return -1;}
    if (x > y) {return 1;}
    return 0;
  });
  displayCars();
}

Array

every

var arr = ['Apple', 'pear', 'orange'];
console.log(arr.every(function (s) {
    return s.length > 0;
})); // true, 因为每个元素都满足s.length>0

find
查找符合条件的第一个元素,如果找到了,返回这个元素;否则返回undefined

var arr = ['Apple', 'pear', 'orange'];
console.log(arr.find(function (s) {
    return s.toLowerCase() === s;
})); // 'pear', 因为pear全部是小写

findIndex
find类似,区别:findIndex()会返回这个元素的索引,如果没有找到,返回-1;
forEach
forEach()map()类似,但不会返回新数组;

函数闭包

把函数作为结果值返回,返回函数不要引用任何循环变量,或者后续会发生变化的变量:再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
  • 用了一个“创建一个匿名函数并立刻执行”的语法:
(function (x) {
    return x * x;
})(3); // 9
  • 只有函数的语言里,借助闭包,可以封装一个私有变量。我们用JavaScript创建一个计数器:
'use strict';
function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}
  • 使用:
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
  • 闭包可以把多参数的函数变成单参数的函数:
function make_pow(n) {
    return function (x) {
        return Math.pow(x, n);
    }
}

// 创建两个新函数:
var pow2 = make_pow(2);
var pow3 = make_pow(3);

console.log(pow2(5)); // 25
console.log(pow3(7)); // 343

箭头函数

this的指向与标准function不同,始终指向词法作用域(还是挺糊涂的,以后遇到实例再说吧);

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

箭头函数修复了this的指向

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

generator

generatorfunction*定义,可以用yield多次返回,也可以和函数一样用return返回一次。

function* fib2(max){
    var a=0, b=1, t;
    for (var i = 0; i<max; i++) { 
        t=a;  //也可以直接执行 yield a;
        [a,b]=[b,a+b];
        yield t;
    }
}
//generator的调用,有两种方式
for (var shc of fib2(5)){
    console.log(shc);
}
  • 也可以用next()调用;
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: false}
f.next(); // {value: undefined, done: true}

学了AJAX以后可以体会到generator更大的好处,目前只知道可以保存函数的中间状态;

RegExp相关

  • 基本知识
    \w可以匹配一个字母或数字,\d匹配一个数字;
    +表示至少一个字符:\s+表示至少有一个空格;
    *表示任意个字符,?表示0个或1个字符;
    \d{3,8}表示3-8个数字,如'1234567'等;
    匹配'010-12345'-是特殊字符,需要转义,所以号码的正则是\d{3}\-\d{3,8}
    [a-zA-Z\_\$][0-9a-zA-Z\_\$]*表示由字母或下划线、$开头,后接任意个由一个数字、字母或者下划线、$组成的字符串;
    A|B可以匹配A或B:(J|j)ava(S|s)cript
    ^表示行的开头,^\d必须以数字开头;
    $表示行的结束,\d$必须以数字结束:js也可以匹配jsp,但js$只能匹配js;
  • 创建正则表达式:
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');

re1; // /ABC\-001/
re2; // /ABC\-001/
  • 切分字符串
'a b   c'.split(' '); // ['a', 'b', '', '', 'c'];
'a b   c'.split(/\s+/); // ['a', 'b', 'c'];
'a,b, c  d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd'];
//至少一个[' '或','或';']
'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd'];
  • 分组
    除了匹配外,正则还可以提取字符串,()表示的就是要提取的分组;
//先匹配字符串
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null

exec()方法在匹配成功后,会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串;失败则会返回null

var re = /^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
re.exec('19:05:30'); // ['19:05:30', '19', '05', '30']

上述可以识别合法日期。
但是对于日期的识别可能会出问题:

var re = /^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$/;

对于'2-30''4-31'非法日期正则很难去识别,需要程序实现;

  • 贪婪匹配:正则默认贪婪匹配
var re = /^(\d+)(0*)$/;
re.exec('102300'); // ['102300', '102300', '']

导致0*无法匹配到字符串,可以加个来解决(尽可能少匹配):

var re = /^(\d+?)(0*)$/;
re.exec('102300'); // ['102300', '1023', '00']
  • 全局匹配
    g,表示全局匹配;i,表示忽略大小写;m,表示多行匹配。
var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');

全局匹配可以多次执行exec()方法来搜索一个匹配的字符串,指定g标志后,每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引:

var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到

全局匹配不能使用不能使用/^...$/

Jason学习

学习中看了篇评论区文章,箭头函数不乱用,箭头函数本身无this、arguments等属性,使用箭头函数一定要在外层套一层函数,使this在可见范围内,对象无法分割作用域(对象内的箭头函数无法确定this的指向),定义变量const>let>var尽量依次使用。

创建对象

通过函数创建对象,理解还较浅,注意prototype__proto__以及原型链

function Cat(name) {
    this.name = name;
}
Cat.prototype.say = function(){
    return 'Hello, ' + this.name + '!';
}

可以用一个createStudent来内部封装new

function Student(props) {
	this.name = props.name || '匿名';
	this.grade = props.grade || 1;
}

Student.prototype.hello = function () {
	alert('Hello, ' + this.name + '!');
}

function createStudent(props) {
	return new Student(props || {})
}

createStudent的参数非常灵活,可以不传也可以如下:

var xiaoming = createStudent({
	name: '小明'
});

xiaoming.grade; 

下一篇: 0128小结→

loading...