Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(五)javascript高级程序设计: 面向对象 #5

Open
4 tasks done
Quickeryi opened this issue Jun 9, 2017 · 0 comments
Open
4 tasks done

(五)javascript高级程序设计: 面向对象 #5

Quickeryi opened this issue Jun 9, 2017 · 0 comments

Comments

@Quickeryi
Copy link
Owner

Quickeryi commented Jun 9, 2017

本文记录一下javascript中最神秘的概念:面向对象

一切皆对象 👍

  • 数据属性
# 数据拥有以下四个内部属性
[[configurable]]:默认为true,当false => 属性不可delete,也不可修改下列其他内部属性
[[writable]]:默认为true
[[enumerable]]:默认为true
[[value]]:默认为undefined

#demo
var person = {};
Object.defineProperty(person, 'age', {
    configurable: false,
    value: 1
});
person.age; // 1
delete person.age;
person.age; // 1
  • 访问器属性
# 访问器拥有以下四个内部属性
[[configurable]]:默认为true,当false => 属性不可delete,也不可修改下列其他内部属性
[[writable]]:默认为true
[[getter]]:默认为undefined,没有这个属性,属性不可读
[[setter]]:默认为undefined,没有这个属性,属性不可写
  • 构造对象
#深入浅出构造函数
function Person(name) {
   this.name = name;
}
var person = new Person('tom');
// 问题:构造函数并没有返回值,为何使用new 操作符就可以创建一个实例,并且指向Person.prototype,这中间到底经历了什么?
#分析
new Person('tom') => {
    var _obj_ = {};
    _obj_.__proto__ = Person.prototype; // 原型链建立 => _obj_ instanceof Person => true
    var obj = Person.call(_obj_, 'tom');
    //  这里注意:一般来讲构造函数是没有返回值的,如果无返回值或者返回一个非对象值,则将_obj_返回作为新对象;否则会将返回值作为新对象返回
    return typeof obj === 'object' ? obj : _obj_;
}

#构造函数缺点:由于每一个函数都是一个对象(new Function()),所以每一个实例的方法都是一个独立的实例,这违背了面向对象思想

# in 操作符:只要属性可以通过对象访问到(自身或原型链)就返回true
# for..in:返回自身或原型链上的可枚举属性
# keys: 返回自身的可枚举属性
# getOwnPropertyNames:返回自身所有属性

# 动态原型模式
function  Person(name) {
    this.name = name;
    if (typeof this.sayName != "function") { // 初次调用构造函数才会调用
       Person.prototype.sayName = function () {
          //...
       }
    }
}

# 稳妥构造函数模式
  - 稳妥对象:没有公共属性,其方法也不能使用this,适用于一些安全环境
  - demo
    function  Person(name) {
         var o = new Object();
         o.getName = function () { // 特点:除了方法外,无法通过其他方式获取到name值
            return name;
         };
         return o;
    }

理解JS中的new运算符

  • 继承
# 原型链继承解析
function Super() {
    this.colors = ['red', 'blue']
}
function Sub() {}
// 等价于 Sub.prototype = Object.create(Super.prototype);
Sub.prototype = new Super(); // 此时Sub.prototype.__proto__ => Super.prototype; 
var instance = new Sub(); // instance.__proto__ => Sub.prototype
instance instanceof Super; // true <= instance.__proto__.__proto__ === Super.prototype

# 确定原型和实例之间的关系
instanceof 
isPrototypeOf()

# 原型链继承的问题
 - 引用类型属性公用:上述代码中Super类中定义了一个colors的数组,这会造成所有Sub的实例公用 => 因为继承后,Sub.prototype变成了Super的一个实例了,所以colors此时挂载在Sub.prototype上,导致所有的Sub实例公用
 - 创建子类实例时,无法像ES6一样,调用超类构造函数
 - 鉴于上述两点缺点(很致命的缺点),一般不会单独使用原型链继承方式

# 组合继承:原型链 + 借用构造函数(在子类中调用父类构造函数)
- 缺点:调用两次父类构造函数
function Super(name) {
    this.name = name;
    this.colors = ['red', 'blue'];
}
Super.prototype.sayName = function () {
     return this.name;
}

function Sub(name, age) {
    Super.call(this, name);  // 第二次
    this.age = age;
}
Sub.prototype = new Super(); // 第一次
Sub.prototype.sayAge = function () {
     return this.age;
}

# Object.create等价于下面操作
function object(o, properties) {
   function F() {};
   F.prototype = o;
   var  _obj_ = new F();
   Object.defineProperties(_obj_, properties);
   return _obj_;
}

# 寄生组合继承(最好的方式)解决了组合继承调用两次构造函数的缺点
   - 寄生组合继承:通过构造函数继承属性,通过原型链混成形式继承方法
   - 思路:不必为了指定子类型的原型,而调用父类型的构造方法(即:Sub.prototype = new Super()
   - demo
   function object(o) {
      function F() {};
      F.prototype = o;
      return new F();
   }
   
   function Extends(sub, sup) {
       var prototype = object(sup.prototype);
       prototype.constructor = sub; // 增强对象
       sub.prototype = prototype;
   }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant