JavaScript对象高级|青训营笔记

59 阅读9分钟

这是我参与「第四届青训营 」笔记创作活动的的第10天

1. 对象的创建模式

1). Object构造函数模式

var obj = new Object()
obj.name = 'Tom'
obj.setName = function(name){this.name=name}

2). 对象字面量模式

var obj = {
    name : 'Tom',
    setName : function(name){this.name = name}
}

3). 工厂函数模式

// 工厂函数: 返回一个需要的数据的函数
  function Person(name, age) {
    return {
      name: name,
      age: age
    }
  }
  var person1 = Person('kobe', 43);

4). 自定义构造函数模式

function Person(name, age) {
    this.name = name
    this.age = age
    this.setName = function(name){this.name=name}
}
var person1 = new Person('tom', 12)

5). 构造函数+原型的组合模式

function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.setName = function(name){this.name=name}
var person1 = new Person('tom', 12)

2. 继承模式

1). 原型链继承 : 得到方法

  function Person(name, age) {  
    this.name = name;
    this.age = age;
  }
  Person.prototype.showName = function () {
    console.log(this.name);
  }
​
  // 原型继承: 子类的原型 成为 父类的实例
  // Child.prototype = {constructor: Child}
  Child.prototype = new Person();
  Child.prototype.constructor = Child;     // 要手动加上原型的constructor属性
  // 定义一个child类
  function Child(name, age) {
    this.name = name;
    this.age = age;
  }
  
  var child1 = new Child('xiaoming', 18);

2). 借用构造函数继承 : 得到属性

function Parent(xxx){this.xxx = xxx}
Parent.prototype.test = function(){}
function Child(xxx,yyy){
  Parent.call(this, xxx) //借用父类型的构造函数 
}
var child = new Child('a', 'b')  //child.xxx为'a', 但child没有test()

3). 组合继承

function Parent(xxx){this.xxx = xxx}
Parent.prototype.test = function(){}
function Child(xxx,yyy){
  Parent.call(this, xxx) //借用构造函数   this.Parent(xxx)
}
Child.prototype = new Parent() //得到test()
Child.proptotype.constructor = Child
var child = new Child() //child.xxx为'a', 也有test()

3. 理解

1). 定义一个函数背后做了什么?

创建一个Function的实例对象
给对象添加prototype属性, 其值为object空对象(原型对象)
给原型对象添加constructor属性, 指向当前函数对象

2). new一个对象背后做了些什么?

创建一个新的空对象
给对象设置__proto__, 值为构造函数对象的prototype属性值
通过对象执行构造函数体(给对象添加属性/方法)

1. 线程与进程

1). 进程:

程序的一次执行, 它占有一片独有的内存空间
可以通过windows任务管理器查看进程

2). 线程:

是进程内的一个独立执行单元
是程序执行的一个完整流程
是CPU的最小的调度单元

3). 关系

一个进程至少有一个线程(主)
程序是在某个进程中的某个线程执行的

2. 浏览器内核模块组成

1). 主线程

js引擎模块 : 负责js程序的编译与运行
html,css文档解析模块 : 负责页面文本的解析
DOM/CSS模块 : 负责dom/css在内存中的相关处理 
布局和渲染模块 : 负责页面的布局和效果的绘制(内存中的对象)

2). 分线程

定时器模块 : 负责定时器的管理
事件响应模块 : 负责事件的管理
网络请求模块 : 负责Ajax请求

3). js线程

js是单线程执行的(回调函数也是在主线程)
H5提出了实现多线程的方案: Web Workers   --->var worker = new Worker('./work.js');
只能是主线程更新界面

3. 定时器问题:

定时器并不真正完全定时
如果在主线程执行了一个长时间的操作, 可能导致延时才处理

4. 事件循环机制

img

1). 代码分类

初始化执行代码: 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
回调执行代码: 处理回调逻辑

2). js引擎执行代码的基本流程:

初始化代码===>回调代码

3). 模型的2个重要组成部分:

事件管理模块
回调队列 (callback queue)

4). 模型的运转流程

执行初始化代码, 将事件回调函数交给对应模块管理
当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行

理解ES

  1. 全称: ECMAScript
  2. js语言的规范
  3. 我们用的js是它的实现
  4. js的组成
  • ECMAScript(js基础)

  • 扩展-->浏览器端

    • BOM
    • DOM
  • 扩展-->服务器端

    • Node.js

