JavaScript基础部分总结

参考自: https://www.liaoxuefeng.com/wiki/1022910821149312/1023024358748480

个人简单总结, 加入自己理解


基础语法

字符串常用方法

  • toUpperCase()

  • toLowerCase()

  • indexOf()

  • substring()

    返回指定区间字符串, 一个参数表示结束位置, 两个参数第一个表示开始第二个表示结束

    var s = 'hello, world'
    s.substring(0, 5); // 从索引0开始到5(不包括5),返回'hello'
    s.substring(7); // 从索引7开始到结束,返回'world'
    

数组常用的方法

  • indexOf() 查找元素指定位置

  • slice() 它截取Array的部分元素,然后返回一个新的Array

    var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
    arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
    arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
    
  • sort排序 递增, 可以自定义

    arrInt = arrInt.sort(function (a, b) {
        return b - a; // 后面比前面大的时候就要交换, 也就是从 大  ==> 小
    })
    
  • reverse反转数组

  • splice()删除添加函数, 最厉害的, 三个参数(开始位置, 删除个数, 添加的值)

    其中添加的值可以有很多个

  • concat 数组拼接

    注意concat()方法并没有修改当前Array,而是返回了一个新的Array

    返回的数组是一维的

  • join 把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串

    返回的是连接后的字符串

  • pop和push

  • unshift和shift 是队列用的

    • unshift 队头添加
    • shift 队尾巴添加

对象的常用方法

  • 循环查看对象, 用for…in...

    var o = {
        name: 'Jack',
        age: 20,
        city: 'Beijing'
    };
    for (var key in o) {
        console.log(key); // 'name', 'age', 'city'
    }
    

    要过滤掉对象继承的属性,用hasOwnProperty()来实现:

     if (o.hasOwnProperty(key)) {}
    

    注意for ... inArray的循环得到的是String而不是Number

    var a = ['A', 'B', 'C'];
    for (var i in a) {
        console.log(i); // '0', '1', '2'
        console.log(a[i]); // 'A', 'B', 'C'
    }
    

    也即是下标是字符串

  • map: JavaScript的对象中, 键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型Map, 键可以是任意类型

    var m = new Map(); // 空Map
    m.set('Adam', 67); // 添加新的key-value
    m.set('Bob', 59);
    m.has('Adam'); // 是否存在key 'Adam': true
    m.get('Adam'); // 67
    m.delete('Adam'); // 删除key 'Adam'
    m.get('Adam'); // undefined
    
  • set: Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。需要提供一个Array作为输入,或者直接创建一个空Set

    SetArray类似,但Set没有索引

    var s1 = new Set(); // 空Set
    var s2 = new Set([1, 2, 3]); // 含1, 2, 3
    s.add(4);// Set {1, 2, 3, 4}
    s.add(4); // 仍然是 Set {1, 2, 3, 4}
    var s = new Set([1, 2, 3]);// Set {1, 2, 3}
    s.delete(3); // Set {1, 2}
    

iterable循环遍历数组, map和set

使用for ... of循环来遍历。for ... of循环是ES6引入的新的语法

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 ... in循环遍历的实际上是对象的属性名称

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
    console.log(x); // '0', '1', '2', 'name'
}

for ... of循环则完全修复了这些问题,它只循环集合本身的元素:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
    console.log(x); // 'A', 'B', 'C'
}

forEach

foEach没有返回值

SetArray类似,但Set没有索引,因此回调函数的前两个参数都是元素本身:

var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
    console.log(element);
});

Map的回调函数参数依次为valuekeymap本身:

var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
    console.log(value);
});

JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Arrayelement

var a = ['A', 'B', 'C'];
a.forEach(function (element) {
    console.log(element);
});

函数

函数参数arguments代表实际传入的参数, 可以当做一个数组来取用, 但是它不是数组

function abs() {
    if (arguments.length === 0) {
        return 0;
    }
    var x = arguments[0];
    return x >= 0 ? x : -x;
}

