ECMAScript入门

基本介绍

1. 它是一种由ECMA组织(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范
2. 而我们学的 JavaScript 是ECMA的实现, 但术语ECMAScript和JavaScript平时表达同一个意思
3. JS包含三个部分:
   1). ECMAScript(核心)
   2). 扩展==>浏览器端
      * BOM(浏览器对象模型)
      * DOM(文档对象模型)
   3). 扩展==>服务器端
      * Node
4. ES的几个重要版本
   * ES5 : 09年发布
   * ES6(ES2015) : 15年发布, 也称为ECMA2015
   * ES7(ES2016) : 16年发布, 也称为ECMA2016  (变化不大)

ES5

严格模式

1. 理解:
  * 除了正常运行模式(混杂模式),ES5添加了第二种运行模式:"严格模式"(strict mode)。
  * 顾名思义,这种模式使得Javascript在更严格的语法条件下运行
2. 目的/作用
  * 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为
  * 消除代码运行的一些不安全之处,为代码的安全运行保驾护航
  * 为未来新版本的Javascript做好铺垫
3. 使用
  * 在全局或函数的第一条语句定义为: 'use strict';
  * 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用
4. 语法和行为改变
  * 必须用var声明变量
  * 禁止自定义的函数中的this指向window
  * 创建eval作用域
  * 对象不能有重名的属性

示例代码:

<script type="text/javascript">
    'use strict';
    // username = 'kobe';
    var username = 'kobe';
    console.log(username);

    function Person (name, age) {
        this.name = name;
        this.age = age;
    }
    // Person('kobe', 41);
    new Person('kobe', 41);

    var str = 'NBA';
    eval('var str = "CBA"; alert(str)');
    alert(str);

    var obj = {
        username: 'kobe',
        // username: 'wade'
    }
</script>

JSON对象

1. JSON.stringify(obj/arr)
  * js对象(数组)转换为json对象(数组)
2. JSON.parse(json)
  * json对象(数组)转换为js对象(数组)

Object扩展

ES5给Object扩展了一些静态方法, 常用的2个:
1. Object.create(prototype, [descriptors])
  * 作用: 以指定对象为原型创建新的对象
  * 为新的对象指定新的属性, 并对属性进行描述
    - value : 指定值
    - writable : 标识当前属性值是否是可修改的, 默认为false
    - configurable: 标识当前属性是否可以被删除 默认为false
    - enumerable: 标识当前属性是否能用for in 枚举 默认为false
2. Object.defineProperties(object, descriptors)
  * 作用: 为指定对象定义扩展多个属性
  * get :用来获取当前属性值的回调函数(需要取值时才会调用,“惰性求值”)
  * set :修改当前属性值得触发的回调函数,并且实参即为修改后的值
  * 存取器属性:setter,getter一个用来存值,一个用来取值

示例代码:

  var obj = {username: 'damu', age: 30};
  var obj1 = {};
  obj1 = Object.create(obj, {
    sex: {
        value: '男',
        writable: true,
        configurable: true,
        enumerable: true
    }
  });
  console.log(obj1.sex);
  obj1.sex = '女';
  console.log(obj1.sex);
  // delete obj1.sex;
  console.log(obj1);
  for(var i in obj1){
    console.log(i);
  }


  var obj2 = {firstName: 'kobe', lastName: 'bryant'};
  Object.defineProperties(obj2, {
      fullName: {
          get: function(){// 获取扩展属性的值(获取扩展属性值时get会自动调用)
              return this.firstName + ' ' + this.lastName;
          },
          set: function(data){// 监听扩展属性,当扩展属性发生变化的时候会自动调用(变化后的值作为实参传入)
              var names = data.split(' ');
              this.firstName = names[0];
              this.lastName = names[1];
          }
      }
  })
  console.log(obj2.fullName);
  obj2.fullName = 'tim duncan';
  console.log(obj2.fullName);
  console.log(obj2.lastName);
对象本身的两个方法
* get propertyName(){} 用来得到当前属性值的回调函数
* set propertyName(){} 用来监视当前属性值变化的回调函数

