js

669 阅读24分钟

持续更新中... ...

数组合并

push apply

eg:

        let arr1 = [1,2,3];
        let arr2 = [4,5,6];
        arr1.push.apply(arr1, arr2);

结果:

image.png

push and flat

eg:

        let arr1 = [1,2,3];
        let arr2 = [4,5,6];
        arr1.push(arr2);
        let _arr1 = arr1.flat(Infinity);
        console.log(_arr1);

结果:

image.png

类型转换

split()

  • 字符串转数组 eg:
        // 字符串转数组
        text = "aa bb cc";
        console.log(text.split(/\s+/));

结果:

image.png

parseInt()

  • 转化为number类型 eg:
        // 强制转化为number类型
        var num = '546';
        console.log(parseInt(num));

结果:

image.png

toString()

  • 转化为字符串类型 eg:
        // 转化为字符串类型
        var num2 = 546;
        console.log(num2.toString());

结果:

image.png

flat(Infinity)函数

eg:

        //数组扁平化
        let ary = [1, [2, [3, [4, 5]]], 6];
        _ary = ary.flat(Infinity);
        console.log(_ary); // -> [1, 2, 3, 4, 5, 6]

结果:

image.png

replace()函数

eg:

        var arr7 = [6, 6, 7, 8, 8, 9];
        // 去除字符所有逗号
        function clear(str) {
            str = str.replace(/,/g, '');
            return str;
        }
        // 返回数字字符串
        text = arr7.toString();
        console.log(clear(text));

结果:

image.png

reverse函数

eg:

        // 反向排列
        const num = [2, 6, 3, 9, 7];
        console.log(num.reverse());

结果:

image.png

排序

  • -1和1决定升降排序 eg:
        // 升序排序
        function compare1(val1, val2) {
            if (val1 > val2) {
                return 1;
            } else if (val1 < val2) {
                return -1;
            } else {
                return 0;
            }
        }
        let value1 = [0, 1, 66, 10, 5];
        console.log(value1.sort(compare1));
        // 降序排序
        function compare2(val1, val2) {
            if (val1 > val2) {
                return -1;
            } else if (val1 < val2) {
                return 1;
            } else {
                return 0;
            }
        }
        let value2 = [0, 1, 66, 10, 5];
        console.log(value2.sort(compare2));
        // 冒泡排序
        let arr2 = [88, 23, 56, 44, 1, 8];
        for (let i = 1; i < arr2.length; i++) {
            for (let j = 0; j < arr2.length; j++) {
                if (arr2[j] > arr2[j + 1]) {
                    [arr2[j], arr2[j + 1]] = [arr2[j + 1], arr2[j]]
                }
            }
        }
        console.log(arr2);
        // 插入排序
        let arr3 = [88, 23, 56, 44, 1, 8];
        for (let i = 1; i < arr3.length; i++) {
            for (let j = i; j > 0; j--) {
                if (arr3[j - 1] > arr3[j]) {
                    [arr3[j - 1], arr3[j]] = [arr3[j], arr3[j - 1]]
                }
            }
        }
        console.log(arr3);
        
        // 对数字进行排序,简写
        const arr = [3, 2, 4, 1, 5]
        arr.sort((a, b) => a - b)
        console.log(arr) // [1, 2, 3, 4, 5]

        // 对字母进行排序,简写
        const arr = ['b', 'c', 'a', 'e', 'd']
        arr.sort()
        console.log(arr) // ['a', 'b', 'c', 'd', 'e']

结果:

image.png

image.png

includes函数

eg:

        //是否包含
        const arr = ['html', 'word', 'doxc'];
        const _arr = arr.includes('word'); //返回 true 和 false
        if (_arr) {
            console.log('存在');
        } else {
            console.log('不存在');
        }

结果:

image.png

unshift函数

eg:

        // 数组 追加全部到最前面的方法
        var arr1 = [{
            value: 0,
            label: '男'
        }, {
            value: 1,
            label: '女'
        }];
        var newArr = arr1.unshift({
            value: -1,
            label: '全部'
        })
       console.log(arr1); 

结果:

image.png

slice函数

eg:

        // 数组 截取第一个
        var arr1 = [{
            value: -1,
            label: '全部'
        }, {
            value: 0,
            label: '男'
        }, {
            value: 1,
            label: '女'
        }];
        var newArr = arr1.slice(1);
        console.log(newArr); 

结果:

image.png

map函数

eg:

        // 数组 遍历
        var arr1 = [{
            value: -1,
            label: '全部'
        }, {
            value: 0,
            label: '男'
        }, {
            value: 1,
            label: '女'
        }];
        var newArr = arr1.map(
            _item => _item.label
        );
        console.log(newArr);

结果:

image.png

filter函数

eg:

        // 数组 筛选
        var arr1 = [{
            value: -1,
            label: '全部'
        }, {
            value: 0,
            label: '男'
        }, {
            value: 1,
            label: '女'
        }];
        var newArr = arr1.filter(
            _item => _item.value !== -1
        );
        console.log(newArr);

结果:

image.png

find函数

eg:

        // 数组 匹配
        var arr1 = [{
            value: -1,
            label: '全部'
        }, {
            value: 0,
            label: '男'
        }, {
            value: 1,
            label: '女'
        }];
        var newArr = arr1.find(
            _item => _item.value === -1
        );
        console.log(newArr);

结果:

image.png

防抖

eg:

        // 防抖1
        let add = document.getElementById('btn');

        function fn() {
            console.log('ajax请求');
        }

        function debounce(fun, time) {
            let timer;
            return function() {
                if (timer) clearTimeout(timer)
                let args = arguments;
                timer = setTimeout(() => {
                    fun.apply(this, args);
                }, time)
            }
        }
        add.addEventListener('click', debounce(fn, 1000));
        //模拟实战防抖2 
        //vue利用loading加载数据模拟select输入调取更新列表数据
        //`filterable`属性即可启用搜索功能
        //`filter-method`为一个`Function`,它会在输入值发生变化时调用,参数为当前输入值。
        <el-select :remote-method="search_componey" @change="init_data(true)" v-model="value" filterable placeholder="请选择" :loading="loading"> 
        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> 
        </el-select>
        
        data数据:
        options:[],
        value: '',
        
        methods方法:
        init_data(){
            ...获取列表数据
        }
        
        search_componey(value){
            console.log(value); //输出搜索输入的内容
            if(value){
                const _params = {
                    要传的参数: value
                };
                this.loading = true;
                ...调取接口模糊查询数据
                this.loading = false;
                if(rest.code === 200){
                    this.options = 接口返回来的数据;
                }
            }
        }

结果防抖1:

image.png

拷贝

  • JSON.stringify():序列化对象,也可以过滤对象 eg:
        let book = {
            titile: '西游记',
            authors: [
                '吴承恩',
                '测试'
            ],
            edition: 4,
            year: 2017
        };
        let jsonText = JSON.stringify(book, ['titile', 'edition']);
        console.log(jsonText);
        console.log(jsonText.titile);
        let dee_copy = JSON.parse(jsonText);
        console.log(dee_copy.titile);

结果:

