理解对象

对象包含数据属性和访问器属性,通过Object.defineProperty()函数定义
数据属性为设置属性的设置(删除、循环、是否可修改和默认值)
访问器属性为设置属性值的设置(删除、循环、读取和写入的函数)

数据属性

  1. configurable:能否使用delete删除属性。默认为true
  2. enumerable:能否使用for-in循环返回属性。默认为true
  3. writable:能否修改该属性。默认为true
  4. value: 读取写入属性值,默认undefined

    1. var person = {};
    2. Object.defineProperty(person, "name", {
    3. writable: false,
    4. value: "Nicholas"
    5. });
    6. alert(person.name); //"Nicholas"
    7. person.name = "Greg";
    8. alert(person.name); //"Nicholas"

    访问器属性

  5. configurable:能否使用delete删除属性。默认为true

  6. enumerable:能否使用for-in循环返回属性。默认为true
  7. get:读取属性时调用的函数,默认undefined
  8. set:写入属性时调用的函数,默认undefined ```javascript var book = { _year: 2004,
    1. edition: 1
    }; // 定义单个属性 Object.defineProperty(book, “year”, { get: function(){
     return this._year;
    
    }, set: function(newValue){
     if (newValue > 2004) {
         this._year = newValue;
         this.edition += newValue - 2004;
     } 
    
    } }); book.year = 2005; alert(book.edition); //2

//定义多个属性 Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004 } } } }) // 读取属性的特性 var descriptor = Object.getOwnPropertyDescriptor(book, “year”); alert(descriptor.value); //undefined alert(descriptor.enumerable); //false alert(typeof descriptor.get); //“function”

<a name="eY2gw"></a>
## 创建对象
<a name="fV1nN"></a>
### 工厂模式
```javascript
function createPerson(name, age, job){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
      alert(this.name);
  };
    return o; 
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
// 只解决了创建多个相似对象的问题,没有解决对象识别的问题

构造函数模式

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function(){
      alert(this.name);
    }; 
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
//上述构造函数创建的每一个实例都包含一个不同的function实例

原型模式

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
person1.sayName();   //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName);  //true
//省略了参数初始化的环节,所有实例共享原型对象的属性值。实例会修改原型中的值,影响其他实例

组合使用构造函数和原型模式

function Person(name, age, job){
  this.name = name; 3 this.age = age;
  this.job = job;
  this.friends = ["Shelby", "Court"];
}
Person.prototype = {
  constructor : Person,
  sayName : function(){
    alert(this.name);
  }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Count,Van"
alert(person2.friends);    //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

动态原型模式

function Person(name, age, job){
    this.name = name; 
  this.age = age; 
  this.job = job;
  if (typeof this.sayName != "function"){
      Person.prototype.sayName = function(){
      alert(this.name);
        }; 
  }
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();

稳妥构造函数模式

function Person(name, age, job){
  var o = new Object();
  //定义私有变量和函数
  o.sayName = function(){
    alert(name)
  };
  return o;
}

继承

原型链

image.png

var obj = new Object();
// 对象是有原型对象的   原型对象也有原型对象 
obj._proto_._proto_._proto_
// 原型对象也有原型对象,对象的原型对象一直往上找,会找到一个null
// 原型链示例
var arr = [];
arr -> Array.prototype ->Object.prototype -> null
var o = new Object();
o -> Object.prototype -> null;

image.png
实例对象的proto指向构造函数的prototype
构造函数的constructor指向实例对象

function SuperType(){
    this.property = true;
}
function SubType(){
    this.subproperty = false;
}
SubType.prototype = new SuperType();
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
      2、继承单一。
      3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

构造函数继承

function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
   2、解决了原型链继承缺点1、2、3。
   3、可以继承多个构造函数属性(call多个)。
   4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
 2、无法实现构造函数的复用。(每次用每次都要重新调用)
 3、每个新实例都有父类构造函数的副本,臃肿。

组合继承

function Person(name){
    this.name = name;
}
Person.prototype.showName = function(){
    console.log(this.name);
}
function Student(name,age){
    Person.call(this,name);
    this.age = age;
}
Student.prototype = new Person();
Student.prototype.contructor = Student;
Student.prototype.showAge = function(){
    console.log(this.age);
}
var stu = new Student('张三',12);
stu.showName();
stu.showAge();
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
   2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。

原型式继承

function object(o){
    function F(){}
  F.prototype = o;
    return new F(); 
}
var o = new Object()
var o1 = object(o)
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
 2、无法实现复用。(新实例属性都是后面添加的)

寄生式继承

function createAnother(original){ 
  var clone=object(original);
  clone.sayHi = function(){
      alert("hi");
  };
    return clone;
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。

寄生组合式继承(常用)

寄生:在函数内返回对象然后调用
组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
function inherit(fa,son) {
  let protoType = Object.create(fa.prototype)
  protoType.custructor = son
  son.prototype = protoType
}
inherit(SuperType,SubType)
SubType.prototype.sayAge = function(){
    alert(this.age);
};