示例代码:

    var obj = {
        firstName: 'curry',
        lastName: 'stephen',
        get fullName(){
            return this.firstName + ' ' + this.lastName;
        },
        set fullName(data){
            var names = data.split(' ');
            this.firstName = names[0];
            this.lastName = names[1];
        }
    };
    console.log(obj);
    obj.fullName = 'kobe bryant';
    console.log(obj.fullName);

Array扩展

1. Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
2. Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
3. Array.prototype.forEach(function(item, index){}) : 遍历数组
4. Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组,返回加工之后的值
5. Array.prototype.filter(function(item, index){}) : 遍历过滤出一个新的子数组, 返回条件为true的值

示例代码:

  /*
   需求:
   1. 输出第一个6的下标
   2. 输出最后一个6的下标
   3. 输出所有元素的值和下标
   4. 根据arr产生一个新数组,要求每个元素都比原来大10
   5. 根据arr产生一个新数组, 返回的每个元素要大于4
   */

  var arr = [2,4,3,1,2,6,5,4];
  console.log(arr.indexOf(4));
  console.log(arr.lastIndexOf(4));
  arr.forEach(function(item, index){
    console.log(item, index);
  })

  var arr1 = arr.map(function (item, index) {
      return item + 10;
  })
  console.log(arr1);

  var arr2 = arr.filter(function (item, index) {
      return item > 4;
  })
  console.log(arr2);

Function扩展

1. Function.prototype.bind(obj) :
  * 作用: 将函数内的this绑定为obj, 并将函数返回
2. 面试题: 区别bind()与call()和apply()?
  * 都能指定函数中的this
  * call()/apply()是立即调用函数
  * bind()是将函数返回

示例代码:

  var obj = {username: 'kobe'};
  function foo(data){
      console.log(this, data);
  }
  // 直接调用foo方法打印的this是Window
  // foo();

  // call和apply的方法作用一样,区别在于传参的方式
  foo.call(obj, 33);// 直接从第2个参数开始,依次传入
  foo.apply(obj, [33]);// 第二个参数必须是数组,参数放在数组里

  // bind的特点:绑定完this不会立即调用当前的函数,而是将函数返回
  var bar = foo.bind(obj);
  bar();
  // bind的传参方式和call一样
  foo.bind(obj, 33)();

  // 应用举例
  setTimeout(function(){
    console.log(this);
  }.bind(obj), 1000);

ES6(常用)

let关键字

1. 作用:
  * 与var类似, 用于声明一个变量
2. 特点:
  * 在块作用域内有效
  * 不能重复声明
  * 不会预处理(即不能在声明之前使用,会抛出异常,而var在声明前使用值是undefined), 不存在提升
3. 应用:
  * 循环遍历加监听
  * 使用let取代var是趋势

示例代码:

  // console.log(username);
  let username = 'kobe';
  // let username = 'wade';
  console.log(username);

  let btns = document.getElementsByTagName('button');
  for(var i = 0; i < btns.length; i++){
    var btn = btns[i];
    btn.onclick = function () {
        // 打印出来的都是3
        alert(i);
    }
  }

  // 解决方法1:用闭包函数
  btns = document.getElementsByTagName('button');
  for(var i = 0; i < btns.length; i++){
      var btn = btns[i];
      (function(i){
          btn.onclick = function () {
              // 打印出来的都是3
              alert(i);
          }
      })(i)
  }

  // 解决方法2:用let关键字
  btns = document.getElementsByTagName('button');
  for(let i = 0; i < btns.length; i++){
      var btn = btns[i];
      btn.onclick = function () {
          // 打印出来的都是3
          alert(i);
      }
  }

const关键字

1. 作用:
  * 定义一个常量
2. 特点:
  * 不能修改
  * 其它特点同let
3. 应用:
  * 保存不用改变的数据

解构赋值

1. 理解:
  * 从对象或数组中提取数据, 并赋值给变量(多个)
2. 对象的解构赋值
  let {n, a} = {n:'tom', a:12}
3. 数组的解构赋值
  let [a,b] = [1, 'atguigu'];
4. 用途
  * 给多个形参赋值

