JavaScript 笔记02(js 循环 / 函数参数 / js 中复制值 / 检测类型 / 数组常用 api )

JavaScript 笔记02

接笔记01

5.for / forEach / for-in / for-of

不多 bb,直接看代码。

// 循环数组
let array = ['a', 'b', 'c'];
// 普通 for 循环
for (let index = 0; index < array.length; index++) {
    const element = array[index];
    console.log(element);
}
// forEach 循环
// 不能使用 break 语句中断循环,也不能使用 return 语句返回到外层函数
array.forEach(element => {
    console.log(element);
});
// for-in 循环
// 不推荐,因为这里的 index 不是数字,而是字符串,计算时用到很容易出错
// 遍历出来后的顺序也可能随机
for(const index in array) { 
    console.log(typeof index);
    console.log(array[index]);
}
// for-of 循环
// 这是最简洁、最直接的遍历数组元素的语法
// 这个方法避开了for-in循环的所有缺陷
// 与forEach()不同的是,它可以正确响应break、continue和return语句
for (const value of array) {
    console.log(value);
}

// 循环对象
let me = {
    name: 'ethan',
    sex: 'male',
    age: 24,
    hobby: 'skate'
};
// for-in 循环
for (const key in me) {
    // 先判断是否含有该属性
    if (me.hasOwnProperty(key)) {
        console.log(key+ ':' + me[key]);
    }
}
// for-of 循环,太麻烦,还不如 for-in
for (const key of Object.keys(me)) {
    console.log(key+ ':' + me[key]);
}

但是 for-of 除了可以遍历数组和对象,它还可以遍历 string 字符串,以及 ES6 新增的 Map、Set 集合。更详细的可以参考这篇文章。总结下,循环数组不需要 break 或者 return 推荐使用 forEach,需要的话使用 for-of,循环普通对象使用 for-in,剩下的都用 for-of,当然最重要的还是了解他们的异同,在使用的时候灵活选择。


6.关于函数参数

  1. js 中的函数不在乎参数的个数,也不在乎参数的类型
  2. js 中的参数其实是一个数组

关于上述两点,见如下代码

function abc (a, b) {
    console.log(arguments[0]);
    console.log(arguments.length);
}

abc(1);   // 1 1
abc(1,2); // 1 2
abc();    // undefined 0

再看下我们把函数的参数去掉

function abc () {
    console.log(arguments[0]);
    console.log(arguments.length);
}

abc(1);   // 1 1
abc(1,2); // 1 2
abc();    // undefined 0

结果是相同的。

可以利用 arguments 这个特性来写个不规定加数个数的加法

function add() {
    if(arguments.length === 0){
        return 0;
    } else {
        let total = 0;
        for(let i = 0; i < arguments.length; i++) {
            if (typeof arguments[i] === 'number') {
                total += arguments[i];
            }
        }
        return total;
    }
}

console.log(add(1, 3, 5.5, 7, 8, 'a', 10));

有一点需要注意,arguments 实际上不是 array 的实例,而是一个 array 对象。

function abc() {
    console.log(arguments);
    console.log(typeof arguments);
}

abc();    // {}  object
abc(1);   // { '0': 1 }  object
abc(1,2); // { '0': 1, '1': 2 }  object

7.基本类型和引用类型复制值时的区别

这点主要是用来理解引用类型的指针

  • 复制基本类型的值时会在变量对象上创建一个新值,然后把这个新值复制到新变量分配的位置上。
  • 复制引用类型的值时,复制的其实是一个指针,虽然指针不同,但指针指向的是同一个对象,所以当其中一个引用类型改变了对象,另一个引用类型上的值也会变化。
let num1 = 1;
let num2 = num1;
console.log(num2); // 1
num1 = 2;
console.log(num2); // 1 ,由此可见,改变 num1 并不会影响 num2 的值
let person1 = {
  name: 'ethan'
};
let person2 = person1;
console.log(person2.name);  // ethan
person1.name = 'ethan1';
console.log(person2.name); // ethan1,由此可见,改变 person1 会影响到 person2 的值,因为他们指向的是同一个对象。

8.检测类型

关于 typeof 在笔记1的第4点中已经写明,但 typeof 主要是用来检测基本数据类型,如果检测的值是一个对象或者 null,都会返回object,所以当变量是引用类型的时候,最好使用 instanceof,person instanceof RegExp,返回true/false。对于数组,还可以使用Array.isArray()


9.数组常用 API

