js中对象和对象建立方法

这一次咱们来讲一说在JavaScript中常常会用到的一个复杂基本类型,对象,先从对象的属性讲起,再讲对象的建立方法,基本涵盖了建立对象的各类方法,你们一块儿学习呀~vue

 

1、对象es6

    要掌握对象的使用及继承,首先固然须要先理解它,接下来,将会对对象的属性类型进行一个整理编程

    一、什么是对象设计模式

    对象实际上是无序属性的集合,其属性能够包含基本值,对象或者函数,好比像下面这个例子就是一个person对象啦数组

var person = {
    name: "NIcholas",
    age: 29,
    sayName: function() {
        console.log(this.name);
    }
}

    从上面的例子咱们能够看到,对象能够是由属性和其相应的值构成,对象中能够包含函数,也能够包含其它对象浏览器

 

    二、属性类型安全

    在JavaScript中,其实有两种属性,包括数据属性和访问器属性app

    (1)数据属性函数

    数据属性包含一个数据值的位置,在这个位置能够读取和写入值,通常来讲,有4个描述其行为的特性:学习

    a、[[Configurable]]:表示可否经过delete删除属性从而从新定义属性,默认值为true

    b、[[Enumerable]]:表示可否经过for-in循环返回属性,默认值为true

    c、[[Writable]]:表示可否修改属性的值,默认值为true

    d、[[Value]]:包含这个属性的数据值,默认值为undefined

    通常来讲,数据属性都有本身的默认值,那么若是咱们要修改数据属性默认的特性,应该怎么办呢?这个时候就须要用到Object,defineProperty()方法啦,这个方法接收三个参数:属性所在的对象,属性的名字和一个描述对象,来看下面的例子

var person = {};
Object.defineProperty(person, "name", {
    writable: false,
    value: "Nicholas"
});

console.log(person.name);  // Nicholas
// 从新赋值
person.name = "Greg";
console.log(person.name);  // Nicholas

    从上面的例子咱们能够看到,由于设置了person对象的name属性为不可修改,所以不管你在后面怎么修改person的name属性的值,name属性的值都不会发生改变

    (2)访问器属性

    访问器属性不包含数据值,它们包含一对儿getter和setter函数,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据,访问器属性有如下4个特性

    a、[[Configurable]]:表示可否经过delete删除属性从而从新定义属性,默认值为true

    b、[[Enumerable]]:表示可否经过for-in循环返回属性,默认值为true

    c、[[Get]]:在读取属性时调用的函数,默认值为undefined

    d、[[Set]]:在写入属性时调用的函数,默认值为undefined

    访问器属性不能直接定义,必须调用Object.definedProperty()来定义的,来看下面的例子

var book = {
    _year:2004,
    edition:1
}

Object.defineProperty(book, "year", {
    get: function() {
        return this._year;
    },
    set: function(newValue) {
        this._year = newValue;
    }
});

    这里要说明一下,book对象中_year前面的下划线是一种经常使用的记号,用于表示只能经过对象方法访问的属性,还有呀,你们不要小看了Object.definedProperty()这个方法,这个方法但是很强大呀,像vue的双向数据绑定,其实就是用到了这个方法去实现

    (3)读取属性的特性

    既然JavaScript有数据属性和访问器属性,那么咱们怎样才能读取它们呀,这个时候就须要用到Object.getOwnPropertyDescriptor()方法了,这个方法能够取得给定属性的描述符,接收两个参数,分别是属性所在的对象和要读取其描述符的属性名称

 

2、对象的建立

    在了解了对象以后,接下来咱们就须要说下怎么建立对象了,最简单的方法,固然就是使用前面说的对象字面量的方法去建立啦,可是若是咱们须要建立好多个对象,用前面的方法就不行了,咱们须要用到其它更加简便的方法,帮助咱们建立出多个对象

    一、工厂模式

    这种模式实际上是一个设计模式,抽象了建立具体对象的过程,主要是经过在函数内部建立一个对象,为其添加属性和方法,并将对象返回,从而实现建立多个对象的目的,来看下面的例子

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

var person1 = createPerson("Nicholas", 29);
var person2 = createPerson("Greg", 27);

    优势:可以解决建立多个对象的问题,兼容各个浏览器

    缺点:没有解决对象识别的问题,不能知道一个对象的类型

 

    二、构造函数模式

    这种模式主要经过建立自定义的构造函数,从而定义自定义对象类型的属性和方法,来看下面例子

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function() {
        console.log(this.name);
    }
}

var person1 = new Person("Nicholas", 29);
var person2 = new Person("Greg", 27);

    这里要说明一下,构造函数须要以一个大写字母开头,而非构造函数应该以一个小写字母开头,这个主要是为了区别构造函数和其它函数,构造函数其实自己也是函数,只是用来建立对象而已

    其中,要建立Person的新实例,须要使用new操做符,其实这里会通过4个步骤,首先,将会建立一个新对象,接着会将构造函数的做用域赋给新对象,this指向了这个对象,接着会执行构造函数中的代码,为这个新对象添加属性,最后会返回新对象

    优势:能够建立多个对象,解决对象的识别问题

    缺点:每一个实例都会建立不一样的function实例,而其实建立完成一样任务的function实例是很没有必要的

    这里仍是要说明一下,对象类型的检测须要用到instanceof操做符,好比像上面的例子能够用下面的方法检测

console.log(person1 instanceof Person);  //  true
console.log(person2 instanceof Person);  //  true

    使用构造函数模式能够解决对象的识别问题,而这也是工厂模式没法办到的

 

    三、原型模式

    咱们都知道,每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象就是原型对象,包含了全部实例共享的属性和方法,若是咱们要建立的对象须要共享属性和方法,就可使用这种方法建立