示例代码:

  let obj = {username: 'kobe', age: 39};
  // let username = obj.username;
  // let age = obj.age;
  let {username, age} = obj;
  console.log(username, age);

  let arr = [1,3,5,'abc',true];
  let [,,a,b] = arr;
  console.log(a, b);

  function foo({username, age}){// {username, age} = obj
      console.log(username, age);
  }
  foo(obj);

模板字符串

1. 模板字符串 : 简化字符串的拼接
  * 模板字符串必须用 `` 包含
  * 变化的部分使用${xxx}定义

示例代码:

  let obj = {username: 'kobe', age: 39};
  let str = '我的名字叫:' + obj.username + ',我今年的年龄是:' + obj.age;
  console.log(str);
  str = `我的名字叫:${obj.username},我今年的年龄是:${obj.age}`;
  console.log(str);

简化的对象写法

简化的对象写法
* 省略同名的属性值
* 省略方法的function
* 例如:
  let x = 1;
  let y = 2;
  let point = {
    x,
    y,
    setX (x) {this.x = x}
  };

箭头函数

* 作用: 定义匿名函数
* 基本语法:
  * 没有参数: () => console.log('xxxx')
  * 一个参数: i => i+2
  * 大于一个参数: (i,j) => i+j
  * 函数体不用大括号: 默认返回结果
  * 函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
* 使用场景: 多用来定义回调函数

* 箭头函数的特点:
    1、简洁
    2、箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this
    3、扩展理解: 箭头函数的this看外层的是否有函数,
        如果有,外层函数的this就是内部箭头函数的this,
        如果没有,则this是window。

示例代码:

    // 不同传参的情况
    // 1、没有形参
    let fun = () => console.log('我是箭头函数');
    fun();
    // 2、只有1个形参,()可以省略
    let fun2 = a => console.log(a);
    fun2('aaa');
    // 3、两个及以上形参,()不能省略
    let fun3 = (x, y) => console.log(x, y);
    fun3(25, 36);

    // 不同函数体的情况
    // 1、函数体只有一条语句或是表达式的时候,{}可以省略。会自动返回语句执行的结果或是表达式的结果
    let fun4 = (x, y) => x + y;
    console.log(fun4(24, 36));
    // 2、函数体不止一条语句或表达式的情况下,{}不可以省略
    let fun5 = (x, y) => {
        console.log(x, y);
        return x + y;
    }
    console.log(fun5(35, 50));

    let obj = {
        name: '箭头函数',
        // getName(){
        getName: () => {
            btn2.onclick = () => {
                console.log(this);
            }
        }
    }
    // 等价于 obj.getName = () => {},所以this是Window对象
    obj.getName();

三点运算符

* 用途
1. rest(可变)参数
    * 用来取代arguments 但比 arguments 灵活,只能是最后部分形参参数
    function fun(...values) {
        console.log(arguments);
        arguments.forEach(function (item, index) {
            console.log(item, index);
        });
        console.log(values);
        values.forEach(function (item, index) {
            console.log(item, index);
        })
    }
    fun(1,2,3);
2. 扩展运算符
  let arr1 = [1,3,5];
  let arr2 = [2,...arr1,6];
  console.log(arr2);
  console.log(...arr2);

形参默认值

* 形参的默认值----当不传入参数的时候默认使用形参里的默认值
function Point(x = 1,y = 2) {
  this.x = x;
  this.y = y;
}

Promise对象

1. 理解:
  * Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
  * 有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称'回调地狱')
  * ES6的Promise是一个构造函数, 用来生成promise实例
2. 使用promise基本步骤(2步):
  * 创建promise对象
    let promise = new Promise((resolve, reject) => {
        //初始化promise状态为 pending
      //执行异步操作
      if(异步操作成功) {
        resolve(value);//修改promise的状态为fullfilled
      } else {
        reject(errMsg);//修改promise的状态为rejected
      }
    })
  * 调用promise的then()
    promise.then(
      result => console.log(result),
      errorMsg => alert(errorMsg)
    )
3. promise对象的3个状态
  * pending: 初始化状态
  * fullfilled: 成功状态
  * rejected: 失败状态
