三阶段课程Part1——Day03(函数扩展:箭头函数;类class;iterator迭代器)

1、函数扩展

  1.1、箭头函数基本用法

  主要用在回调函数中,如map、forEach等,一般不用在事件函数对象方法中。

  语法:箭头函数通过声明变量的形式去定义它(本质上是变量中存储了一个箭头函数)

let 变量名 = ( 参数 )=>{
    ......代码块
    return 返回值
}

 

  参数相关特性

  • 没有参数
  • 多个参数
  • 一个参数(有且只有一个参数,可以省略小括号)
  • 剩余参数(箭头函数没有arguments,只能使用rest接收剩余参数)
// 没有参数
let fn = () => {
    console.log('我是箭头函数,我执行了');
}
fn();

// 有多个参数
let fn1 = (a, b) => {
    return a + b;
}
console.log(fn1(3, 5));

// 有一个参数(有且只有一个参数,可以省略小括号)
let fn2 = a => {
    console.log('我有一个参数是:' + a);
}
fn2(3);

// 箭头函数中没有arguments
// 如果想获取所有的实参的集合,用rest参数
let fn3 = (...rest) => {
    // console.log(arguments); // arguments is not defined
    console.log(rest);
}
fn3(3, 4, 5);

 

  返回值的特性

  • 完整的写法:没有省略return关键字
  • 省略return:函数中只有一行代码,且可以省略return,同时大括号也需要省略
  • 返回对象的注意事项,需要用小括号括起来
let fn1 = () => {
    return 10;
}
console.log(fn1());


let fn2 = (a, b) => {
    return a + b;
}
console.log(fn2(3, 5));


// 箭头函数中只有一句代码且要返回这句代码,可以不写return,同时也不写大括号
// let fn3 = (a, b) => {
// return a + b;
// }
// console.log(fn3(4, 5));
let fn3 = (a, b) => a + b; console.log(fn3(4, 5)); let fn4 = a => a.repeat(3); console.log(fn4('小王')); // 返回的是对象,则要将这个对象用小括号括起来 let fn5 = () => ({ name: 'zs', age: 3 }) console.log(fn5());

 

  不作为构造函数

  无法使用new调用箭头函数,调用会报错

 

  函数参数默认值

// 如果没有传参,index为undefined,则使用默认值
// 如果传参,则用传入的参数
function indexOf(arr, val, index = 0) {
    for (var i = index; i < arr.length; i++) {
        if (arr[i] === val) {
            return i;
        }
    }
    return -1;
}

var arr = [3, 2, 3, 2, 32];
console.log(indexOf(arr, 3));
console.log(indexOf(arr, 3, 1));
console.log(indexOf(arr, 5));

 

  1.2、箭头函数中的this问题

  箭头函数没有this,箭头函数的this取决于它所处的上层环境是哪个对象,那么此this就指向这个对象。普通函数可以通过事件、apply或call等改变this指向,箭头函数无法通过上面方法修改this指向。

// 普通函数中的this:是在调用的时候确定的,不是在定义的时候确定的
// 箭头函数中的this:是在函数定义的时候确定的(函数所处的环境是谁,this指向谁),不是在调用的时候确定的
let fn = () => {
    console.log(this);
}

fn(); // window

document.onclick = fn; // window  事件调用不能改变箭头函数的this

fn.call(document); // window  call和apply也不能改变箭头函数中的this

 

  关于环境的补充

  只有script全局和函数内才能称为环境,对象的花括号不属于环境

let obj = {
    fn: function () {
        console.log(this);
    },
    fn1() {
        console.log(this);
    },
    fn2: () => {
        console.log(this);
    }
}

obj.fn(); // obj
obj.fn1(); // obj
obj.fn2(); // window  对象的方法中,一般不用箭头函数

 

  1.3、箭头函数的使用场景

  场景1:

let persons = [
    {
        username: '张飞',
        sex: '男',
        salary: 50000
    },
    {
        username: '关羽',
        sex: '男',
        salary: 60000
    }
]

// 完整写法
// let v = persons.map((item) => {
//     return {
//         ...item,
//         salary: item.salary + 2000
//     }
// });

// 简写
let v = persons.map((item) => ({ ...item, salary: item.salary + 2000 })
);

