美文网首页
2018-04-21 js 面向对象精要 ------ 总结

2018-04-21 js 面向对象精要 ------ 总结

作者: 阳乃橘 | 来源:发表于2018-04-22 19:17 被阅读0次

    前两天看完了 js 面向对象精要, 有所收获, 因此趁热打铁做一下记录. 这本书很薄, 只用了两天午休的时间就看完了, 但作者的讲述是十分清晰的.

    引用类型和原始类型

    js 中的数据, 要么是一个对象, 要么从一个对象中获取

    原始类型
    1. 原始类型直接保存值, 引用类型保存指向内存的指针
    2. 用原始类型给变量赋值时, 值会直接被赋值到改变量中
    3. 对于原始类型, 用 typeof 函数
    4. 原始类型拥有方法, 但它们不是对象, js 使它们用起来像对象, 是为了提供语言上的一致性体验.
    引用类型(对象)

    创建对象

    1. 构造函数和 new 操作符
    2. 使用字面量

    内建类型

    1. 六种内建类型
    2. 鉴别引用类型使用 instanceof 函数
    3. 所有类型都继承自 Object
    4. 使用 Array.isArray 鉴别数组. 由于不同框架会实现不同的 Array 实例.

    原始封装类型
    String, Number, Boolean

    • 每当读取字符串, 数字或布尔值时, 原始封装对象会自动创建
    • 原始封装对象仅存在于该语句
    • 语句执行完成后会自动销毁所创建的原始封装对象

    函数

    函数也是一个对象, 内部独有一个 [[call]] 属性, 表明该对象可以被执行.

    两种定义方式:

    var a = function() {
    }
    
    // 这种写法会有声明提升, 函数定义会被提升到上下文的顶部
    function a() {
    }
    
    函数的参数
    1. 保存在 arguments 对象中(这个对象的行为表现类似于数组)
    2. arguments 不是 Array 的实例
    3. arguments.length 表示期望的参数的长度
    4. js 不存在函数重载, 但可以根据 arguments 的状态去模拟
    this 对象
    1. js 的每个函数的作用域中都有一个 this 对象, 代表 调用改函数的对象
    2. 改变 this 指向的三种方法
      • call(target, param1, param2, ...)
      • apply(target, [params...])
      • bind(target, 其余参数会被设为新函数中的命名参数)

    理解对象

    1. 属性第一次被添加给对象时, js 在对象上调用一个名为 [[put]] 的内部方法
    2. 调用 [[put]] 方法在对象上创建了自有属性
    3. 对已有属性赋新值时, 调用了内部的 [[set]] 方法
    4. 使用 in 操作符判断属性是否存在于方法中, 其实就是在 hashtable 中查找一个键是否存在. in 操作符会检查自由属性和原型属性
    5. delete 删除一个属性, 其实是调用了内部的 [[delete]] 方法
    属性枚举
    1. [[Enumerable]] 属性表示属性是否可枚举
    2. 使用 for-in 循环枚举一个对象的可枚举属性
    3. Object.keys() 得到一个对象的所有可枚举自有属性的名称数组.
    属性类型

    数据属性和访问器属性

    • 数据属性包含值
    • 访问器属性不包含值, 包含 setter 和 getter 两个函数
    • 只定义 getter 就是只读
    • [[Configureable]] 决定该属性是否可配置, 手动声明的所有默认属性都是可枚举, 可配置的
    • 可以用 Object.defineProperty() 方法改变属性特征. 需要为所有特征指定一个值, 否则布尔值类型的特征会被默认设置为 false.
    • 无法将不可配置的属性变成可配置的.
    • 数据属性有一个 [[value]] 属性, 里面保存了值. 还有一个 [[writable]] 表示是否可写.
    • 访问器属性也有两个额外特征, [[get]] 和 [[set]]
    • 定义多重属性使用 Object.defineProperties() 函数
    • Object.getOwnPropertyDescriptor() 方法获取属性的特征
    • [[extensible]] 是否可修改, false 时表示不可修改, 无法添加新属性
    • Object.preventExtensions() 创建一个不可扩展的对象
    • Object.isExtensible() 方法检查 [[extensible]] 的值
    • Object.seal() 方法创建一个封印的对象, [[extensible]] 为 false, 所有属性的 [[Configureable]] 也是 false
    • Object.isSealed() 方法判断一个对象是否被封印
    • Object.freeze() 方法冻结一个对象. 改对象是一个所有属性都是只读的 sealed 对象
    • Object.isFrozen() 判断是否被冻结

    构造函数和原型函数

    构造函数就是你用 new 创建对象时调用的函数, 所有使用同一个构造函数创建的对象都有相同的属性和方法

    • 与普通函数的区别: 首字母大写
    • 调用构造函数时, new 关键字会自动创建 this 对象, 且类型就是构造函数的类型.
    • 也可以在构造函数中显式 return, 如果 return 的是对象, 则返回该对象实例; 如果是原始值, 会被忽略, 返回的依旧是对象实例.
    • 忘记用 new 调用构造函数时, this 是 window
    原型对象

    几乎所有函数都有 prototype 属性, 所有创建的实例都共享原型对象, 且可以访问到原型对象的属性.

    • 鉴别一个属性是否是原型对象的属性:
    var hasPrototypeProperty(object, name) {
      var result = (name in object) && !(Object.hasOwnProperty(name))
      return result
    }
    
    • 对象实例通过 [[prototype]] 跟踪其原型对象
    • 当 new 一个对象时, 构造函数的原型对象会被赋值给该对象的 [[prototype]] 属性
    • 可以使用 Object.getPrototypeOf() 方法读取 [[prototype]] 属性的值
    • 对于所有的泛用对象, 其 [[prototype]] 属性始终指向 Object.prototype
    • 使用 _proto_ 属性可直接读写 [[prototype]] 属性.
    • 原型属性无法赋值
    • 可以直接用字面量替换原型对象, 但需要注意的是 constructor 属性需要手动替换, 不指定的话默认是指向 Object
    • 可以给内建对象的 prototype 增加方法, 但不推荐, 因为可能会误导其他程序员

    继承

    js 中的继承是通过原型对象链继承的.

    对象通常都继承自 Object.prototype, 因此也都有一下方法:

    
    hasOwnProperty()
    
    properTyIsEnumerable()
    
    isPrototypeOf()
    
    // 当一个操作符作用于一个对象时, 就会调用 valueOf() 方法
    // 原始封装类型重写了该方法, 使 String 有不同的表现形式
    valueOf()
    
    // 当 valueOf 方法返回的是一个引用时, 就会调用 toString 方法
    toString()
    
    对象的继承
    • 只需要指定哪个对象是新对象的 [[prototype]], 也可以用 Object.create() 方法显式创建
    • 所有继承链的末端通常是 Object.prototype, 其 [[prototype]] 为 null
    • 访问父类方法时, 使用 call 或 apply 指定 this
    对象模式

    私有成员:

    1. 通过 _name 来约束
    2. 通过立即函数来返回对象
    3. 通过闭包返回对象, 在闭包内调用外部的变量(模块模式)

    混入:
    一个对象在不改变原型对象链的情况下, 得到了另一个对象的属性和方法, 被称为混入
    混入的实现:

    1. 使用 for-in 浅拷贝
    2. 使用 foreach 实现 mixin 函数
    var mixin = function(receiver, supplier) {
      Object.keys(supplier).forEach(function(property) {
        var descriptor = Object.getOwnPropertyDescriptor(supplier, property)  
        Object.defineProperty(receiver, property, descriptor)
        return receiver
      })
    }
    
    作用域安全的构造函数

    在函数内判断自己是否被 new 调用, 处理不同的情况

    相关文章

      网友评论

          本文标题:2018-04-21 js 面向对象精要 ------ 总结

          本文链接:https://www.haomeiwen.com/subject/gugxlftx.html