4. 应用:
  * 使用promise实现超时处理

  * 使用promise封装处理ajax请求
    let request = new XMLHttpRequest();
    request.onreadystatechange = function () {
    }
    request.responseType = 'json';
    request.open("GET", url);
    request.send();

示例代码:

  // 创建promise对象
  let promise = new Promise((resolve, reject) => {
      // 初始化promise状态:pending: 初始化
      console.log('111');
      // 执行异步操作,通常是发送ajax请求、开启定时器
      setTimeout(function () {
          console.log('333');
          // 根据异步任务的返回结果去修改promise状态
          // 异步任务执行成功
          resolve('哈哈');// 修改promise的状态为 fullfilled: 成功的状态

          // 异步任务执行失败
          // reject('555');// 修改promise的状态为 rejected: 失败的状态
      }, 2000);
  })
  console.log('222');

  promise.then((data) => {// 成功的回调
      console.log(data, '成功了!')
  }, (error) => {// 失败的回调
      console.log(error, '失败了。。。')
  })

应用案例:

    // 定义获取新闻的函数
    function getNews(url){
        let promise = new Promise((resolve, reject) => {
            // 状态:初始化
            // 执行异步任务
            // 创建xmlHttp实例对象
            let xmlHttp = new XMLHttpRequest();
            // 绑定监听 readyState
            xmlHttp.onreadystatechange = function(){
                if(xmlHttp.readyState === 4){
                    if(xmlHttp.status == 200){// 请求成功
                        // 修改状态
                        resolve(xmlHttp.responseText);// 修改promise的状态为成功的状态
                    }else{// 请求失败
                        reject('暂时没有新闻内容');
                    }
                }
            }

            // open 设置请求的方式以及url
            xmlHttp.open('GET', url);
            // 发送
            xmlHttp.send();
        })
        return promise;
    }

    getNews('http://localhost:3000/news?id=2').then((data) => {
        console.log(data);
        // 发送请求获取评论内容准备url
        let commentsUrl = JSON.parse(data).commentsUrl;
        let url = 'http://localhost:3000' + commentsUrl;
        // 发送请求
        return getNews(url);
    }, (error) => {
        console.log(error);
    })
    .then((data) => {
        console.log(data);
    }, (error) => {

    })

Symbol

前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
Symbol:
  概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
  特点:
    1、Symbol属性对应的值是唯一的,解决命名冲突问题
    2、Symbol值不能与其他数据进行计算,包括同字符串拼串
    3、for in, for of遍历时不会遍历symbol属性。
  使用:
    1、调用Symbol函数得到symbol值
      let symbol = Symbol();
      let obj = {};
      obj[symbol] = 'hello';
    2、传参标识
      let symbol = Symbol('one');
      let symbol2 = Symbol('two');
      console.log(symbol);// Symbol('one')
      console.log(symbol2);// Symbol('two')
    3、内置Symbol值
      * 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
      - Symbol.iterator
       * 对象的Symbol.iterator属性,指向该对象的默认遍历器方法

示例代码:

    // 创建Symbol属性值
    let symbol = Symbol();
    console.log(symbol);
    let obj = {username: 'kobe', age: 39};
    obj[symbol] = 'hello';
    console.log(obj);

    // for in, for of遍历时不会遍历symbol属性
    for(let i in obj){
      console.log(i);
    }

    let symbol2 = Symbol('one');
    let symbol3 = Symbol('two');
    console.log(symbol2 == symbol3);// false
    console.log(symbol2, symbol3);

    // 可以去定义常量
    const Person_key = Symbol('person_key');
    console.log(Person_key);

Iterator遍历器

概念: iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制
作用:
  1、为各种数据结构,提供一个统一的、简便的访问接口;
  2、使得数据结构的成员能够按某种次序排列
  3、ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
工作原理:
  - 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
  - 第一次调用next方法,指针自动指向数据结构的第一个成员
  - 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
  - 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
    * value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
    * 当遍历结束的时候返回的value值是undefined,done值为false
原生具备iterator接口的数据(可用for of遍历)
  1、Array
  2、arguments
  3、set容器
  4、map容器
  5、String
  。。。