image.png

  • 浅复制:Object.assign(目标对象,源对象) eg:
        // 拷贝1 深拷贝
        function deep_copy(obj) {
            // 转化为对象格式
            return JSON.parse(JSON.stringify(obj));
        }
        const obj = {
            name: '测试',
            age: 21,
            data: 1999 + '-' + 09 + '-' + 18,
            sex: ''
        }
        new_Obj = deep_copy(obj);
        console.log(new_Obj);
        //拷贝2 浅拷贝
        const obj1 = {
            name: '测试',
            age: 21,
            data: 1999 + '-' + 09 + '-' + 18,
            sex: '男'
        };
        const copy = Object.assign(obj1, obj);
        console.log(copy); 

结果:

image.png

检测上传文件后缀是否正确

eg:

        // 检测上传文件后缀是否正确
        var text = '测试.word';
        text_ = text.lastIndexOf('.') + 1;
        const texts = text.substring(text_);
        console.log(texts); // word
        // text是否包含 word
        isWord = ['word'].includes(texts) ? true : false;
        console.log(aa); //true

结果:

image.png

数组去重

eg:

        // Set去重
        const arr = [1, 2, NaN, '1', , null, 1, 'a', 'b', 'a', NaN, undefined, null];
        const newArr2 = [...new Set(arr)];
        console.log(newArr2);
        
        // Array.from去重
        const newArr = Array.from(new Set(arr))
        
        // indexOf 去重
        function resetArr(arr) {
        let res = []
        arr.forEach(item => {
            if (res.indexOf(item) === -1) {
              res.push(item)
            }
        })
          return res
        }
        // 测试
        const arr = [1, 1, 2, 3, 3]
        console.log(resetArr(arr)) // [1, 2, 3]
        
        // 数组去重
        function unique(arr) {
            var res = arr.filter((item, index, array) => {
                // 通过获取下标和index比较,如果有重复的下标和index会不一致
                return array.indexOf(item) === index
            })
            return res
        }
        // 测试
        console.log(unique([1,'a',55,'a',2,'2',1])); 

结果:

image.png

栈pop和队列shift

eg:

        // 栈方法
        var arr = ['000'];
        var arrs = arr.push('aaa', 'bbb'); // 添加到数组后面
        item = arr.pop();
        console.log(item); //取最后一项 bbb
        // 队列方法 
        item = arr.shift();
        console.log(item); //取第一项 000
        arrs = arr.unshift('ccc', 'ddd'); // 添加到数组前面
        item = arr.pop();
        console.log(item); //取最后一项 aaa

结果:

image.png

splice函数

eg:

        // 删除arr数组中第一个aaa
        const arr = ['aaa', 'bbb', 'ccc'];
        _item = arr.splice(0, 1);
        console.log(arr);

结果:

image.png

push函数

eg:

        // 给数组新增ddd
        const arr = ['aaa', 'bbb', 'ccc'];
        _item = arr.push('ddd');
        console.log(arr);

结果:

image.png

join函数

eg:

        let arr = ['aa', 'bb', 'cc'];
        console.log(arr.join('|')); // aa|bb|cc
        console.log(arr.join(',')); // aa,bb,cc

结果:

image.png

变量作用域与内存

  • js原始值:Undefined null Boolean Number String Symbol bigint
  • js引用值:对象,储存在堆内存上
  • typeof用来判断一个变量是否为原始数组 注意:值是对象或null 返回 object
  • instanceof用来判断什么类型的对象和obj构造函数 是返回true 相反false
  • 重复声明var不会报错 重复声明let会抛出SyntaxError:已经声明过了
  • for循环中避免使用var声明应该使用let
  • 开发流程中应该尽可能多使用const声明 | 提升性能
  • js访问局部变量比访问全局变量要快
  • 在IE window.CollectGarbage()立即触发垃圾回收 Opera7及以上版本调用window.opera.collect
  • ES6中constlet声明提升性能同时有助于垃圾回收
  • 内存泄漏解决:在声明变量头上加var、let、const关键字

基本引用类型

  • toString:接收一个基数的参数并返回相应基数形式的数值字符串 eg:
        let num = 10;
        console.log(num, 'number类型');
        console.log(num.toString(), 'string类型');

结果:

image.png

  • toFixed: 返回包含指定小数点位数 eg:
        let num = 10;
        console.log(num.toFixed(2));

结果:

image.png

  • ES6新增isInteger()方法与安全整数(是不是整数且包含小数点10.00)

字符串函数

concat(): 用于将一个或多个字符串拼接成一个新的字符串

eg:

        let stringValue = "hello";
        let result = stringValue.concat(" world"); 
        console.log(result); //"hello word"

结果:

image.png

substr(): 用于将一个或多个字符串拼接成一个新的字符串

eg:

        let stringValue = "hello";
        let result = stringValue.substr(2);
        console.log(result); //"llo"

结果:

image.png

indexOf('要搜索的字符串'): 字符串位置 (要搜索的字符串第一次出现的位置)返回下标

lastIndexOf('要搜索的字符串'): 字符串位置 (要搜索的字符串最后一次出现的位置)返回下标

trim(): 删除前后出现的空格

repeat(): 将字符串复制多少次,然后返回拼接所有副本后的结果

eg:

        let stringValue = "2";
        let result = stringValue.repeat(2) + '00';
        console.log(result); //2200

结果:

image.png

toLocaleLowerCase()|toLocaleUpperCase(): 地区特定大小写转换前小后大

eg:

        let stringValue = "aS";
        let result1 = stringValue.toLocaleLowerCase(); //转换小写
        let result2 = stringValue.toLocaleUpperCase(); //转换大写
        console.log(result1); //as
        console.log(result2); //AS

结果:

image.png

集合引用类型

ES6新增创建数组的静态方法:from() 和 of()

  • form:将类数组结构转换为数组实例
  • of:将一组参数转换为数组实例 eg:
        const m = new Map().set(1, 2).set(3, 4);
        console.log(m);
        console.log(Array.from(m));
        const s = new Set().add(1).add(2).add(3);
        console.log(s);
        console.log(Array.from(s));
        // Array.from对现有数组执行浅复制
        const a1 = [1, 2, 3, 4];
        const a2 = Array.from(a1);
        console.log(a2); // [1, 2, 3, 4]

结果:

image.png

  • 实践中避免使用数组空位,确实要空位用undefined代替

isArray() 检测是否为数组

eg:

        // 检测数组
        const a1 = [1, 2, 3, 4];
        console.log(Array.isArray(a1));

结果:

image.png

ES6检索数组内容方法:keys(),values(),entries()

  • keys: 返回数组索引迭代器
  • values:返回数组元素迭代器
  • entries:返回索引/值对迭代器 eg:
        // 因为这些方法都返回迭代器
        // 所以将他们通过Array.from()转化为数组实例
        const a = ['a', 'b', 'c', 'd'];
        const aKeys = Array.from(a.keys());
        const aValues = Array.from(a.values());
        const aEntries = Array.from(a.entries());
        console.log(aKeys); //索引
        console.log(aValues); //值
        console.log(aEntries); //索引/值对
        // ES6的解构可以容易在循环中拆分键/值对
        for (const [idx, val] of a.entries()) {
            console.log(idx);
            console.log(val);
        }

结果:

image.png

fill()填充数组