函数参数rest代表, 比如我写了两个参数, 但是传入进来了5个, 那么多出来的三个就是rest, 写法如下:

function foo(a, b, ...rest) {
    console.log(rest);
}

JavaScript的作用域是函数作用域, 也即是函数内部的变量不影响外部, 隔离开了

但是内部可以访问上级的变量. 冒泡向上找


变量提升

定义在函数内部的变量, 会被先提前声明到最顶部, 执行函数前会先扫描一遍函数内部


如果不写变量声明就会被绑定到全局作用域, 绑定到window下

foo = 'A`; // 没有写var或let就被当做是全局作用域下的属性

解构赋值

var x=1, y=2;
[x, y] = [y, x]

es6内部可以用解构赋值, 来进行多变量赋值

var person = {
    name: '小明',
    age: 20,
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zip: '100001'
    }
};
var {name, address: {city, zip}} = person;
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素

有些时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误:

// 声明变量:
var x, y;
// 解构赋值:
{x, y} = { name: '小明', x: 100, y: 200};
// 语法错误: Uncaught SyntaxError: Unexpected token =

这是因为JavaScript引擎把{开头的语句当作了块处理,于是=不再合法。解决方法是用小括号括起来:

({x, y} = { name: '小明', x: 100, y: 200});

apply和call

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
  • apply第二个参数是数组

    把参数打包成Array再传入对普通函数调用

    我们通常把this绑定为null

    JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。

    现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt()

    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
    
  • call()把参数按顺序传入

高阶函数

map/reduce

  • map映射

    image-20190529111656949
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
    arr.map((item)=>{
      return parseInt(item)
    });
    
  • reduce reduce()把结果继续和序列的下一个元素做累积计算

    var arr = [1, 3, 5, 7, 9];
    arr.reduce(function (x, y) {
        return x + y;
    }); // 25
    

filter

filter是用于过滤

var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
    return s && s.trim(); // 注意:IE9以下的版本没有trim()方法, 
  // trim()删除头尾空白字符, 这里删了就变空了就返回false
});
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;
});

sort

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return -1; // 表示x排在y左边
    }
    if (x > y) {
        return 1; // 表示x排在y右边
    }
    return 0; // 表示顺序不变
});
console.log(arr); // [1, 2, 10, 20]

Array本身有很多高阶函数

  • every() 判断所有元素是否符合测试条件, 接受一个参数, 是就返回true

    var arr = ['Apple', 'pear', 'orange'];
    console.log(arr.every(function (s) {
        return s.toLowerCase() === s;
    })); // false, 因为不是每个元素都全部是小写
    
  • find() 查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined

    var arr = ['Apple', 'pear', 'orange'];
    console.log(arr.find(function (s) {
        return s.toLowerCase() === s;
    })); // 'pear', 因为pear全部是小写
    
  • findIndex() 和find类似, 不过返回的是索引罢了

  • forEach()和map()类似, 但是不会返回数组, 常用于遍历数组
    参数为(值, 下标, 数组)


闭包

因为JavaScript是函数内作用域
利用这一点可以在函数内建立函数来进行
并且他的作用域是冒泡形式向上的

参考: https://segmentfault.com/a/1190000002778015

闭包的定义

  1. 可以访问外部函数作用域中变量的函数
  2. 被内部函数访问的外部函数的变量可以保存在外部函数作用域内而不被回收---这是核心,后面我们遇到闭包都要想到,我们要重点关注被闭包引用的这个变量。

闭包例子:

var person= function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();
console.log(person.name);//直接访问,结果为undefined    
console.log(person.getName());  //default 
person.setName("jozo");    
console.log(person.getName());  //jozo

闭包作用

  1. 可以读取外部函数的变量, 并且让这些 变量保持在内存中
    例如给每个li添加点击事件
 var oli = document.getElementsByTagName('li');
 var i;
 for(i = 0;i < 5;i++){
     oli[i].onclick = function(){
         alert(i);
     }
 }
 console.log(i); // 5

 //执行匿名函数
 (function(){
    alert(i);  //5
 }());