实现模拟 Iterator 遍历器:

    // 模拟指针对象(遍历器对象)
    function myIterator(arr){// iterator接口
        let nextIndex = 0;// 记录指针的位置
        return {
            next: function(){
                return nextIndex < arr.length ? {value: arr[nextIndex++], done: false} : {value: undefined, done: true};
            }
        }
    }
    // 准备一个数据
    let arr = [1, 4, 65, 'abc'];
    let iteratorObj = myIterator(arr);
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());

示例代码:

    let arr = [1, 4, 65, 'abc'];
    // 将iterator接口部署到指定的数据类型上,可以使用for of去循环遍历
    // 数组、字符串、arguments、set容器、map容器
    for(let i of arr){
      console.log(i);
    }
    let str = 'abcdefg';
    for(let i of str){
        console.log(i);
    }
    function fun(){
        for(let i of arguments){
            console.log(i);
        }
    }
    fun(1,4,5,'abc');

扩展:

    // 对象的Symbol.iterator属性,指向该对象的默认遍历器方法
    // 等同于在指定的数据内结构上部署了iterator接口,
    // 当使用for of去遍历某一个数据结构时,首先先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历 ==》 xxx is not iterable
    let targetData = {
        0: 'a',
        1: 'b',
        2: 'c',
        length: 3,
        [Symbol.iterator]: function() {
            let nextIndex = 0;// 记录指针的位置
            return {
                next: () => {
                    return nextIndex < this.length ? {value: this[nextIndex++], done: false} : {value: undefined, done: true};
                }
            }
        }
    }
    // 定义了Symbol.iterator之后,Object也可以用for of遍历了
    for(let i of targetData){
        console.log(i);
    }

    // 用Symbol.iterator去迭代
    let numbers = [1,2,3,4,5];
    let iterator = numbers[Symbol.iterator]();
    console.log(iterator.next().value);
    console.log(iterator.next().value);

    // 使用三点运算符、解构赋值,默认去调用iterator接口
    let arr2 = [1, 6];
    let arr3 = [2, 3, 4, 5];
    arr2 = [1, ...arr3, 6];
    console.log(arr2);
    let [a, b] = arr2;
    console.log(a, b);

Generator函数

Generator函数
 概念:
   1、ES6提供的解决异步编程的方案之一
   2、Generator函数是一个状态机,内部封装了不同状态的数据,
   3、用来生成遍历器对象
   4、可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
 特点:
   1、function 与函数名之间有一个星号
   2、内部用yield表达式来定义不同的状态
   例如:
     function* generatorExample(){
       let result = yield 'hello';  // 状态值为hello
       yield 'generator'; // 状态值为generator
     }
   3、generator函数返回的是指针对象,而不会执行函数内部逻辑
   4、调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true}
   5、再次调用next方法会从上一次停止时的yield处开始,直到最后
   6、yield语句返回结果通常为undefined, 当调用next方法时传参内容会作为启动时yield语句的返回值。

示例代码:

    function* myGenerator(){
        console.log('开始执行');
        let result = yield 'hello';
        console.log(result);// 打印结果==》传入的参数aaa
        console.log('暂停后,再次执行');
        yield 'generator';
        console.log('遍历完毕');
        return '返回的结果';
    }
    let mg = myGenerator();// 返回的是指针对象
    console.log(mg);
    console.log(mg.next());// {value: "hello", done: false}
    console.log(mg.next('传入的参数aaa'));// {value: "generator", done: false}
    console.log(mg.next());// {value: "返回的结果", done: true}

    // 对象的symbol.iterator属性  指向遍历器对象
    let obj = {username: 'kobe', age: 39};
    obj[Symbol.iterator] = function* myTest(){
        yield 1
        yield 2
        yield 3
    }
    for(let i of obj){
        console.log(i);
    }

应用案例:

   /*
    * 需求:
    * 1、发送ajax请求获取新闻内容
    * 2、新闻内容获取成功后再次发送请求,获取对应的新闻评论内容
    * 3、新闻内容获取失败则不需要再次发送请求。
    * */ 

    function getNews(url){
        $.get(url, function (data){
            console.log(data);
            let url = 'http://localhost:3000' + data.commentsUrl;
            SX.next(url);
        })
    }

    function* sendXml(){
        let url = yield getNews('http://localhost:3000/news?id=3');
        yield getNews(url);
    }
    // 获取遍历器对象
    let SX = sendXml();
    SX.next();