eg:

         // 用5填充整个数组
        const _fill = [0, 0, 0, 0, 0];
        _fill.fill(5);
        console.log(_fill);
        _fill.fill(0); //重置
        // 用6填充索引大于等于3的元素
        _fill.fill(6, 3);
        console.log(_fill);
        _fill.fill(0); //重置
        // 用6填充索引大于等于1的元素且小于3的元素
        _fill.fill(7, 1, 3);
        console.log(_fill);

结果:

image.png

copyWithin()浅复制数组部分内容

  • 开始索引和结束索引与fill()使用同样的计算方法 eg:
        let ints,
            reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        reset();
        //从ints中复制索引0开始的内容,插入索引5开始的位置
        ints.copyWithin(5);
        console.log(ints);
        reset();
        //从ints中复制索引5开始的内容,插入索引0开始的位置
        ints.copyWithin(0, 5);
        console.log(ints);

结果:

image.png

toString(),valueOf()转换方法

  • toString:数组中有null,undefined会以空字符表示 eg:
        // 转换方法
        let colors = ['red', 'blue', 'green', null, undefined];
        console.log(colors.toString()); //red,blue,green, , 
        console.log(colors.valueOf()); //['red', 'blue', 'green']
        console.log(colors); //['red', 'blue', 'green']

结果:

image.png

对象、类与面编程向对象

创建Object新实例

eg:

        // 创建一个对象
        let person = new Object();
        person.name = "Marry";
        person.age = 23;
        person.sex = '女';
        person.sayName = function() {
            console.log(this.name);
        }
        let person1 = {
            name: "Jack",
            age: 24,
            sex: '男',
            sayName() {
                console.log(this.name);
            }
        }

类的属性

  • 修改属性的默认特性必须使用:Object.defineProperty()

数据属性

  • Configurable: 表示属性是否可以通过delete删除并重新定义 默认为true
  • Enumerable:表示属性是否可以通过for~in循环返回 默认为true
  • Writable:表示属性是否可以被修改 默认为true
  • Value:包含属性实际的值 默认为undefined eg:
        // writable = false不能修改 
        let person = {};
        Object.defineProperty(person, "name", {
            writable: false,
            value: "Mary"
        });
        console.log(person.name); //Mary
        person.name = 'Jack'; //不能修改 不会报错 原因writable = false 
        console.log(person.name); //Mary

结果:

image.png

访问器属性

  • Configurable: 表示属性是否可以通过delete删除并重新定义 默认为true
  • Enumerable:表示属性是否可以通过for~in循环返回 默认为true
  • Get:获取函数,在读取属性时调用 默认为undefined
  • Set:设置函数,在写入属性时调用 默认为undefined eg:
        let book = {
            year_: 2017,
            edition: 1
        };
        Object.defineProperty(book, "year", {
            get() {
                return this.year_;
            },
            set(newVal) {
                if (newVal > 2017) {
                    this.year_ = newVal;
                    this.edition += newVal - 2017
                }
            }
        })
        book.year = 2018; //修改属性值
        console.log(book.edition); //set计算出来的值 2

结果:

image.png

定义多个属性

  • 一个对象同时定义多个属性:Object.defineProperties() eg:
        let book = {};
        Object.defineProperties(book, {
            year_: {
                value: 2017
            },
            edition: {
                value: 1
            },
            year: {
                get() {
                    return this.year_;
                },
                set(newVal) {
                    if (newVal > 2017) {
                        this.year_ = newVal;
                        this.edition += newVal - 2017
                    }
                }
            }
        })
        book.year = 2018; //不能修改属性值 2017
        console.log(book.edition); //不能修改 1

结果:

image.png

合并对象

  • 浅复制:Object.assign() 用于后台管理系统取消操作逻辑 eg:
        let dest, src, result;
        // 简单复制
        dest = {};
        src = {
            id: 'src'
        };
        result = Object.assign(dest, src);
        console.log(dest === result); // true
        console.log(src);
        console.log(result);
        // 多个源对象
        dest = {};
        result = Object.assign(dest, {
            a: 'foo'
        }, {
            b: 'bar'
        })
        console.log(result);

结果:

image.png

对象标识及相等判定

  • ES新增:Objec.is()与===很像,必须接收两个参数 eg:
        console.log(Object.is(NaN, NaN));

结果:

image.png

增强对象语法

属性值简写

eg:

        let name = 'Mark';
        let persons = {
            name
        }
        console.log(persons);

结果:

image.png

可计算属性

eg:

        const nameKey = 'name';
        const ageKey = 'age';
        let person = {};
        person[nameKey] = 'Mary';
        person[ageKey] = 21;
        console.log(person);

结果:

image.png

简写方法名

  • 简写方法名比ES6的类更有用 eg:
        const methodKey = 'sayName';
        let person = {
            [methodKey](name) {
                console.log(`My name is ${name}`);
            }
        }
        person.sayName('Mary');

结果:

image.png

对象解构

eg:

        let person = {
            name: 'Mary',
            age: 27
        };
        let {
            name,
            age
        } = person;
        console.log(name); //Mary
        console.log(age); //27

结果:

image.png

原型模式

  • 解决了公共的方法:prototype共享的属性和方法
  • 判断属性是否来自原型链:hasOwnProperty()
  • 判断属性是一个原型属性:in操作符返回truehasOwnProperty()返回false eg:
        function Person() {};
        Person.prototype.name = 'Mary';
        Person.prototype.age = 18;
        Person.sayName = function() {
            console.log(this.name);
        }
        let person1 = new Person();
        let person2 = new Person();
        person1.name = 'Jack';
        console.log(person1.name); //来自实例
        console.log(person1.hasOwnProperty("name"));
        console.log("name" in person1);
        console.log(person2.name); //来自原型链
        console.log(person2.hasOwnProperty("name"));
        console.log("name" in person2);
        delete person1.name; //删除实例name
        console.log(person1.name); //来自原型链
        console.log(person1.hasOwnProperty("name"));
        console.log("name" in person1);

结果:

image.png

对象迭代

  • 返回对象值的数组:Object.values()
  • 返回对象键/值对的数组:Object.entries() eg:
        const o = {
            name: 'aa',
            age: 17,
            sex: '男'
        };
        console.log(Object.values(o));
        console.log(Object.entries(o));

结果:

image.png

代理与反射

  • 为开发者提供了拦截并向基本操作嵌入额外行为的能力.可以给目标对象定义一个关联的代理对象,可以作为抽象的目标对象来使用,在对目标对象的各种操作影响目标对象之前,可以在代理对象中的对这些操作加以控制
  • 在实际开发中经常会遇到js抛出的错误,但是我们有没有想过自己去接管js异常验证,根据自己的需求抛出异常呢?原本也许不行,但是在es6出来后就可以做到了

创建空代理

  • 代理是使用Proxy构造函数创建的接收两个参数:目标对象和处理程序对象 eg:
        const target = {
            id: 'target'
        };
        const handler = {};
        const proxy = new Proxy(target, handler);
        // id属性会访问同一个值
        console.log(target.id);
        console.log(proxy.id);
        // 给目标属性赋值会反映在两个对象上
        // 因为两个对象访问的是同一个值
        target.id = 'foo';
        console.log(target.id);
        console.log(proxy.id);
        // 给代理属性赋值会反映在两个对象上
        // 因为这个赋值会转移到目标对象
        proxy.id = 'bar';
        console.log(target.id);
        console.log(proxy.id);
        // hasOwnProperty()方法在两个地方
        // 都会应用到目标对象
        console.log(target.hasOwnProperty('id'));
        console.log(proxy.hasOwnProperty('id'));

