理解Javascript的动态语言特性(4)

var book = { _year: 2004, edit: 1 }; Object.defineProperties(book,{ _year: { value: 2015 }, edit: { value: 2 }, year: { get: function(){ return this._year; }, set: function(newValue){ if(newValue > this._year) { this._year = newValue; this.edit += newValue - this._year; } } } });

如上代码;给book对象设置了3个属性,其中前面两个会覆盖原有的book的对象的属性,三个属性是添加的;

上面确实是给对象设置了多个属性了,那么现在我们如何读取属性了?

ECMAScript5给我们提供了方法 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。该方法接收2个参数,属性所在的对象和需要读取描述符的属性名称。返回值也是一个对象,如果是访问器属性,这个对象的属性有configurable、enumerable、get 和set;如果是数据属性,这个对象的属性有configurable、enumerable、writable 和value。

我们先来看下数据属性,如下代码获取:

复制代码 代码如下:


var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
console.log(descriptor);

打印出来如下:

Object {value: 2015, writable: true, enumerable: true, configurable: true}

是一个对象,现在的value变成2015了;

但是如果我们来看下访问器属性的话,如下代码:

var descriptor = Object.getOwnPropertyDescriptor(book, "year");

console.log(descriptor);

打印如下:

就有如上四个属性了;

Object.getOwnPropertyDescriptor方法,支持这个方法的浏览器有:

IE9+,firefox4+,safari5+,opera12+和chrome;

理解构造函数

function Dog(name,age) { this.name = name; this.age = age; this.say = function(){ alert(this.name); } }

如上就是一个构造函数,它与普通的函数有如下区别:

1.函数名第一个首字母需要大写,为了区分是构造函数。
2.初始化函数的时候需要new下;任何函数,只要它是通过new初始化的,那么他们就可以把它当做构造函数;
比如如下初始化实例化2个对象:

var dog1 = new Dog("wangwang1",'10'); var dog2 = new Dog("wangwang2",'11');

那么我们现在可以打印console.log(dog1.say());打印出来肯定是wangwang1,console.log(dog2.say());打印出来是wangwang2;

dog1和dog2分别保存着Dog的一个不同的实例,且这两个对象都有一个constructor(构造函数)属性。该属性指向Dog,如下代码:

alert(dog1.constructor === Dog); // true alert(dog2.constructor === Dog); // true

同时实例化出来的对象都是Object的实例,可以通过instanceof 来检测如下代码:

alert(dog1 instanceof Object); // true alert(dog2 instanceof Object); // true alert(dog1 instanceof Dog); // true alert(dog2 instanceof Dog); // true

构造函数的缺点:就是每个方法都需要在每个实例上重新创建一遍,比如上面的实例化2个Dog对象,分别为dog1和dog2,dog1和dog2都有一个say方法,但是那个方法不是同一个Function的实例,如下代码:

alert(dog1.say === dog2.say); // false

因此我们需要引入原型模式;原型模式就是要解决一个共享的问题,我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途就是让所有的实例共享属性和方法;比如还是上面的代码改造成如下:

function Dog() {}; Dog.prototype = { name: 'wangwang', age:'11', say: function(){ alert(this.name); //wangwang } } var dog1 = new Dog(); dog1.say(); var dog2 = new Dog(); dog2.say(); alert(dog1.say === dog2.say); // true

如上打印 dog1.say === dog2.say,他们共享同一个方法;为什么会是这样的?

我们可以先来理解下原型对象;

不管什么时候,只要创建了一个函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象;比如上面的函数Dog,那么就会为该函数创建一个Dog.prototype 这么一个对象,在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性.

构造函数的任何一个实例都会指向与该构造函数的原型;比如我们可以通过isPrototypeOf()方法来确定对象是否存在这种关系;如下代码:

function Dog() {}; Dog.prototype = { name: 'wangwang', age:'11', say: function(){ alert(this.name); //wangwang } } var dog1 = new Dog(); var dog2 = new Dog(); console.log(Dog.prototype.isPrototypeOf(dog1));//true console.log(Dog.prototype.isPrototypeOf(dog1));//true

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgdxzg.html