async函数

async函数(源自ES2017)
概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
本质: Generator的语法糖
语法:
    async function foo(){
      await 异步操作;
      await 异步操作;
    }
特点:
  1、不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
  2、返回的总是Promise对象,可以用then方法进行下一步操作
  3、async取代Generator函数的星号*,await取代Generator的yield
  4、语意上更为明确,使用简单,经临床验证,暂时没有任何副作用

示例代码:

  // async基本使用
  function foo(){
      return new Promise(resolve => {
          setTimeout(resolve, 2000);
      })
  }

  async function test(){
      console.log('开始执行', new Date().toTimeString());
      await foo();
      console.log('执行完毕。。。', new Date().toTimeString());
  }
  test();

应用案例:

  // 获取新闻内容
  async function getNews(url){
      return new Promise((resolve, reject) => {
          $.ajax({
              method: 'GET',
              url,
              success: data => resolve(data),
              error: error => reject(error)
          })
      })
  }

  async function sendXml(){
      let result = await getNews('http://localhost:3000/news?id=3');
      console.log(result);
      result = await getNews('http://localhost:3000' + result.commentsUrl);
      console.log(result);
  }
  sendXml();

class面向对象

1. 通过class定义类/实现类的继承
2. 在类中通过constructor定义构造方法
3. 通过new来创建类的实例
4. 通过extends来实现类的继承
5. 通过super调用父类的构造方法
6. 重写从父类中继承的一般方法

示例代码:

  // 定义一个人物的类
  class Person{
      // 类的构造方法
      constructor(name, age){
          this.name = name;
          this.age = age;
      }
      // 类的一般方法
      showName(){
          console.log(this.name, this.age);
      }
  }

  let person = new Person('kobe', 39);
  console.log(person);
  person.showName();

  // 子类
  class StarPerson extends Person{
      constructor(name, age, salary){
          super(name, age);// 调用父类的构造方法
          this.salary = salary;
      }
      // 子类的方法重写
      showName(){
          console.log(this.name, this.age, this.salary);
      }
  }
  let p1 = new StarPerson('wade', 36, 100000000);
  console.log(p1);
  p1.showName();

Module

ES6(其他)

字符串扩展

1. includes(str) : 判断是否包含指定的字符串
2. startsWith(str) : 判断是否以指定字符串开头
3. endsWith(str) : 判断是否以指定字符串结尾
4. repeat(count) : 重复指定次数

示例代码:

  let str = 'abc';
  console.log(str.includes('t'));
  console.log(str.includes('a'));
  console.log(str.startsWith('a'));
  console.log(str.endsWith('f'));
  console.log(str.repeat(3));// abcabcabc

数值扩展

1. 二进制与八进制数值表示法: 二进制用0b, 八进制用0o
2. Number.isFinite(i) : 判断是否是有限大的数
3. Number.isNaN(i) : 判断是否是NaN
4. Number.isInteger(i) : 判断是否是整数
5. Number.parseInt(str) : 将字符串转换为对应的数值
6. Math.trunc(i) : 直接去除小数部分

示例代码:

  console.log(0b1010);// 10
  console.log(0o56);// 46
  console.log(Number.isFinite(Infinity));// false
  console.log(Number.isNaN(NaN));// true
  console.log(Number.isInteger(123.12));// false
  console.log(Number.isInteger(123.0));// true
  console.log(Number.parseInt('123abc222'));// 123
  console.log(Number.parseInt('abc222'));// NaN
  console.log(Math.trunc(123.12));// 123

数组扩展

1. Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
2. Array.of(v1, v2, v3) : 将一系列值转换成数组
3. find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
4. findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标

示例代码:

  let btns = document.getElementsByTagName('button');
  console.log(btns);
  Array.from(btns).forEach(function(item, index){
      console.log(item);
  })

  let arr = Array.of(1,3,'abc',true);
  console.log(arr);

  let arr2 = [2,3,4,2,5,7,3,6,5];
  let result = arr2.find(function(item, index){
      return item > 4;
  })
  console.log(result);
  result = arr2.findIndex(function(item, index){
      return item > 4;
  })
  console.log(result);

