js 面向对象学习(构造函数篇)

面向对象是无序属性的集合,其属性可以是对象,函数,基本值。每个对象都是基于引用类型创建的。
内部属性有两种:数据属性和访问器属性。
数据属性:configurable,Enumerable,Writable,Value
修改属性默认值用Object.defineProperty()

var person = {}
Object.defineProperty(person, "name", {
configurable: false,     // 配置此属性后,不能随便在进行更改。
writable: false,
value: "Nicholas"
})
alert(person.name)

访问器属性:
Configurable
Enumerable 是否能通过for-in
Get,Set

Object.defineProperty(book, "year", {
    get: function() {
    return this._year;
    },
    set: function() {
        if(newValue > 2004){
             this._year = newValue;
             this.edition += newValue - 2004;
        }
    }
})

读取属性的特性:getOwnPropertyDescriptor(book, "_year");

由于js没有类,所以用函数和对象实现。现在让我来介绍js的面向对象的发展历程:
如何创建类似与类的对象:
1.工厂模式:
这是一个较有名的模式
优点:实现了封装和分派
缺点:没有解决对象识别问题
例子:

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("Niclouse", 12, "Doctor");

 

此图显示对象是Object对象,并非Person对象。

2.构造函数模式:
优点:因为创建原型对象会创建constructor属性,该属性指向对象,所以可以获得对象类型。
缺点:1. 每个方法都要在每个实例上创建一遍。2. ECMAScript中的函数是对象,每定义一个方法,就是实例一个对象。
例子:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        alert(this.name);
    };
}

此图中指向Person类。(constructor)
var person1 = new Person("Nichlas", 29, "Software Engineer");
区别:1.没有显示创建对象。2.直接将属性和方法付给this对象。3.没有return。
注意:任何函数只要通过new来调用,就可以作为构造函数。
使用new的主要步骤:
1.创建一个对象。
2.将构造函数的作用域付给新对象(因此this就指向这个新对象)。
3.执行构造函数中的代码(为这个新对象添加属性)
4.返回新对象。

3.原型模式:

步骤:

1.创建一个函数,为函数创建prototype属性,该属性指向函数的原型对象。

2.原型对象自动获得constructor属性。指向包含prototype(构造函数)所在函数的指针。

3.构造函数实例化实例后,该实例拥有一个指针指向构造函数原型。

观察图片,查看原型模式联系图:
优点:所有实例共享它包含的属性方法。
缺点:1.不能通过对象实例重写原型的值。实例中重写只会屏蔽原型的值。

   2.省略了对构造函数传递参数

   3.若属性为引用类型,则实例都共享。因为都指向同一个引用对象

方法:Object.getPrototypeOf() 返回对象的原型。
hasOwnProperty() 检查属性是否存在于实例中。
delete()删除实例属性重而能访问原型.
例子:
方法1:

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指向Person类(constructor)

方法2:

function Person() {}        // 每创建一个函数自动创建prototype对象,自动获得constructor
var friend = new Person();
Person.prototype = {        // 重写了原型
    constructor: Person,    // 必须写constuctor,因为重写后,从constructor自动指向Object
    name: "Nicholas",
    age: 29,
    job: 'Software Engineer',
    sayName: function() {
        alert(this.name);
    }
}

 

此图中friend指向Person类。

4.组合构造函数模式和原型模式:(最广泛,认同度最高)

优点:1.可以传参数。2.可以有自己的属性的副本,也可以共享方法的引用,最大限度节省内存。
例子:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["CKJ"];
}
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);
alert(person2.firends);

5.动态原型模式:

这里略微提一下,他是将所有信息都封装在构造函数中,通过构造函数初始化原型。

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();

6.寄生构造函数:

特点:创建对象的代码封装在函数中
优点:因为用new,所以函数一定是构造函数,默认返回新对象实例;但函数中又有return,可以重写调用构造函数的返回值。
缺点:返回对象与构造函数或与构造函数的原型属性之间没有关系。
不能依赖instanceof来确定对象类型。
例子:

function Person(name, age, job){
    var o = Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");

 

此图中friend指向Object类

原文地址:https://www.cnblogs.com/Caikejia/p/3048456.html