ES5

  1. 严格模式
  • 运行模式: 正常(混杂)模式与严格模式

  • 应用上严格式: 'strict mode';

  • 作用:

    • 使得Javascript在更严格的条件下运行

    • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为

    • 消除代码运行的一些不安全之处,保证代码运行的安全

    • 需要记住的几个变化

      • 声明定义变量必须用var
      • 禁止自定义的函数中的this关键字指向全局对象
      • 创建eval作用域, 更安全
  1. JSON对象
  • 作用: 用于在json对象/数组与js对象/数组相互转换
  • JSON.stringify(obj/arr) js对象(数组)转换为json对象(数组)
  • JSON.parse(json) json对象(数组)转换为js对象(数组)
  1. Object扩展
  • Object.create(prototype[, descriptors]) : 创建一个新的对象

    • 以指定对象为原型创建新的对象

    • 指定新的属性, 并对属性进行描述

      • value : 指定值
      • writable : 标识当前属性值是否是可修改的, 默认为true
      • get方法 : 用来得到当前属性值的回调函数
      • set方法 : 用来监视当前属性值变化的回调函数
  • Object.defineProperties(object, descriptors) : 为指定对象定义扩展多个属性

  1. Array扩展
  • Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
  • Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
  • Array.prototype.forEach(function(item, index){}) : 遍历数组
  • Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组
  • Array.prototype.filter(function(item, index){}) : 遍历过滤出一个子数组
  1. Function扩展
  • Function.prototype.bind(obj)

    • 将函数内的this绑定为obj, 并将函数返回
  • 面试题: 区别bind()与call()和apply()?

    • fn.bind(obj) : 指定函数中的this, 并返回函数
    • fn.call(obj) : 指定函数中的this,并调用函数
  1. Date扩展
  • Date.now() : 得到当前时间值