Object扩展

1. Object.is(v1, v2)
  * 判断2个数据是否完全相等(其实是用字符串比较)
2. Object.assign(target, source1, source2..)
  * 将源对象的属性复制到目标对象上
3. 直接操作 __proto__ 属性
  let obj2 = {};
  obj2.__proto__ = obj1;

示例代码:

  console.log(0 == -0);// true
  console.log(NaN == NaN);// false
  console.log(Object.is(0, -0));// false
  console.log(Object.is(NaN, NaN));// true

  let obj = {};
  let obj1 = {username: 'iverson', age:42};
  let obj2 = {sex: '男'};
  Object.assign(obj, obj1, obj2);
  console.log(obj);

  let obj3 = {};
  let obj4 = {qian: 5000000};
  obj3.__proto__ = obj4;
  console.log(obj3);
  console.log(obj3.qian);

深度克隆

1、数据类型:
  * 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
  - 基本数据类型:
    特点: 存储的是该对象的实际数据
  - 对象数据类型:
    特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
2、复制数据
  - 基本数据类型存放的就是实际的数据,可直接复制
    let number2 = 2;
    let number1 = number2;
  - 克隆数据:对象/数组
    1、区别: 浅拷贝/深度拷贝
       判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
       知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
       let obj = {username: 'kobe'}
       let obj1 = obj; // obj1 复制了obj在栈内存的引用
    2、常用的拷贝技术
      1). arr.concat(): 数组浅拷贝
      2). arr.slice(): 数组浅拷贝
      3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
      4). 浅拷贝包含函数数据的对象/数组
      5). 深拷贝包含函数数据的对象/数组