结果:

image.png

使用场景

  • MVVM的数据双绑
  • 这个时候当array数组元素改变的时候,会调用对应的回调。
  • target:目标对象
  • propertyKey:引用的目标对象上的字符串属性
  • value:要赋给属性的值
  • receiver:代理对象或继承代理的对象 eg:
        function observedArray(cb) {
            const array = [];
            return new Proxy(array, {
                set(target, propertyKey, value, receiver) {
                    cb(propertyKey, value);
                    return Reflect.set(target, propertyKey, value, receiver);
                }
            });
        }
        const array = observedArray((key, value) => console.log(`${key}: ${value}`));
        array.push('a');
        array.push('b');
        array.push('c');

结果:

image.png

函数

箭头函数

  • 箭头函数不能使用argments,也不能用作构造函数,也没有prototype属性 eg:
        let num = () => {
            console.log(arguments[0]);
        }
        num('han');

结果:

image.png

  • argments:相当于函数里面的参数 eg:
        function sayHi() {
            console.log(arguments[0]); //han
            console.log(arguments[1]); //aaa
            console.log(arguments[2]); //bbb
        }
        sayHi('han', 'aaa', 'bbb');

结果:

image.png

参数扩展

  • apply:给函数传参
  • ES6扩展操作符...:给函数传参 eg:
        let values = [1, 2, 3, 4, 5];
        function getSum() {
            let sum = 0;
            for (let i = 0; i < arguments.length; i++) {
                sum += arguments[i];
            }
            return sum;
        }
        console.log(getSum.apply(this, values)); //apply传参
        console.log(getSum(...values)); //ES6扩展运算符传参

结果:

image.png

函数内部 argumentsthis

  • arguments.callee:让函数逻辑与函数名解耦 避免递归函数出错 eg:
        function text(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * arguments.callee(num - 1); //避免递归函数出错
            }
        }
        console.log(text(5)); //120
        let _text = text; //将text赋给_text 这时指针改变方向指向_text
        text = function() {
            return 0;
        }
        console.log(_text(5)); //text指针指向_text 输出120
        console.log(text(5)); // 0

结果:

image.png

  • this:特殊的对象 eg:
        window.color = 'red';
        let o = {
            color: 'blue'
        };
        function sayColor() {
            console.log(this.color);
        }
        //结果1
        sayColor(); //red
        o.sayColor = sayColor;
        o.sayColor(); //blue this指向o 
        //结果2 箭头函数
        // let sayColor = () => console.log(this.color); //箭头函数是在window上下文定义的
        // sayColor(); //red
        // o.sayColor = sayColor;
        // o.sayColor(); //red

结果1:

image.png 结果2:

image.png

  • 解决在事件或定时回调中调用某函数:this指向的并非想要的对象。此时将回调函数写成箭头函数可以解决问题 eg:
        function King() {
            this.sayName = 'Mary';
            // this引用King的实例
            setTimeout(() => {
                console.log(this.sayName);
            }, 1000);
        };

        function Queen() {
            this.sayName = 'Jack';
            // this引用window对象
            setTimeout(function() {
                console.log(this.sayName);
            }, 1000);
        }

        new King();
        new Queen();

结果:

image.png

函数属性与方法

  • call(),apply()作用一样,只是传参形式不同
  • 如何用取决于传参更方便:直接传arguments 对象或者数组apply()否则call()
  • apply 接收的是一个包含多个参数的数组, 而 call 方法接收的是若干个参数列表。 bind 接收的是若干个参数列表,但必须要调用一次 eg:
        function sum(num1, num2) {
            return num1 + num2;
        }

        function callSum(num1, num2) {
            return sum.call(this, num1, num2);
        }
        console.log(callSum(10, 10));

        function callSum1(num1, num2) {
            return sum.apply(this, arguments);
        }
        console.log(callSum1(10, 10));

        function callSum2(num1, num2) {
            return sum.apply(this, [num1, num2]); //传入数组
        }
        console.log(callSum2(10, 10));

结果:

image.png

  • call()和apply()最强大地方:控制函数调用上下文函数体内this值的能力
  • 好处:可以将任意对象设置为任意函数的作用域
  • ES5bind():创建一个新函数实例,this值会被绑定到传给bind()的对象 eg:
        window.color = 'red';
        let o = {
            color: 'blue'
        };

        function sayColor() {
            console.log(this.color);
        }
        sayColor(); //red
        sayColor.call(this); //red
        sayColor.call(window); //red
        sayColor.call(o); //blue
        sayColor.apply(this); //red
        sayColor.apply(window); //red
        sayColor.apply(o); //blue
        let objSayColor = sayColor.bind(o);
        objSayColor(); //blue

结果:

image.png

函数表达式

  • 函数声明和函数表达式之间的区别,关键是理解提升 eg:
        let isEdit = false;
        // 千万别这样做
        if (isEdit) {
            function sayHi() {
                console.log('Hi!');
            }
        } else {
            function sayHi() {
                console.log('Yo!');
            }
        }
        let sayHi;
        // 没问题
        if (isEdit) {
            sayHi = function() {
                console.log('Hi!');
            }
        } else {
            sayHi = function() {
                console.log('Yo!');
            }
        }
        sayHi();

结果:

image.png

递归函数

  • 通常形式是一个函数通过名称调用自己 eg:
        function factorial(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * factorial(num - 1);
            }
        }
        let _factorial = factorial;
        factorial = null;
        console.log(_factorial(4));

结果:

image.png

  • 为了上面递归出错:写递归函数时使用arguments.callee可以避免上面的问题
  • arguments.callee:在严格模式下不能访问arguments.callee eg:
        function factorial(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * arguments.callee(num - 1);
            }
        }
        let _factorial = factorial;
        factorial = null;
        console.log(_factorial(4)); //24

结果:

image.png

  • arguments.callee:用匿名函数代替
  • 解决在严格模式下访问arguments.callee出错 eg:
        const factorial = (function f(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * f(num - 1); //用匿名函数代替
            }
        });
        console.log(factorial(4)); //24

结果:

image.png

尾调用优化

  • 以递归为例 eg:
        function fib(n) {
            if (n < 2) {
                return n;
            }
            return fib(n - 1) + fib(n - 2)
        }
        console.log(fib(6)); //8

结果:

image.png

  • 优化递归 eg:
        // 基础框架
        function fib(n) {
            return fibImpl(0, 1, n);
        }
        // 执行递归
        function fibImpl(a, b, n) {
            if (n === 0) {
                return a;
            }
            return fibImpl(b, a + b, n - 1)
        }
        console.log(fib(6)); //8

结果:

image.png

回调函数

  • 把一个函数的定义当作参数传递给另一个函数 eg:
        function eat(food, callback) {
            callback(food);
        }
        eat('水果捞', function(food) {
            console.log(`拿着${food}放着糖吃`);
        })

结果:

image.png