ES6

  1. 2个新的关键字
  • let/const
  • 块作用域
  • 没有变量提升(不准确)
  • 不能重复定义
  • 值不可变
  • let

    • 作用:同var一样用来声明变量

    • 变量提升:

      • 全局变量提升

        • 会创建一个变量对象(script)用来收集全局作用域下let定义的变量,但是没有赋值
      • 局部变量提升

        • 会将var let定义的变量全部放到当前函数的变量对象中
      • 同var的变量提升的区别

        • let提升的变量在未赋值之前不允许被使用
  • const

    • 作用:定有常量
    • 特点:定义的常量不可以被修改
  1. 变量的解构赋值

    • 将包含多个数据的对象(数组)一次赋值给多个变量
    • 数据源: 对象/数组
    • 目标: {a, b}/[a, b]
  2. 各种数据类型的扩展

  • 字符串

    • 模板字符串

      • 作用: 简化字符串的拼接
      • 模板字符串必须用``
      • 变化的部分使用${xxx}定义
    • contains(str) : 判断是否包含指定的字符串

    • startsWith(str) : 判断是否以指定字符串开头

    • endsWith(str) : 判断是否以指定字符串结尾

    • repeat(count) : 重复指定次数

  • 对象

    • 简化的对象写法

      let name = 'Tom';
      let age = 12;
      let person = {
          name,
          age,
          setName (name) {
              this.name = name;
          }
      };
      
    • Object.assign(target, source1, source2..) : 将源对象的属性复制到目标对象上

    • Object.is(v1, v2) : 判断2个数据是否完全相等

    • proto属性 : 隐式原型属性

  • 数组

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

    • 箭头函数

      • 用来定义匿名函数

      • 基本语法:

        • 没有参数: () => console.log('xxxx')
        • 一个参数: i => i+2
        • 大于一个参数: (i,j) => i+j
        • 函数体不用大括号: 默认返回结果
        • 函数体如果有多个语句, 需要用{}包围
      • 使用场景: 多用来定义回调函数

      • 特点:

        • this:箭头函数没有自己的this,不是调用的时候决定的,而是定义的时候决定的
        • 理解: - 看定义的时候外部是否有函数,如果有当前箭头函数的this同外部函数的this指向是同一个对象 - 如果没有,箭头函数this指向的是window
        • 箭头函数不能用作构造函数
    • 形参的默认值

      • 定义形参时指定其默认的值
    • 三点运算符

      • rest(可变)参数

        1. 通过形参左侧的...来表达, 取代arguments的使用
        2. 它比arguments更加灵活
        3. 同样是来收集函数的实参列表
        4. 使用三点运算符收集的是一个真数组
        5. 可以根据需求收集指定的参数
      • 扩展运算符(拆包)

        • 语法:...arr
        • 作用:可以分解出数组中的数据
        • 原理:三点运算符会调用iterator接口,如果底层有这个接口,那就可以去遍历数组
  • Symbol

    1. 理解:ES6提供的一种新的数据类型
    2. 基本数据类型:string, number, boolean, undefined, null, symbol,
    3. typeof返回值:number, string, boolean, undefined, object, function, symbol
    4. symbol特点:值是唯一的
  1. iterator遍历器对象

    function iteratorUtil() { // iterator接口 : 方法 || api
        console.log('我的方法被调用了', this); // this是遍历的目标数组或目标对象
        // console.log(target);// undefined
        // 缓存this
        let that = this;
        let index = 0; //  标识指针的起始位置
        let keys = Object.keys(that);// 获取对象中所有key的数组
        if(this instanceof Array){ // 遍历数组
          return { // 生成iterator遍历器对象
            next:  function (){ // 可以使用箭头函数解决this的指向问题
              return index < that.length ? {value: that[index++], done: false} : {value: that[index++], done:                   true}
            }
          }
        }else {// 遍历对象
          return { // 生成iterator遍历器对象
            next:  function (){ // 可以使用箭头函数解决this的指向问题
              return index < keys.length?{value: that[keys[index++]], done: false}:{value:                                  that[keys[index++]], done: true}
            }
          }
        }
      }
    ​
      Array.prototype[Symbol.iterator] = iteratorUtil;
      Object.prototype[Symbol.iterator] = iteratorUtil;
    
  2. set/Map容器结构

  • 容器: 能保存多个数据的对象, 同时必须具备操作内部数据的方法

  • 任意对象都可以作为容器使用, 但有的对象不太适合作为容器使用(如函数)

  • Set的特点: 保存多个value, value是不重复 ====>数组元素去重

  • Map的特点: 保存多个key--value, key是不重复, value是可以重复的

  • API

    • Set()/Set(arr) //arr是一维数组
    • add(value)
    • delete(value)
    • clear();
    • has(value)
    • size
    • Map()/Map(arr) //arr是二维数组
    • set(key, value)
    • get(key)
    • clear()
    • has(key)
    • size
  1. for--of循环
  • 可以遍历任何容器
  • 数组
  • 伪/类数组
  • 字符串
  • 可迭代的对象
  1. Promise
  • 解决回调地狱(回调函数的层层嵌套, 编码是不断向右扩展, 阅读性很差)

  • 能以同步编码的方式实现异步调用

  • 在es6之前原生的js中是没这种实现的, 一些第三方框架(jQuery)实现了promise

  • ES6中定义实现API:

    // 1. 创建promise对象
    var promise = new Promise(function(resolve, reject){ 
      // 做异步的操作 
      if(成功) { // 调用成功的回调
        resolve(result); 
      } else { // 调用失败的回调
        reject(errorMsg); 
      } 
    }) 
    // 2. 调用promise对象的then()
    promise.then(function(
      result => console.log(result), 
      errorMsg => alert(errorMsg)
    ))
    
  1. class类
  • 用 class 定义一类
  • 用 constructor() 定义构造方法(相当于构造函数)
  • 一般方法: xxx () {}
  • 用extends来定义子类
  • 用super()来继承父类的构造方法
  • 子类方法自定义: 将从父类中继承来的方法重新实现一遍
  • js中没有方法重载(方法名相同, 但参数不同)的语法
  1. 模块化(后面讲)

ES7

  • 指数运算符: **

  • Array.prototype.includes(value) : 判断数组中是否包含指定value

  • 区别方法的2种称谓

    • 静态(工具)方法

      • Fun.xxx = function(){}
    • 实例方法

      • 所有实例对象 : Fun.prototype.xxx = function(){} //xxx针对Fun的所有实例对象
      • 某个实例对象 : fun.xxx = function(){} //xxx只是针对fun对象