示例代码:

  // 不会影响原数据
  let str = 'abcd';
  let str2 = str;
  console.log(str2);
  str2 = '';
  console.log(str);
  let bool1 = true;
  let bool2 = bool1;
  bool2 = false;
  console.log(bool1);

  // 拷贝数组/对象,没有生成新的数据而是复制了一份引用
  let obj = {username: 'kobe', age: 39};
  let obj2 = obj;
  console.log(obj2);
  obj2.username = 'wade';
  console.log(obj.username);
  let arr = [1, 4, {username: 'kobe', age: 39}];
  let arr2 = arr;
  arr2[0] = 'abcd';
  console.log(arr, arr2);

  /**
   * 拷贝数据:
   *  基本数据类型:
   *    拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响原数据
   *  对象/数组:
   *    拷贝后不会生成新的数据,而是拷贝的引用。修改拷贝以后的数据会影响原来的数据
   *
   *  拷贝数据的方法:
   *    1.直接赋值给一个变量  // 浅拷贝
   *    2.Object.assign()  // 浅拷贝
   *    3.Array.prototype.concat()  // 浅拷贝
   *    4.Array.prototype.slice()  // 浅拷贝
   *    5.JSON.parse(JSON.stringify())  // 深拷贝(深度克隆),但不能处理函数数据
   *
   *  浅拷贝(对象/数组)
   *    特点:拷贝的引用,修改拷贝以后的数据会影响原数据,使得原数据不安全
   *  深拷贝(深度克隆)
   *    特点:拷贝的时候生成新数据,修改拷贝以后的数据不会影响原数据
   */
  {
  let obj = {username: 'kobe'};
  let obj2 = Object.assign(obj);
  console.log(obj2);
  obj.username = 'wade';
  console.log(obj2);

  let arr = [1, 3, {username: 'kobe'}, function fun(){}];
  let arr2 = arr.concat();
  arr2[0] = 2;// 这个修改不影响arr的第一个元素,因为是复制的基本类型
  arr2[2].username = 'wade';// 这个修改会影响原数据,因为复制是对象的引用
  console.log(arr);
  let arr3 = arr.slice();
  arr3[2].username = 'iverson';// 会影响
  console.log(arr);
  let arr4 = JSON.parse(JSON.stringify(arr));
  console.log(arr4);
  arr4[2].username = 'duncan';// 不影响
  console.log(arr, arr4);

实现深度克隆前的知识储备:

  /**
   * 思考:如何实现深度拷贝(克隆)
   *  即使有对象/数组,也可以继续遍历对象/数组拿到里边每一项值,直到拿到的是基本数据类型,然后再去复制,就是深度拷贝
   *
   * 如何判断数据类型:arr --> Array null --> Null
   * 1.typeof返回的数据类型:String, Number, Boolean, Undefined, Object, Function
   * 2.Object.prototype.toString.call(this)
   */
  let result= 'abcd';
  result = null;
  result = [1, 3];
  console.log(Object.prototype.toString.call(result).slice(8, -1));

  // for in循环,对象(属性名) 数组(下标)
  let obj6 = {username: 'kobe', age: 39};
  for (let i in obj6){
      console.log(i);
  }
  let arr6 = [1, 3, 'abc'];
  for (let i in arr6){
      console.log(i);
  }

实现深度克隆:

  // 定义检测数据类型的功能函数
  function checkType(target){
      return Object.prototype.toString.call(target).slice(8, -1);
  }
  // 实现深度克隆 --> 对象/数组
  function clone(target){
      // 判断拷贝的数据类型
      // 初始化变量result成为最终克隆的数据
      let result, targetType = checkType(target);
      if(targetType === 'Object'){
          result = {};
      }else if(targetType === 'Array'){
          result = [];
      }else{
          return target;
      }

      // 遍历目标数据
      for(let i in target){
          // 获取遍历数据结构的每一项值
          let value = target[i];
          // 判断目标结构里的每一项值是否存在对象/数组
          if(checkType(value) === 'Object' || checkType(value) === 'Array'){// 对象/数组里嵌套了对象/数组
              // 继续遍历获取到的value值
              result[i] = clone(value);
          }else{// 获取到的value值是基本的数据类型或函数
              result[i] = value;
          }
      }
      return result;
  }
  let arr7 = [1, 2, {username: 'kobe', age:39}];
  let arr8 = clone(arr7);
  console.log(arr8);
  arr8[2].username = 'wade';
  console.log(arr7, arr8);

  let obj7 = {username: 'kobe', age: 39};
  let obj8 = clone(obj7);
  console.log(obj8);
  obj8.username = 'wade';
  console.log(obj7, obj8);

Set和Map

1. Set容器 : 无序不可重复的多个value的集合体
  * Set()
  * Set(array)
  * add(value)
  * delete(value)
  * has(value)
  * clear()
  * size
2. Map容器 : 无序的 key不重复的多个key-value的集合体
  * Map()
  * Map(array)
  * set(key, value)//添加
  * get(key)
  * delete(key)
  * has(key)
  * clear()
  * size

示例代码:

  let set = new Set([1,2,4,5,2,3,6]);
  console.log(set);
  set.add(7);
  console.log(set.size, set);
  console.log(set.has(8));// false
  console.log(set.has(7));// true
  set.delete(4);
  console.log(set);
  set.clear();
  console.log(set);

  let map = new Map([['username', 'kobe'], [36, 'age']]);
  console.log(map);
  map.set(78, 'haha');
  console.log(map);
  map.delete(36);
  console.log(map);
  console.log(map.size);

for of循环

for(let value of target){}循环遍历
  1. 遍历数组
  2. 遍历Set
  3. 遍历Map
  4. 遍历字符串
  5. 遍历伪数组

示例代码:

  // 数组去重
  let arr = [1,2,4,5,5,6,2];
  let arr1 = arr;
  arr = [];
  let set = new Set(arr1);
  for (let i of set){
      arr.push(i);
  }
  console.log(arr);

  // 遍历伪数组
  let btns = document.getElementsByTagName('button');
  for(let i of btns){
      console.log(i);
  }

ES7

1. 指数运算符(幂): **
2. Array.prototype.includes(value) : 判断数组中是否包含指定value

示例代码:

  console.log(3 ** 3);// 27
  let arr = [1,4,5,6,'abc'];
  console.log(arr.includes(6));// true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值