闭包

  • 好处:局部变量不随着原函数的销毁而销毁
  • 闭包是指那些引用了另一个函数作用域中变量的函数,通常是在嵌套中实现的
  • 函数执行完毕不会释放变量,仍在闭包函数中保存,等待下一次使用 eg:
        function createCounter() {
            let counter = 0;
            const myFunction = function() {
                counter = counter + 1;
                return counter;
            }
            return myFunction;
        }
        const increment = createCounter()
        const c1 = increment(); //1
        const c2 = increment(); //2
        const c3 = increment(); //3
        console.log(c1, c2, c3); //1,2,3
     
        // ES6形式闭包
        let c = 4
        const addX = x => n => n + x
        const addThree = addX(3);
        let d = addThree(c);
        console.log(d);
        // 常规
        let c = 4
        function addX(x) {
            return function(n) {
                return n + x
            }
        }
        const addThree = addX(3)
        let d = addThree(c)
        console.log(d)
        
        // 闭包
        function text() {
            var a = 0;
            return function(num) {
                a += num;
                console.log(a);
            }
        }
        var inner = text();
        inner(1);
        inner(1);
        inner(1);
        // 自执行函数
        var inners = (function() {
            var a = 0;
            return function(num) {
                a += num;
                console.log(a);
            }
        })();
        inners(2);
        inners(2);
        inners(2);

结果:

image.png

image.png

期约和异步函数

异步编程

  • 异步行为是为了优化因计算量大而时间长的操作。
  • 在等待其他操作完成的同时,即使运行其他指令,系统也能保存稳定。
  • 异步操作不一定要计算量大或者时间长,不想为等待某个操作而阻塞线程执行,那么任何时候都可以使用。

同步与异步

  • 同步行为对应内存中顺序执行的处理器指令。
  • 异步行为类似于系统中断,即当前进程外部的实体可以出发代码执行。
  • 异步操作是必要的,因为强制等待一个长时间操作不可行。

以往的异步编程模式

  • 以往只支持定义回调函数表明异步操作完成。
  • 需要深度嵌套回调函数,因此产生「回调地狱

嵌套异步函数

  • 噩梦一般的 嵌套😈

期约

期约基础

  • 引用类型Promise,可以用new操作符来实例化
  • 创建时需要传入执行器函数作为参数

期约状态机

  • 三种状态

    • 待定(pending)

      • 最初始状态,待定状态下可以落定(settled)为代表成功兑现状态,或者失败的拒绝状态
      • 状态修改不可逆
      • 不能保证期约必然会脱离待定状态
    • 兑现(fulfilled,有时也称解决,resolved)

    • 拒绝(rejected)

  • 期约的状态是私有的,不能外部检测到,为了避免读取到期约状态,用同步的方式处理期约对象。

  • 期约的状态是不能被外部修改。

Promise.resolve

  • 通过调用Promise.resolve()静态方法,可以实例化一个解决的期约 eg:
        // p1 和 p2实际上一样
        let p1 = new Promise((resolve, reject) => resolve());
        let p2 = Promise.resolve();
        setTimeout(console.log, 0, Promise.resolve()); //undefind
        setTimeout(console.log, 0, Promise.resolve(3)); //3
        // 多余的参数忽略
        setTimeout(console.log, 0, Promise.resolve(4, 5, 6)); //4

结果:

image.png

Promise.reject

  • 与Promise.resolve()类似。Promise.reject()会实例化一个拒绝的期约并抛出一个异步错误(这个错误不能通过try/cat捕获,只能通过拒绝处理程序捕获) eg:
        // p1 和 p2实际上一样
        let p1 = new Promise((resolve, reject) => reject());
        let p2 = Promise.reject();

        let p = Promise.reject(3);
        setTimeout(console.log, 0, p); // 3
        p.then(null, (e) => setTimeout(console.log, 0, e)); //3
        setTimeout(console.log, 0, Promise.reject(Promise.resolve()));

结果:

image.png

同步/异步执行的二元性

eg:

        try {
            throw new Error('foo');
        } catch (e) {
            console.log(e);
        }
        try {
            Promise.reject(new Error('bar'));
        } catch (e) {
            console.log(e);
        }

结果:

image.png

Promise.prototype.then()

  • 为期约实例添加处理程序的主要方法
  • then() 方法
    • 最多接收两个参数 onResolved和onRejected处理程序
    • 都是可选的,如果提供的话则会在期约分别进入"兑现"和“拒绝”状态时执行。
    • 如果想提供onRejected参数,就要在onResolved参数位置传入undefind,有助于避免在内存中创建多余对象

Promise.prototype.catch()

  • 用于给期约添加拒绝处理程序,直接收一个参数onRejected处理程序。
  • 语法糖,相当于调用Promise.prototype.then(null, onRejected)

异步函数

async

  • async 关键词用于声明异步函数,可用在函数声明、函数表达式、箭头函数
  • 使用async可让函数具有异步特征,但总体上仍然是同步求值的
  • 使用async关键字可以让函数具有异步特征,在实际中它需要和await配合使用。

await

  • 一旦定义了一个函数作为一个异步函数,我们就可以使用 await 关键词。这个关键词放在回调的Promise之前,将会暂停执行函数,直到Promise执行或拒绝。
  • await 关键字会暂停执行异步函数后面的代码,它这个行为和生成器函数中的yield关键字是一样的,await关键字也是解包对象的值,任何将这个值传给表达式,再用异步恢复异步执行的操作。
  • 异步函数里不包含await关键字,和普通函数没区别

await的限制

  • 必须在异步函数中使用,不能在顶级上下文使用。
  • 可以定义并立即调用
  • 异步函数特质不会扩展到潜逃函数,await只能直接出现在异步函数的定义中

综合

eg:

        function doubleAfter2seconds(num) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(2 * num)
                }, 2000);
            } )
        }
        async function testResult() {
            let result = await doubleAfter2seconds(30);
            console.log(result);
        }
        testResult();

结果:

image.png

BOM

  • BOM的核心 ----- window对象
  • 通过location对象获取页面信息
  • 使用navigator对象了解浏览器
  • 通过history对象操作浏览器历史

window对象

  • window对象在浏览器中身份
    • ECMAScript中的Global对象
    • 浏览器窗口的JavaScript接口

Clobal作用域

  • 通过var声明的所有全局变量和函数都会变成window对象的属性和方法 eg:
        var age = 29;
        console.log(window.age);

结果:

image.png

  • 使用let或const替代var,这不会把变量添加到全局对象

窗口关系

  • top对象始终指向最上层,即浏览器窗口本身
  • parent对象则始终指向当前窗口的父窗口
    • 如果当前窗口是最上层窗口,则parent等于top
    • 最上层window如果不是通过window.open()打开的,那么其name属性不会包含值
  • self对象是始终window属性会始终指向window

窗口位置和像素比

  • screenLeft 和 screenTop属性,表示窗口相对于屏幕左侧和顶部的位置
  • moveTo和moveBy方法移动窗口 eg:
        // 把窗口移动到左上角
        window.moveTo(0,0);
        // 把窗口向下移动100像素
        window.moveBy(0,100);

窗口大小

  • 返回浏览器窗口中页面视口的大小:innerWidth innerHeigth
  • 返回浏览器窗口自身的大小:outerHeigth outerWidth
    • resizeTo() resizeBy() 调整窗口大小
      • resizeTo()接收新的宽度和高度值
      • resizeBy()接收宽度和高度各要缩放多少 eg:
        // 返回页面视口的宽度和高度
        var a = document.documentElement.clientWidth;
        console.log(a);
        var b = document.documentElement.clientHeight;
        console.log(b);