function Person() {
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.sayName = function() {
    console.log(this.name);
}

var person1 = new Person();
var person2 = new Person();
person1.sayName();  //  Nicholas
person2.sayName();  //  Nicholas

    优势:不用为构造函数传递参数,能够建立多个相同的对象

    缺点:原型中的属性被不少实例共享,当属性为包含引用类型值的属性时,修改一个实例中属性的值,另外一个实例中的属性的值也会改变

 

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

    经过前面的分析,咱们应该能够看到构造函数模式和原型模式的优势和缺点啦,构造函数能够建立多个不一样属性值的对象,原型模式能够用于定义方法和共享的属性,咱们能够将这两种模式结合起来,这种模式如今是使用最普遍的一种模式啦

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

Person.prototype = {
    constructor: Person,
    sayName: function() {
        console.log(this.name);
    }
}

var person1 = new Person("Nicholas", 29);
var person2 = new Person("Greg", 27);

person1.sayName();  //  Nicholas
person2.sayName();  //  Greg
person1.sayName === person2.sayName; // true

    从上面的例子咱们能够看到,使用这种模式建立对象,每一个实例都会有本身的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存,另外,这种混成模式还支持向构造函数传递参数,可谓是集两种模式之长

 

    五、动态原型模式

    这种模式主要是将全部信息都封装在了构造函数里,由于在组合构造函数模式和原型模式中,构造函数和原型模式是独立的,有些开发人员会感到很困惑,所以,这种模式也是为了解决这个问题,经过在构造函数中初始化初始化原型,又保持了同时使用构造函数和原型的优势,换句话说,就是能够经过在构造函数中,检查某个应该存在的方法是否有效,来决定是否须要初始化原型

 

function Person(name, age) {
    this.name = name;
    this.age = age;
    if(typeof this.sayName != "function") {
        Person.prototype.sayName = function() {
            console.log(this.name);
        }
    }
}

var person1 = new Person("Nicholas", 29);
person1.sayName();  // Nicholas

 

    这里要说明一下,在if语句中的代码,只有在首次调用构造函数时才会执行,以后原型已经获得初始化,不须要再作什么修改了

 

    六、寄生构造函数模式

    这种模式其实和工厂模式很像,除了使用new操做符并把使用的包装函数叫作构造函数以外,和工厂模式能够说是如出一辙的,这种模式的基本思想是建立一个函数,该函数的做用仅仅是封装建立对象的代码,而后再返回新建立的对象

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

var person1 = new Person("Nicholas", 29);
person1.sayName();  //  Nicholas

    寄生构造函数模式和工厂模式真的是很像,那么既然有了工厂模式,为何还要有寄生构造函数模式呢?其实这个模式主要是用来给js原生的构造函数定义一些新的方法,咱们能够看下面这个例子

function SpecialArray() {
    var values = new Array();
    values.push.apply(values, argumens);
    values.toPipedString = function() {
        return this.join("|");
    }
    return values;
}

var colors = new SpecialArray("red","blue");
console.log(colors.toPipedString());  //  red|blue

    从上面这个例子咱们能够看到,咱们在构造函数里面建立了一个新的数组,而后经过push方法初始化这个数组,而且又给数组的实例添加了一个toPipedString方法,而且将所建立的数组返回,所以呢,当咱们经过new建立了SpecialArray实例时,其实就获得增长了新方法的数组实例啦,就能够在这个实例上使用咱们添加的新的方法toPipedString

 

    七、稳妥构造函数模式

    在说这种模式以前,要先说一下稳妥对象,稳妥对象就是指没有公共属性,并且其方法也不引用this的对象,稳妥对象最适合在一些安全的环境中,或者防止数据被其余应用程序改动时使用,稳妥构造函数模式遵循与寄生构造函数相似的模式,可是仍是有下面的不一样,第一个是新建立的对象实例方法不引用this,第二个是不使用new操做符调用构造函数

function Person(name, age) {
    var o = new Object();
    _name = name;
    _age = age;
    o.sayName = function() {
        return _name;
    }
    return o;
}

var person1 = Person("Nicholas", 29);
person1.sayName();  //  Nicholas

    在上面这个例子中,咱们在构造函数中建立了一个对象后,能够继续添加一些私有的变量和函数,要修改这些私有的变量和函数,只能经过建立的对象的方法进行访问,这里在对象上建立的方法其实能够看做就是公有方法,好比说这里的_name和_age就是私有变量,而对象o的sayName方法就是访问私有变量的公有方法了,这里除了调用sayName()方法外,没有其它方法能够访问其数据成员

 

    八、es6中建立对象的方法

    最后要来讲下es6中建立对象新增的方法啦,在es6中,引入了 Class(类)这个概念,做为对象的模板,经过class关键字,能够定义类,基本上,ES6 的class能够看做只是一个语法糖,它的绝大部分功能,ES5 均可以作到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
}

var person1 = new Person("Nicholas", 29);
person1.sayName();  //  Nicholas

    上面这个例子其实就是组合构造函数模式和原型模式的改写,其中,constructor属性直接指向类自己,该方法会默认返回实例对象,在里面定义的属性和方法都是实例自己具备的方法,不是其它实例共享的,而像sayName方法就是定义在原型上的方法了,是全部实例一块儿共享的

 

    好啦,今天就介绍到这里了,不知道你们对对象和对象的建立是否有了一个比较详细的了解了呢

相关文章
相关标签/搜索