方法 作用 返回值
push() 将任意数量的参数添加到数组末尾 修改后数组的长度
pop() 从数组末尾移除最后一项 移除的项
shift() 移除数组的第一项 移除的项
unshift() 将任意数量的参数添加到数字前端 修改后数组的长度
reverse() 反转数组项的顺序 反转后的数组
sort() 排序,默认的基本不用,需要重写 排序后的数组
concat() 基于当前数组创建一个新数组 新数组
splice() 删除:array.splice(0,2); 2个参数分别是要删除的第一项和要删除的项数 从原数组中删除的项组成的数组
插入:array.splice(2,0,"red","green");从第二项起删除0项,并插入 red 和 green。 从原数组中删除的项组成的数组
替换:array.splice(2,1,"red","green");参考上一条,很容易看懂 从原数组中删除的项组成的数组
indexOf() / lastIndexOf() 从数组开头/末尾开始查找位于第 n 位的项 查找的项
every() 对数组中的每一项运行给定函数 如果每一项都返回 true,则返回 true
filter() 对数组中的每一项运行给定函数 返回该数组中所有返回 true 的项组成的新数组
forEach() 对数组中的每一项运行给定函数 无返回值,该方法主要用来遍历数组
map() 对数组中的每一项运行给定函数 每次函数调用的结果组成的数组
some() 对数组中的每一项运行给定函数 只要有一项返回 true,则返回 true
reduce() /reduceRight() 归并方法,看下面的例子吧 看例子

重写 sort 方法

function compare (value1, value2) {
  if(value1 < value2) {
    return -1;
  } else if (value1 > value2) {
    return 1;
  } else {
    return 0;
  }
}

let values = [14,2,53,3,6,1];
values.sort(compare);
console.log(values);  // [ 1, 2, 3, 6, 14, 53 ]

迭代方法

let num = [1,2,3,4,5,4,3,2,1];

// every()
let everyResult = num.every((item, index, array) => {
  return (item > 2);
});
console.log(everyResult); // false

// filter()
let filterResult = num.filter((item, index, array) => {
  return (item > 2)
})
console.log(filterResult); // [ 3, 4, 5, 4, 3 ]

// forEach()
num.forEach(element => {
  console.log(element);  // 1  2  3  4  5  4  3  2  1
});

// map()
let mapResult = num.map((item, index, array) => {
  return (item*2);
})
console.log(mapResult);  // [ 2, 4, 6, 8, 10, 8, 6, 4, 2 ]

// some()
let someResult = num.some((item, index, array) => {
  return (item > 2);
})
console.log(someResult);  // ture

reduce()

let num = [1,2,3,4,5];
let sum = num.reduce((prev, cur, index, array) => {
  return prev+cur;
})
console.log(sum);  // 15

10.关于 callee(严格模式下会报错)

函数内部有两个特殊的对象:arguments 和 this。callee 就是 arguments 的一个属性。

首先看下非常经典的阶乘函数。

function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * factorial(num-1);
  }
}

console.log(factorial(5)); // 120

但这样有个问题,函数的执行和函数名factorial紧紧耦合在一起了,为了解决这个问题,我们就可以使用arguments.callee

function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * arguments.callee(num-1);
  }
}

console.log(factorial(5)); // 120

这样,即使改了函数名也不会有任何影响。注意与 caller 区分。


11.函数的 apply()、call() 和 bind()方法

  1. apply():接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。
function sum (num1, num2) {
  return num1 + num2;
}

function applySum1 (num1,num2,num3) {
  return sum.apply(this, [num1, num3]);
}

function applySum2 (num1,num2,num3) {
  return sum.apply(this, arguments);
}

console.log(applySum1(10,20,30)); // 40
console.log(applySum2(10,20,30)); // 30
  1. call():作用和apply()相同,不同的是第二个参数,不能以数组的形式,必须一个个列出来。
function sum (num1, num2) {
  return num1 + num2;
}

function callSum1 (num1,num2,num3) {
  return sum.call(this, num1, num3);
}

console.log(callSum1(10,20,30)); // 40

作用apply()call()最大的作用是能扩充函数赖以运行的作用域,如下:

window.color = 'red';
let o = {
  color: 'green'
};
function printColor () {
  return this.color;
}

console.log(printColor.call(window)); // red
console.log(printColor.call(this));   // red
console.log(printColor.call(o));      // green
  1. 这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind()函数的值,如下:
let color = 'red';
let o = {
  color: 'green'
};
function printColor () {
  console.log(this.color);
}

let objectPrintColor = printColor.bind(o);
objectPrintColor(); // green

12.具体位数的小数处理

自己工作中刚好遇到,要求是四舍五入取小数点后一位。我是这样写的:

s = Math.round(s * 10) / 10 + 'km';

今天一看书中有现成的方法toFix()

let s = 3.1415;
s1 = Math.round(s * 10) / 10;
console.log(s1);         // 3.1
console.log(typeof s1);  // number

s2 = s.toFixed(1);
console.log(s2);         // 3.1
console.log(typeof s2);  // string

似乎更简单,但数据类型已经改变了。所以书中也建议不要去实例化 Number 类型。当然,你看我工作中使用的场景,其实使用toFix()也不影响。


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

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,114评论 0 13
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,096评论 0 21
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,205评论 0 4
  •   引用类型的值(对象)是引用类型的一个实例。   在 ECMAscript 中,引用类型是一种数据结构,用于将数...
    霜天晓阅读 1,035评论 0 1
  • “他们都跑了,你也跟着跑啊。”李毓临瞟了一眼慕容冲,“现在不走,以后可没机会了。” “跑什么?左庶子是掌侍从的,”...
    朝笙浮塔阅读 343评论 0 0