结果:

image.png

视口位置

  • scroll() scrollTo() scrollBy() 方法滚动页面 eg:
        // 相当于当前视口向下滚动100像素
        window.scrollBy(0,100);

导航与打开新窗口

  • window.open():导航到指定URL
        window.open('http://www.baidu.com');

定时器

  • setTimeout():指定在一定时间后执行某代码
  • clearTimeout():取消等待中的排期任务 eg:
        setTimeout(() => {
            console.log('你好我的电脑');
        }, 1000);

结果:

image.png

  • setInterval():指定每隔一段时间执行某代码 eg:
        setInterval(() => {
            console.log('你好我的电脑');
        }, 1000);

结果:

image.png

系统对话框

  • alter():警告框
  • confirm():确认框
  • prompt():提示框

location对象

  • 修改hash的值会在浏览器历史记录增加一条新纪录
  • 最好把reload()作为最后一行代码 eg:
        // 假设当前URL为http://www.wrox.com/WileyCDA/
        // 把URL修改为http://www.wrox.com/WileyCDA/#section1
        location.hash = "#section1"; 
        // 把URL修改为http://www.wrox.com/WileyCDA/?q=javascript
        location.search = "?q=javascript";
        // 把URL修改为http://www.somewhere.com/WileyCDA/
        location.hostname = "www.somewhere.com" 
        // 把URL修改为http://www.somewhere.com/mydir/
        location.pathname = "mydir" 
        // http://www.somewhere.com:8080/WileyCDA/
        location.port = 8080; 
        // 重定向之后不能回到前一页
        location.replace("http://www.wrox.com/");
        // 重新加载 可能是从缓存加载
        location.reload();
        // 重新加载 从服务器加载
        location.reload(true);

navigator对象

  • 通常用于确定浏览器的类型

history对象

  • 表示当前窗口首次使用以来用户的导航历史记录

导航

  • history.go(-1) = history.back():后退一页
  • history.go(1) = history.forward():前进一页
  • history.go(2):前进两页

DOM

节点层级

  • doucument节点表示每个文档的根节点
  • 文档元素:根节点的唯一子节点是<html>元素

Node类型

  • 每个节点都有nodeType属性,表示该节点类型

nodeName与nodeValue

  • nodeName与nodeValue保存着有关节点的信息
    • 值取决于节点类型

节点关系

  • 每个节点都有一个childNodes属性
    • 如果childNodes中只有一个节点:它的previousSibling和nextSibling属性都是null
    • 父节点和它的第一个及最后一个字节点都有专门属性:firstChild和lastChild分别指向childNodes中的第一个和最后一个字节点

操作节点

  • 最常用的方法是appendChild():用于在childNodes列表末尾添加节点,返回新添加的节点
  • insertBefore():把节点放到childNodes特定位置而不是末尾。
    • appendChild()和insertBefore()在插入节点时不会删除任何已有节点
  • replaceChild()接收2参数:要插入的节点和要替换的节点
  • removeChild():移除节点

Document类型

  • 用于获取关于页面的信息及操作其外观和底层结构

定位元素

  • getElementByid():要获取元素的ID eg:
        <div id="div">测试</div>
        let div = document.getElementById('div');
        console.log(div);

结果:

image.png

  • getElementsByTagName():获取元素引用的方法
    eg:
        <img src="aaaa.html" alt="">
        <img src="v-bind.html" alt="">
        <img src="v-for.html alt="">
        let imgs = document.getElementsByTagName("img");
        console.log(imgs,length); // 3
        console.log(imgs[1].src);

结果:

image.png

  • getElementsByName():获取给定name属性的所有元素
    eg:
        <input type="radio" value="red" name="color" id="colorRed">
        <input type="radio" value="blue" name="color" id="colorBlue">
        <input type="radio" value="green" name="color" id="colorGreen">
        let radios = document.getElementsByName('color');
        console.log(radios);

结果:

image.png

特殊集合

  • document.anchors():包含文档所有带name属性的<a>元素
  • document.forms():包含文档所有<form>元素
  • document.images():包含文档所有<img>元素
  • document.links():包含文档所有带href属性的<a>元素

文档写入

  • document.write():向文档中输出内容

Element类型

  • 表示XML或HTML元素

DOM扩展

Selectors API

  • 核心方法:querySelector()querySelectorAll()

querySelector()

  • 接收css选择符参数,返回匹配该模式的第一个后代元素,没有匹配返回null eg:
        <div>测试1</div>
        <div>测试2</div>
        <div>测试3</div>
        let div1 = document.querySelector("div");
        console.log(div1);
        let div2 = document.querySelector('#div');
        console.log(div2);
        let div3 = document.querySelector('.div');
        console.log(div3);

结果:

image.png

querySelectorAll()

  • 返回所有匹配节点,返回的是一个NodeList实例
  • 避免了使用NodeList对象可能造成的性能问题 eg:
        <div id="myDiv">
        <em>测试1</em>
        <em>测试2</em>
        <em>测试3</em>
        </div>
    <script>
        // 取得ID为"myDiv"的<div>元素中的所有<em>元素
        let ems = document.getElementById('myDiv').querySelectorAll('em');
        console.log(ems);
        // 取得所有类名中包含"selected"的元素
        let selecteds = document.querySelectorAll('.selected');
        // 取得所有是<p>元素子元素<strong>元素
        let strongs = document.querySelectorAll('p strong');
    </script>

结果:

image.png

元素遍历

  • childElementCount:返回子元素数量
  • firstElementChild:指向第一个Element类型的子元素
  • lastElementChild:指向最后一个Element类型的子元素
  • previousSibling:指向前一个Element类型的同胞元素
  • nextSibling:指向后一个Element类型的同胞元素

HTML5

CSS类扩展

  • getElementsByClassName():返回类名中包含相应类的元素的NodeList

classList属性

  • IE10及以上版本(部分)和其他主流浏览器实现了classList属性
  • 操作类名,通过className属性实现添加删除和替换 每次操作后要重新设置这个值才生效 eg:
        <div class="bd user disabled"></div>
    <script>
        let div = document.querySelector("div");
        // 要删除"user"类
        let targetClass = "user";
        // 把类名拆成数组
        let className = div.className.split(/\s+/);
        // 找到要删除类的索引
        let idx = className.indexOf(targetClass);
        // 如果有删除
        if (idx > -1) {
            className.splice(idx, 1);
        }
        // 重新设置类名
        div.className = className.join(" ");
        console.log(div.className);
    </script>

结果:

image.png

  • add:向类名列表中添加指定的字符串value。有的话什么也不做
  • contains:返回布尔值,表示给定的value是否存在
  • remove:从类名列表中删除指定的字符串值value
  • toggle:类名列表中存在指定value则删除,不存在则添加 优化 eg:
        <div class="bd user disabled"></div>
    <script>
        let div = document.querySelector("div");
        // 要删除"user"类
        div.classList.remove('user');
        console.log(div.className);
    </script>

结果:

image.png

焦点管理

eg:

        <input type="button" id="btn" value="">
    <script>
        let btn = document.getElementById('btn');
        btn.focus();
        console.log(document.activeElement === btn);
    </script>