console.log(v);
console.log(persons);

 

  场景2:

var cartGoods = [
    {
        goodsname: '小米10',
        price: 5000,
        isChecked: true,//代表是否选中了
    },
    {
        goodsname: '苹果10',
        price: 3000,
        isChecked: false,//代表是否选中了
    }
]

// 完整写法
var a = cartGoods.every((item) => {
    return item.isChecked;
});

//简写
var a = cartGoods.every(item => item.isChecked);

console.log(a);

 

2、类class

  2.1、面向对象编程

    2.1.1、概念

    面向对象是一种以对象为中心的编程思想。面向对象是相对于面向过程来讲的,面向对象把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模。

 

    面向过程

    面向过程思想强调的是步骤,当碰见问题时,思考的是“我该怎么做”,分析出解决问题所需要的步骤,一步步的去实现。 例如:想吃蛋炒饭,首先想到的是我要如何做,包括哪些步骤。比如:起锅烧油,加入鸡蛋,加入米饭,加入调料,翻炒,装盘等。

 

    面向对象

    面向对象思想强调的是对象(是一个整体),当碰见问题时,思考的是“我该让谁来做”。这个“谁”其实就是对象。找合适的对象做合适的事情。而对象如何去做(采用什么样的步骤)我们就不关心了,最终把问题解决掉就可以了。

    例如:还是想吃蛋炒饭,首先想到的是让谁来帮我做蛋炒饭,比如找厨师来帮我做蛋炒饭。具体厨师如何去做这个蛋炒饭,做饭的步骤是怎么样的我们并不关心。只要最终把蛋炒饭做好就可以了。

 

    2.1.2、类和对象的关系

    现实中先有对象,根据不同的对象有着相似的特点(归为一类)

    程序中(先有类,使用类实例化对象),之前都是使用构造函数创建对象

    es5的构造函数有一些问题:方法必须加在原型上。使用function创建对象对于其它语言的工程师觉得很另类 。

 

  2.2、class的基本使用

    2.2.1、传统方式创建对象

// 创建对象的标准模式
// 构造函数 + 原型 = 混合模式
function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.showName = function () {
    console.log(this.name);
}
Person.prototype.showAge = function () {
    console.log(this.age);
}

let p1 = new Person('zs', 3);
console.log(p1);

 

    2.2.2、ES6创建类

class Person {
    constructor(name, age) { // 实例化的时候,此构造器函数自动调用
        this.name = name;
        this.age = age;
    }
    // 方法都是自动加到类的原型上
    showName() {
        console.log(this.name);
    }
    showAge() {
        console.log(this.age);
    }
}

let p1 = new Person('李四', 5);
// console.log(p1);
console.log(p1.name);
p1.showName();

 

  2.3、静态属性和静态方法

  实例属性和实例方法:通过实例调用的属性和方法。

  静态属性和方法:通过构造函数访问到的属性和方法。

// js中存在的静态方法
// Array.isArray() Array.of()  Array.from()
// Object.assign()  Object.keys()   Object.values()
class Person {
    // 静态的属性和方法
    static attr = '人类';
    static eat() {
        console.log('吃东西');
    }

    // 构造函数上的属性和方法
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    // 原型上的属性和方法
    showName() {
        console.log(this.name);
    }
    showAge() {
        console.log(this.age);
    }
}

let p1 = new Person('张三', 5);
console.log(p1);

// ---------------------
console.log(Person.attr);
Person.eat();

 

  2.4、继承

  class可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。

// 格式:class 子类 extends 父类 { }

// 父类
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    showName() {
        console.log(this.name);
    }
    showAge() {
        console.log(this.age);
    }
}

// 子类
class Student extends Person {
    constructor(name, age, sex) {
        super(name, age); // 写在constructor里面第一行,可以理解为把父类的constructor调用了
        this.sex = sex;
    }
    showSex() {
        console.log(this.sex);
    }
}

let s1 = new Student('张三', 3, '男');
console.log(s1);

 

  2.5、面向对象的应用场景

  对面向对象不要有负担,只要懂语法即可。我们更多的是使用面向对象思想封装的框架去写业务,而不是用面向对象思想封装框架。

    2.5.1、封装工具原理