上面是一个经典的例子,是没有用到闭包, 我们都知道点击执行结果是都弹出5, 可以用闭包解决这个问题

a. 先来分析没用闭包前的情况:for循环中,我们给每个li点击事件绑定了一个匿名函数,匿名函数中返回了变量i的值,当循环结束后,变量i的值变为5,此时我们再去点击每个li,也就是执行相应的匿名函数(看上面的代码),这是变量i已经是5了,所以每个点击弹出5. 因为这里返回的每个匿名函数都是引用了同一个变量i,如果我们新建一个变量保存循环执行时当前的i的值,然后再让匿名函数应用这个变量,最后再返回这个匿名函数,这样就可以达到我们的目的了,这就是运用闭包来实现的!

b. 再来分析下运用闭包时的情况:

     var oli = document.getElementsByTagName('li');
     var i;
     for(i = 0;i < 5;i++){
         oli[i].onclick = (function(num){
             var a = num; // 为了说明问题
             return function(){
                 alert(a);
             }
         })(i)
     }
     console.log(i); // 5

这里for循环执行时,给点击事件绑定的匿名函数传递i后立即执行返回一个内部的匿名函数,因为参数是按值传递的,所以此时形参num保存的就是当前i的值,然后赋值给局部变量 a,然后这个内部的匿名函数一直保存着a的引用,也就是一直保存着当前i的值。 所以循环执行完毕后点击每个li,返回的匿名函数执行弹出各自保存的 a 的引用的值

  1. 可以避免命名重复全局污染问题, 也就是说命名可以和全局名字一样, 但是他们互不影响的

  2. 要访问函数内部变量就可以用闭包来实现

      function f1(){
        var n=999;
        function f2(){
          alert(n); // 999
        }
         return f2;
      }
    

缺点

闭包会常驻内存, 会增大内存使用, 使用不当就会有内存泄漏


generator生成器

就是使用yield可以类似中断一样, 通过调用下一步来运行

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}
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}

标准对象

data对象

JavaScript的Date对象月份值从0开始,牢记0=1月,1=2月,2=3月,……,11=12月

获取系统当前时间

var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

RegExp

正则匹配, 可以用new RegExp()创建正则

var re = /ABC\-001/;
var re = new RegExp('ABC\\-001');
re.test(字符);

切分字符串

'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

分组, 可以用exec()方法提取出子串

var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']

JSON

json字符串转为json对象

var obj = eval('('+str+')');
var obj = str.parseJSON();
var obj = JSON.parse(str);

json对象转为json字符串

var str = obj.toJSONString();
var str = JSON.stringify(obj);

面向对象编程

关于JavaScript继承可以看我的文章:

https://www.jianshu.com/p/70e86e2d2636

浏览器对象

window

window对象有innerWidthinnerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高。


navigator

  • navigator.appName:浏览器名称;
  • navigator.appVersion:浏览器版本;
  • navigator.language:浏览器设置的语言;
  • navigator.platform:操作系统类型;
  • navigator.userAgent:浏览器设定的User-Agent字符串。

screen

  • screen.width:屏幕宽度,以像素为单位;
  • screen.height:屏幕高度,以像素为单位;
  • screen.colorDepth:返回颜色位数,如8、16、24。

location

location.protocol; // 'http'
location.host; // 'www.example.com'
location.port; // '8080'
location.pathname; // '/path/index.html'
location.search; // '?a=1&b=2'
location.hash; // 'TOP'

DOM操作

常见的dom操作

添加节点

document.creatElement()

div.appendChild()

获取父元素

div.appendChild()

获取子元素

div.childNodes()

删除节点

div.removeChild()


promise

Promise().then().then....catch() 多任务串行执行.

Promise.all([p1,p2,...]) 多任务并行执行

都要成功才进入then,返回结果数组.

Promise.race([p1,p2,...]) 多任务赛跑.

then()和catch(),谁先调用算谁的,其它任务中断.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351