结果:

image.png

插入标记

  • innerHTML属性innerText eg:
        <div id="btn"></div>
    <script>
        let btn = document.getElementById('btn');
        btn.innerHTML = 'hello word!';
    </script>

结果:

image.png

DOM2和DOM3

样式

css属性js属性
background-imagestyle.backgroundImage
colorstyle.color
displaystyle.display
font-familystyle.fontFamily

eg:

        <div id="div"></div>
    <script>
        let div = document.getElementById('div');
        div.style.backgroundColor = "green";
        div.style.width = "100px";
        div.style.height = "100px";
    </script>

结果:

image.png

事件

  • JavaScript与HTML的交互是通过事件实现的

事件流

  • 描述了页面接收事件的顺序

事件冒泡

  • IE事件流被称为事件冒泡。事件被定义为从最具体的元素开始触发,然后向上传播至没有那么具体的元素
  • 从下往上

DOM事件流

  • DOM2规定事件流分为3个阶段:事件捕获、到达目标、事件冒泡

事件处理程序

  • 为响应事件而调用的函数称为事件处理程序(或事件监听器)
    • 事件处理程序的名字以on开头

HTML事件处理程序

eg:

        <input type="button" value="11111" onclick="console.log('HTML事件处理程序')">

DOM0事件处理程序

eg:

        <button id="btn">DOM0事件处理程序</button>
    <script>
        let btn = document.getElementById('btn');
        btn.onclick = function() {
            console.log(this.id); // id
        }
        btn.onclick = null; //移除事件处理
    </script>

DOM2事件处理程序

  • DOM2 Events为事件处理程序的赋值和移除定义的两个方法
    • addEventListener()和removeEventListener()暴露在所有DOM节点上,接收3个参数
      • 事件名、事件处理函数和一个布尔值
      • true:表示在捕获阶段调用事件处理程序
      • false:表示在冒泡阶段调用事件处理程序 eg:
        <button id="btn">DOM2事件处理程序</button>
    <script>
        let btn = document.getElementById('btn');
        btn.addEventListener('click', () => {
            console.log('DOM2事件处理程序'); // DOM2事件处理程序
        }, false)
    </script>

IE事件处理程序

  • attachEvent()detachEvent() eg:
        <button id="btn">IE事件处理程序</button>
    <script>
        let btn = document.getElementById('btn');
        btn.attachEvent('onclick', function() {
            console.log('IE事件处理程序'); // IE事件处理程序
        })
    </script>

事件对象

  • DOM中发生事件时所有相关信息都会被收集并储存在event的对象中

DOM事件对象

  • event对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁
  • 在事件处理程序内部
    • this对象始终等于currentTarget的值
    • target只包含事件的实际 eg:
        <button id="btn">DOM事件对象</button>
    <script>
        let btn = document.getElementById('btn');
        btn.onclick = function(event) {
            console.log(event.type); // click
            console.log(event.currentTarget === this); // true
            console.log(event.target === this); // true
        }
    </script>
    // target属性等于按钮本身
    <button id="btn">移动到我身上变红</button>
    <script>
        let btn = document.getElementById('btn');
        let handler = function(event) {
            switch (event.type) {
                case "click":
                    console.log('clicked');
                    break;
                case "mouseover":
                    btn.style.backgroundColor = 'red';
                    break;
                case "mouseout":
                    event.target.style.backgroundColor = '';
                    break;

            }
        }
        btn.onclick = handler;
        btn.onmouseover = handler;
        btn.onmouseout = handler;
    <script>      

IE事件对象

  • 如果事件处理程序是使用DOM0方式制定的:event对象只是window对象一个属性

事件类型

  • 用户界面事件:涉及与BOM交互的通用浏览器事件
  • 焦点事件:在元素获得和失去焦点时触发
  • 鼠标事件:使用鼠标在页面上执行某些操作时的触发
  • 滚轮事件:使用鼠标滚轮时触发
  • 输入事件:向文档输入文本时触发
  • 键盘事件:使用键盘在页面上执行某些操作时触发
  • 合成事件:在使用某种IME输入字符时触发

用户界面事件

  • DOMActivate:元素被用户通过鼠标或键盘操作激活时触发
  • load:在window上当页面加载完成后触发
  • unload:在window上页面完全卸载后触发
  • abort:在<object>元素上当相应对象加载完成前被用户提前终止下载时触发
  • error:在window上当JavaScript报错时触发
  • select:在文本框(<input>或textarea)上用户选择一个或多个字符时触发
  • resize:在window或窗格上当窗口或窗格被缩放时触发
  • scroll:当用户滚动包含滚动条的元素时在元素上触发 eg:
        window.addEventListener("load", (event) => {
            console.log('Loaded!'); // Loaded!
        })

焦点事件

  • focus:当元素获取焦点时触发
  • blur::当元素失去焦点时触发

鼠标和滚轮事件

  • click:在用户单击鼠标主键(左键)或回车时触发
  • dbclick:在用户双击鼠标主键(左键)时触发
  • mousedown:在用户按下任意鼠标键时触发
  • mouseenter:在用户把鼠标光标从元素外部移到内部时触发
  • mouseleave:在用户把鼠标光标从元素内部移到外部时触发
  • mousemove:在鼠标在元素上移动时反复触发
  • mouseout:在用户把鼠标光标从一个元素移到另一个元素上时触发
  • mouseover:在用户把鼠标光标从元素外部移到内部时触发
  • mouseup:在用户释放鼠标键时触发
    • 页面的所有元素都支持鼠标事件,除了mouseenter和mouseleave,所有鼠标事件都会冒泡,都可以取消

键盘与输入事件

  • keydown:用户按下键盘某个键时触发
  • keypress:用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发

表单脚本

表单基础

  • acceptCharset:服务器可以接收的字符集。等价于HTML的accept-charset属性
  • action:请求的URL,等价于HTML的action
  • elements:表单中所有控件的HTMLCollection
  • enctype:请求的编码类型,等价于HTML的enctype属性
  • length:表单控件的数量
  • method:HTTP请求的方法类型,通常是get或post,等价于HTML的method属性
  • name:表单的名字,等价于HTML的name属性
  • reset:把表单字段重置为各自的默认值
  • submit:提交表单
  • target:用于发送请求和接收响应的窗口名字,等价于HTML的target属性
    • 公共属性
      • document.forms获取页面上所有表单元素
      • event.preventDefault()阻止表单提交
      • disable:布尔值,表示表单字段是否禁用
      • from:指针,指向表单字段所属的表单。(只读属性)
      • name:字符串、这个字段的名字
      • type:字符串,表示字段类型,如radio、checkbox
      • value:要提交给服务器的字段值
    • 公共事件
      • blur:在字段失去焦点时触发
      • change:<input>元素的value发生变化且失去焦点时触发,<select>选中选项触发
      • focus:在字段获得焦点时触发