class JS {
    constructor() {
        this.version = '1.0.1'
    }
    Array() {
        return {
            indexOf() { },
            slice() { }
        }
    }
    Object() {
        return {
            keys() { }
        }
    }
    DOM() {
        return {
            add() {
                console.log('我是添加方法');
            },
            delete() {
                console.log('我是删除方法');
            }
        }
    }
}

let js = new JS();
// console.log(js);

let dom = js.DOM();
// console.log(dom);
dom.add();
dom.delete();

 

3、iterator迭代器

  3.1、简介

  Iterator是一种接口机制,是为各种不同的数据结构提供统一的访问(循环)机制

  现在有Array / Object / Set / Map / String / NodeList / HTMLCollection / Arguments 等多种数据结构,每种都有对应的遍历方法,所以ES6 加入了Iterator遍历器,只要拥有这个Iterator遍历器,就都可以使用for...of进行遍历,这样统一方便。(但是对象没有遍历器)

 

  3.2、作用

  • 为各种数据结构,提供一个统一的、简便的访问接口
  • 使得数据结构的成员能够按某种次序排列
  • ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of使用
  • Iterator是一个抽象的概念, 具体的实现 for...of / Symbol.iterator

  只要可遍历的数据结构的原型上有 Symbol.iterator属性,则此数据就可以使用for...of进行遍历。唯独Object没有。

 

  3.3、for...of

  遍历数组、字符串、对象

// 以下数据类型能够被for-of循环,是因为它的原型上面都有Symbol.iterator

// 循环数组
var arr = [11, 22, 33];
// console.log(arr);
for (let value of arr) {
    console.log(value);
}

// 循环字符串
var str = 'abcd';
for (let value of str) {
    console.log(value);
}

// 循环set
let set = new Set(['aa', 'bb', 'cc']);
// console.log(set);
for (let val of set) {
    console.log(val);
}

// 循环map
let map = new Map([
    [true, 1],
    ['ab', 345],
    [null, 123]
])
for (let val of map) {
    console.log(val);
}

// 循环NodeList
let btn = document.getElementsByTagName('button');
for (let b of btn) {
    console.log(b);
}

 

  注意事项:在使用for...of遍历数据时, 要确保被遍历的数据, 拥有Iterator功能

  原生具备iterator接口的结构有:Array / Set / Map / String / NodeList / HTMLCollection / Arguments

 

  3.4、数组的Iterator

  数组的原型上有一个 Symbol.iterator属性,这个属性上存在一个方法

  分析:

    1、Symbol.iterator是个函数,这个函数执行完毕会返回一个指针对象

    2、指针对象有一个next方法,每调用一次next则返回一个值 { value:当前值, done:true/false }

let arr = [11, 22, 33];

// console.log(arr);
// console.log(arr[Symbol.iterator]); // 在数组的原型上有Symbol.iterator,它是一个函数,哪我们就可以调用它

let ab = arr[Symbol.iterator](); // 函数调用返回一个对象,这个对象下面有一个next()方法
console.log(ab.next()); // next方法调用一次,返回一个对象 {value: 11, done: false}
console.log(ab.next()); // {value: 22, done: false}
console.log(ab.next()); // {value: 33, done: false}
console.log(ab.next()); // {value: undefined, done: true}

// ------------------------------------
// 总结:Symbol.iterator在原型上,它是一个函数,这个函数被调用,会返回一个对象,这个对象的下面有next()方法,next()方法调用一次,就返回{value: 值, done: 是否到最后了}
// 不断的next就可以遍历这个数组

 

  3.5、为对象部署iterator接口

Object.prototype[Symbol.iterator] = function () {
    let keyArr = Object.keys(this);
    let valueArr = Object.values(this);
    let index = 0;

    return {
        next() {
            let arr = [keyArr[index], valueArr[index]];
            return {
                value: arr,
                done: index++ >= keyArr.length
            }
        }
    }
}


let obj = {
    name: 'zs',
    age: 3,
    sex: '男'
}
for (let val of obj) {
    console.log(val); // ["name", "zs"] ["age", 3] ["sex", "男"]
}

 

Part1重点:let、const、模板字符串、对象的简写、解构赋值、...运算符、箭头函数

上一篇:Day03_04 一些基础


下一篇:cgb2007-京淘day03