JavaScript 对象的属性与创建方式

理解对象:数据属性和访问器属性。
创建对象:工厂模式、构造函数模式、原型模式、组合使用构造函数和原型模式、动态原型模式、寄生构造函数模式、稳妥构造函数模式。

1. 对象的属性 property

2.1 数据属性

行为特性:

  • configurable 能否删除
  • enumerable 能不能通过for in
  • writable 能否修改
  • value 设定属性值
Object.defineProperty(person, "name", {
    configurable: false,
    value: "Nicholas"
});

2.2 访问器属性

  • configurable 能否删除
  • enumerable 能不能通过for in
  • get
  • set

访问器属性不包含数据值;它们包含一对儿 getter 和 setter函数(optional)

在读取访问器属性时,会调用 getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter 函数并传入新值,这个函数负责决定如何处理数据。

也就是说不需要显示的调用set和get函数,它是自动执行的。

  • 只指定 getter 意味着属性是不能写
  • 只指定 setter 函数的属性也不能读,否则在非严格模式下会返回 undefined,
var book = {
    _year: 2004, //这个属性表示只能通过对象(object)访问
};
// 这里访问器属性是year,_year是数据属性
Object.defineProperty(book, "year", {
    get: function(){
        return this._year;
    },
    set: function(newYear){
        this._year=newYear;
    }
});
book.year = 2005;
console.info(book._year);  //2005

查看属性的信息:

     Object.getOwnPropertyDescriptor(book,"_year")

2. 创建对象的方法

2.1 使用Object方式创建

2.1.1 new

使用 new 操作符后跟 Object 构造函数

    var p1 = new Object();
    p1.name="p1";
2.1.2 对象字面量
    var p2 = {
        name:"p2"
    };

虽然 Object 构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点: 使用同一个接口创建对象时会产生大量代码


2.2. 更有效的创建对象的方法

2.2.1. 工厂模式

用函数来封装以特定接口创建对象的细节

function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
}
var person1 = createPerson("Nicholas");
2.2.2. 构造函数模式

ECMAScript 中的构造函数可用来创建特定类型的对象。像 Object 和 Array 这样
原生构造函数,在运行时会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

function Person(name) {
    this.name = name;
};
var person1 = new Person("Nicholas");
var person2 = new Person("Nicholas");
// 这两个对象都有一个 constructor(构造函数)属性,该属性指向 Person

要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。

console.info(person1.constructor == person2.constructor); //t
console.info(person1.constructor == Person); //t
console.info(person1 instanceof Person); //t
console.info(person1 instanceof Object);  //t

构造函数的三个特点:

  • 没有显式地创建对象;
  • 直接将属性和方法赋给了 this 对象;
  • 没有 return 语句。

只要用new调用的就是构造函数,不用new的就不是。

// 当作构造函数使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"

// 作为普通函数调用
Person("Greg", 27, "Doctor"); // 添加到 window
window.sayName(); //"Greg"

// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
2.2.3. 原型模式

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针

function Person(name) {
    this.name = name;
};
// 函数自带了prototype属性
// 这个属性指向 系统为这个函数自动创建的 “原型对象” Person Prototype
console.info(Person.prototype);  //Person {}
// “原型对象”里面有一个属性 叫做constructor  这个属性指向 这个函数
console.info(Person.prototype.constructor); //[Function: Person]

当用构造函数创建一个新实例后,该实例的内部会包含一个指针,指向刚才的那个“原型对象”,这个指针叫[[prototype]], 使用__proto__ 访问。
也就是说, 每个实例只是指向了“原型对象”,而不与它们的构造函产生直接的联系。
实例的指针 -> 原型对象 -> 原型对象的指针 -> 构造函数

function Person(){
}

Person.prototype.name = "Nicholas";
var p1=new Person();
console.info(Person.prototype); //Person { name: 'Nicholas' }
console.info(p1.__proto__); //Person { name: 'Nicholas' }
console.info(Person.prototype.constructor); //[Function: Person]
2.2.4. 组合使用构造函数模式和原型模式
  • 构造函数模式用于定义实例属性
  • 原型模式用于定义方法和共享的属性

每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。

function Person(name) {
    this.name = name;
    this.friends = ["Shelby", "Court"];
}

// typeof(Person.prototype)  object
Person.prototype = {
    constructor: Person,
    sayName: function () {
        alert(this.name);
    }
}
var person1 = new Person("Nicholas");
var person2 = new Person("Greg");
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
2.2.5. 动态原型模式

这里只在 sayName()方法不存在的情况下,才会将它添加到原型中。

function Person(name) {
    this.name = name;
    this.friends = ["Shelby", "Court"];
    if (typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        }
    }
}
2.2.6. 寄生构造函数模式

除了使用构造函数的方法初始化对象以外,这个方法和工厂模式是一样的。

function Person(name) {
    var o = new Object();
    o.name = name;
    o.sayName = function () {
        alert(this.name);
    };
    return o;
}
var friend = new Person("Nicholas");
friend.sayName(); //"Nicholas"
2.2.7. 稳妥构造函数模式
  • 不用 this
  • 不用 new
function Person(name, age, job) {
    //创建要返回的对象
    var o = new Object();
    o.sayName = function () {
        alert(name);
    };

    //返回对象
    return o;
}

var friend = Person("Nicholas", 29, "Software Engineer");

// name只能通过sayname来访问
friend.sayName(); //"Nicholas"

一些变量只能通过函数访问,确保安全性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值