文本框编程

  • 在HTML有两种文本框的方式:单行使用 input 和 多行使用 textarea
    • required:必填字段
    • HTML5新增type值:email 和 url
    • pattern:用于指定一个正则表达式,用户输入的文本必须与之匹配 eg:
    <form id="form" action="" method="post">
        密码:<input type="password" id="pwd" value="123456" name="password"><br>
        <input type="radio" name="sex" value="男">男
        <input type="radio" name="sex" checked value="女">女
    </form>
    <script>
        let form = document.getElementById('form');
        let filed1 = form.elements['sex'].value;
        console.log(filed1);
        let filed2 = form.elements['password'].value;
        console.log(filed2);
        let pwd = document.getElementById('pwd');
        let pwdValue = pwd.value;
        console.log(pwdValue);
        let radio = form.elements[1].type;
        console.log(radio);
        let name = form.elements[0].name;
        console.log(name);
    </script>

结果:

image.png

JSON

  • 理解JSON语法
  • 解析JSON
  • JSON序列化

语法

  • 简单值:字符串、数值、布尔值和null可以在JSON中出现。特殊值undefined不可以
  • 对象:第一种复杂数据类型,对象表示有序键/值对。每个值可以是简单值,也可以是复杂类型
  • 数组:第二种复杂数据类型,数组表示可以通过数值索引访问的值的有序列表。

简单值

  • JSON字符串必须使用双引号
  • 布尔值和null本身也是有效的JSON值 eg:
       "hello word!" 

对象

  • JSON的对象必须使用双引号把属性名包围起来 eg:
        {
            "name": "测试",
            "age": 29
        }

数组

  • 数组在JSON中使用JavaScript的数组字面量形式表示 eg:
       [25, "测试", true];

解析与序列化

JSON对象

  • JSON对象有俩个方法:stringfy()parse()
    • JSON.stringfy()把一个JavaScript对象序列化为一个JSON字符串
    • 输出不包括空格或缩进的JSON字符串
    • JSON字符串直接传给JSON.parse()得到相应的JavaScript对象 eg:
        let book = {
            title: "西游记",
            authors: [
                "吴承恩",
                "六小龄童"
            ],
            edition: 4,
            year: 2017
        };
        let jsonText = JSON.stringify(book);
        console.log(jsonText, 'jSON字符串');
        let bookCopy = JSON.parse(jsonText);
        console.log(bookCopy, 'js对象');
        

结果:

image.png

网络请求与远程资源

使用XHR

  • 使用XHR对象要调用open():请求类型("get"、"post"等)、请求URL,以及是否异步的布尔值
  • 只能访问同源URL:域名、端口、协议相同 eg:
       xhr.open("get", "index.php", false);

  • 发送定义好的请求,必须调用send()方法
  • 不需要发送请求体,必须传null eg:
       xhr.open("get", "index.php", false);
       xhr.send(null);

  • responseText:作为响应体返回的文本
  • responseXML:响应数据的XML DOM文档
  • status:相应的HTTP状态
  • statusText:相应的HTTP状态描述

HTTP头部

  • Cookie:页面中设置的Cookie
  • Host:发送请求页面所在的域
  • Referer:发送请求页面的URL

GET请求

  • 向服务器查询某些信息。必要时在get请求的URL后面添加查询字符串参数
  • 查询字符串的每个名和值必须使用encodeURLComponent()编码,名/值必须以和号(&)分隔 eg:
       xhr.open("get", "index.php?name1=value1&name2=value2", true);

POST

  • POST请求比GET请求占用更多资源。
  • 性能方面:发送相同数量的数据,GET请求比POST请求要快2倍 eg:
       xhr.open("post", "index.php", true);

FormData类型

  • FormData:对表单数据进行序列化

超时

  • IE8给XHR增加timeout:用于表示发请求后等待多少毫秒,如果响应不成功就中断请求

跨源资源共享

  • Origin:http://www.text.net
  • 如果服务器决定响应请求,应该发送Access-Control-Allow-Origin头部,包含相同的源;或者如果资源是公开的,那么就包含"*"。
  • 无论是请求还是响应都不会包含cookie信息 eg:
       Access-Control-Allow-Origin: http://www.text.net

JSONP跨域

  • JSONP包含两部分:回调和数据 eg:
      callback({"name": "Nicholas"})
      // JSONP请求
      http://index.net/json/?callback=handleResponse

原理:通过script里面的src属性

解决跨域问题

  • 修改响应头 跨域请求:res.header("Access-Control-Allow-Origin","*")
  • jsonp 跨域请求:回调函数callback eg:
      <h1>Hello!!</h1>
    <script>
        // 1.修改响应头 跨域请求
        res.header("Access-Control-Allow-Origin","*")
        // 2.jsonp 跨域请求
        var app = express();
        app.get("/", function(req, res) {
            var funcname = req.query.callback;
            res.send(funcname + "('你好')");
            // fn('你好')
        })
    </script>

    <script>
        function fn(data) {
            alert(data);
        }
    </script>
    <script src="http://localhost:80?callback=fn"></script>

Fetch API

image.png

错误处理与调试

try/catch 语句

eg:

      try {
            // 可能出错的代码
      } catch (error) {
            // 出错时要做什么
      }

finally 子句

  • 只要代码包含了finally子句。try块a或catch块中的return会被忽略 eg:
      try {
            return 2;
        } catch (error) {
            return 1;
        } finally {
            return 0;
        }

客户端储存

cookie

  • 在客户端储存会话信息

限制

  • 与特定域绑定的

cookie的构成

  • 名称:唯一标识 不区分大小写
  • 值:必须经过URL编码
    • 编码:encodeURIComponent()
    • 解码:decodeURIComponent()
  • 域:有效的域
  • 路径:请求URL中包含这个路径才会把cookie发送到服务器
  • 过期时间:何时删除cookie的时间戳
  • 安全标志:设置之后,只在使用SSL安全连接的情况下才会把cookie发送到服务器

Web Storage

  • 解决通过客户端不需要频繁发送回服务器的数据时使用cookie的问题
    • localStorage:永久储存机制
    • sessionStorage:跨会话的储存机制

Storage类型

  • 用于保存名/值对数据。
    • clear():删除所有值,不在Firefox中实现
    • getItem(name):取得name的值
    • key(index):取得给定数值位置的名称
    • removeItem(name):删除给定name名/值对
    • setItem(name,value):设置给定name的值

sessionStorage对象

  • 只储存会话数据,数据只会储存到浏览器关闭。
    • 只能由最初存储数据的页面使用,多页面程序中用处有限
    • 通过使用setItem()方法或直接给属性赋值给它添加数据 eg:
        // 储存数据
        sessionStorage.setItem("name", "Mary");
        // 取出数据
        let name = sessionStorage.getItem("name");
        console.log(name);
        // 删除值
        sessionStorage.removeItem("name");

结果:

image.png

localStorage对象

  • 同一个域,在相同端口上使用相同的协议
  • 不受页面刷新影响,也不会因关闭窗口、标签页或重新启动浏览器而丢失 eg:
       // 储存数据
        localStorage.setItem("name", "Mack");
        // 取出数据
        let mack = localStorage.getItem("name");
        console.log(mack);

结果:

image.png

vue登录验证token

eg:

       // 路由守卫
       // '/login':初始页面
       // to:即将要进入的目标路由对象 from:即将要离开的路由对象; next 进行管道中的下一个钩子
       router.beforeEach((to, from, next) => {
            // 取token值
            let token = localStorage.getItem("token");
            if (token || to.path === '/login') {
                next();
            } else {
                next('/login');
            }
        })