设为首页 加入收藏

TOP

深入 JavaScript 中的对象以及继承原理(一)
2019-09-17 19:00:42 】 浏览:72
Tags:深入 JavaScript 对象 以及 继承 原理

ES6引入了一个很甜的语法糖就是 class, class 可以帮助开发者回归到 Java 时代的面向对象编程而不是 ES5 中被诟病的面向原型编程. 我也在工作的业务代码中大量的使用 class, 很少去触及 prototype 了.

两面性:

  1. class 语法糖的本质还是prototype, 所以应该回归到写 prototype 上.

  2. 既然有 class 的写法了, 而且继承上也相比原型好写, 好理解许多, 所以应该向前看, 摒弃掉以前的 prototype 写法.

睿智而理性的读者, 你的理解是其中之一还是二者兼备? 我的看法是: 语法糖存在即合理, 语法糖不仅仅是更高层级的封装, 它可以避免写出没有语法糖时候的 bug, 但是语法糖不是语言本身的特性, 所以也一定要理解背后的成因, 加上原型是 java script 里面特别特别重要的知识点, 不能不去深究. 你可以不用, 但不能不懂.

好了, 来看看 ES5 的面向对象编程

什么是对象

ECMA的官方解释: 无序属性的集合, 属性可包括基本值, 函数, 对象

注意无序二字, 可理解为包含一定属性或方法的键值对. 是的, 本质上, 对象就是包含键值对映射的集合, 键是属性的名字, 值就是属性

属性的类型

  1. 数据属性

    • configurable
      • 表示是否可以被配置(除了 enumerable 和 writable 之外), 包含但不限于属性属性转化为访问器属性, 主要是用于 delete 的限制
    • enumerable
      • 是否可以被 for in 或 Object.keys 到
    • value
      • 属性具体的值, 默认 undefined
    • writable
      • 可修改 value
  2. 访问器属性

    • configurable
      • 表示是否可以被配置(除了 enumerable 和 writable 之外), 包含但不限于属性属性转化为访问器属性, 主要是用于 delete 的限制
    • enumerable
      • 是否可以被 for in 或 Object.keys 到
    • get
      • 获取属性的值, 默认 undefined
    • set
      • 设置属性的值, 默认 undefined

注意, 第二个访问器属性就是被著名的 React 和 Vue 实现数据响应的原理之一. 再注意, 以上所有的 bool 属性在没有进行配置的时候都默认为 false.

如何实现这两者的转化呢

在 configurable 为 true 的情况下, 凡是包含 value 或 writable 的会默认为数据属性, 会将原有的 get 和 set 属性删除, 反之如果设置了 get 或 set, 那么就会认为为访问器属性, 将 value 和 writable 删除

const  o = {}
Object.defineProperty(o, 'name', {
    configurable: true,
    enumerable: false, // 可不写, 默认为 false
    value: 'lorry',
    writable: false // 可不写, 默认为 false
})
console.log(o)//{name: "lorry"}
o.name = 'jiang'// 不会改变, 因为 writable 为 false
console.log(o)//{name: "lorry"}
Object.keys(o)// []
// 转化为访问器属性
o['_name'] = 'lorry'; // 设置私有属性
Object.defineProperty(o, 'name', {
    get: function(){return this._name},
    set: function(newName){this._name = newName},
    configurable: false,
    enumerable: true
})
console.log(o); // {_name: "lorry"}
o.name = 'setted jiang'
console.log(o.name); // setted jiang
Object.keys(o); // ["_name", "name"]

其他的方式

除了Object.defineProperty之外, 还有其他的跟对象属性相关的原生方法

  • Object.defineProperties(o, {attr1:{}, attr2:{}}), 批量设置一个对象多个属性

  • Object.getOwnPropertyDescriptor(o, attrName), 获取对象某个属性的配置

  • Object.getOwnPropertyDescriptors(o), 获取对象所有属性的配置

对象的创建

工厂模式

function createObject(name) {
    var o = new Object();
    o.name = name;
    o.sayName = function() {console.log(this.name)};
    return o;
}

const p1 = createObject('lorry')

优点: 简单直观 缺点: 无法进行对象识别, 没有 instanceof 可以去追溯.

构造函数模式

function Person(name) {
    this.name = name;
    this.sayName = function() {console.log(this.name)};
}
const p1 = new Person('lorry')

注意, 凡是构造函数都应该首字母大写 优点:

  • 不显式创建对象(实质还是有创建新对象)

  • 使用 this 的上下文对象

  • 不用 return(默认隐式创建的新对象)

  • 能够使用 p1 instanceof Person进行对象识别

缺点:

  • 每个实例都会生成新的属性和方法, 会造成内存的浪费(在当今性能过剩的年代, 这个实质上不算什么问题, 只是显得代码不是很规范和专业)

原型模式

function Person() {};
Person.prototype.name = 'Lorry';
Person.prototype.sayName = function() {
    console.log(this.name);
}
const p1 = new Person();
const p2 = new Person();
p1.sayName(); // lorry;
console.log(p1.sayName === p2.sayName) // true

可以看到两个实例p1 和 p2 共享同一个 name 属性和 sayName 的方法, 会节省内存.

注意, 在原型上的方法和属性是不会被 hasOwnProperty()检测出来的(Object.keys()同样如此), 但是在in中是有的.比如

p1.hasOwnProperty('name'); // false
Object.keys(p1); // []
'name' in p1; // true

一种更简单的定义方法

function Person(){};
Person.prototype = {
    name: 'lorry',
    sayName: function(){
        console.log(this.name)
    },
    //ES6
    sayName2() {
        console.log(this.na
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇bootstrap datatable editor 扩展 下一篇localStorage&sessionStorage&Coo..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目