js高级程序设计笔记 -- 属性类型以及创建对象
2017-03-13 21:55
716 查看
1.属性类型
ECMAScript中有两种属性:数据属性和访问器属性1.数据属性:
数据属性包含一个数据值的位置,在这个位置可以读取和写入值[[ Configurable ]] : 表示能否删除属性或者修改属性为访问器属性。默认值为true;
[[ Enumerable ]] : 表示能否通过for-in 循环返回属性。默认值为true;
[[ Writable ]] : 表示能否修改属性的值 。默认值为true;
[[ Value ]] : 包含这个属性的数据值,读取属性值的时候从这个位置读取,写入属性值的时候,把新值保存在这个位置 默认值为 undefined;
修改数据属性默认的特性,必须使用 ECMAScript5 的object.defineProperty() 方法。这个方法接受三个参数:
属性所在的对象,属性的名字和一个描述符对象,其中描述符对象的属性必须是: configurable, enumerable, writable, value.
var person = {}; Object.defineProperty(person, "name", { writable: false, value: "mnixu" }) console.log(person.name) //"mnixu" person.name = "xu" console.log(person.name) //"mnixu" var person = {}; Object.defineProperty(person, "name", { configurable: false, value: "mnixu" }) console.log(person.name) //"mnixu" delete person.value; console.log(person.name) //"mnixu" var person = {}; Object.defineProperty(person, "name", { configurable: false, value: "mnixu" }) //拋出錯誤 Object.defineProperty(person, "name", { configurable: true, value: "mnixu" })
注意:一但把属性定义为不可配置的,就不能再把它变为可配置的。
在调用Object.defineProperty()方法创建一个新的属性时,如果不指定,configurable, enumerable, writable,特性的默认值都为false,
如果调用Object.defineProperty()方法只是修改已定义的属性,则无限制
2.访问器属性:
访问器属性不包含数据值:他们包含一对getter和setter函数。也有四个特性。
[[ Configurable ]] : 表示能否删除属性或者修改属性为访问器属性。默认值为true;
[[ Enumerable ]] : 表示能否通过for-in 循环返回属性。默认值为true;
[[ get ]] : 在读取属性时调用的函数。默认值为undefined;
[[ set ]] : 在写入属性是调用的函数。 默认值为undefined;
访问器属性不能直接定义,必须 使用object.defineProperty() 方法 来定义
var book = { _year: 2004, 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; console.log(book.edition)
_year前面的下划线是用于表示只能通过对象方法访问的属性。
getter函数返回_year的值,setter函数通过计算来确定正确的版本,修改year属性为2005时候会导致_year变为2005
edition变为2,这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
2.定义多个属性
使用Object.defineProperties()方法可以定义多个属性var book = {}; Object.defineProperties(book, { _year: { writable: true, value: 2004 }, edition: { writable: true, value: 1 }, year: { get: function () { return this._year; }, set: function (newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004 } } } });
这个定义的最终对象和上面定义的对象相同,唯一的区别是这里的属性都是在同一时间创建的。
3.读取属性的特性
使用Object.getOwnPropertyDescriptor() 可以取得给定义属性的描述符例子:
var descriptor = Object.getOwnPropertyDescriptor(book, "_year") console.log(descriptor.value) //2004 var descriptor = Object.getOwnPropertyDescriptor(book, "year") console.log(descriptor.enumerable) //false console.log(typeof descriptor.get) //"function"
2.创建对象
1.构造函数模式
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { console.log(this.name) }; } var person1 = new Person("mnixu", "20", "Student"); var person2 = new Person("zhangsan", "11", "Student"); //person1 和 person2 都保存着Person 的不同实例。都有一个constructor(构造函数)属性,该属性指向Person console.log(person1.constructor == Person); //true console.log(person2.constructor == Person); //true //对象的constructor属性最初使用来标识对象类型的。但是,检测对象类型使用instanceof操作符更可靠 console.log(person1 instanceof Person); //true console.log(person1 instanceof Object); //true console.log(person2 instanceof Person); //true console.log(person2 instanceof Object); //true
构造函数也可以当做普通函数来调用:
//当做构造函数使用 var person = new Person("mnixu", "20", "Student"); person.sayName(); //"mnixu" //当做普通函数使用 Person("zhangsan", "20", "Student"); //添加到window window.sayName(); //"zhangsan" //在另一个对象的作用域中调用 var o = new Object(); Person.call(o, "lisi", "20", "Student"); o.sayName(); //"lisi"
构造函数模式虽然好用,但是使用构造函数有一个主要问题,就是每个方法都要在每个实例上重新创建一遍。
前面的person1 和 person2 都有一个sayName()方法,但是两个方法不是同一个Function实例。
在ECMAScript中的函数就是对象,每定义一个函数,就是实例化一个对象。
console.log(person1.sayName == person1.sayName); //false
2.原型模式
我们创建的每一个函数都有一个prototype(原型)属性。这个属性是一个指针,指向一个对象。使用原型对象可以让所有对象实例共享它所包含的属性和方法。
function Person() { }; Person.prototype.name = "mnixu"; Person.prototype.age = "20"; Person.prototype.job = "Student"; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); person1.sayName(); //"mnixu" var person2 = new Person(); person2.sayName(); //"mnixu" console.log(person1.sayName == person1.sayName); //true创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性;至于其他方法,都是从Object继承过来的。
当我们调用构造函数创建一个新的实例后,该实例内部讲包含一个指针(内部属性),指向构造函数的原型对象。
ES5管这个指针叫[[ Prototype ]] 。我们可以通过__proto__这个内置属性来访问
console.log(person1.__proto__ === Person.prototype); //true console.log(Person.prototype.__proto__ === Object.prototype); //true console.log(Object.prototype.__proto__) //null 当我们访问对象的某个属性时,会从对象实例本身开始寻找,没找到就继续搜索指针指向的原型对象,直至找到顶层null为止 我们把上面的例子串起来就是原型链 person1 --> Person.prototype --> Object.prototype --> null 原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用 Person.prototype.constructor === Person //true Function.prototype.constructor === Function //true Object.prototype.constructor === Object //true
原型模式也是有缺点的,但是原型中的所有属性是被很多实例共享,对于包含引用类型值的属性来说,可能会有很多问题
例子:
function Person() { }; Person.prototype = { constructor: Person, name: "mnixu", age: 20, job: "Student", friends: ["zhangsan", "lisi"], sayName: function () { console.log(this.name) } } var person1 = new Person(); var person2 = new Person(); person1.friends.push("wangwu"); console.log(person1.friends); //["zhangsan", "lisi", "wangwu"] console.log(person2.friends); //["zhangsan", "lisi", "wangwu"] console.log(person1.friends === person2.friends) //true
3.组合使用构造函数模式和原型模式
创建自定义类型的常见方式就是组合使用构造函数模式和原型模式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。所以,每个实例都有自己的一份实例属性副本,但同时又共享着对方法的引用。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["zhangsan", "lisi"]; } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name) } } var person1 = new Person("mnixu", 20, "Student"); var person2 = new Person("lisi", 20, "Student"); person1.friends.push("wangwu") console.log(person1.friends); //["zhangsan", "lisi", "wangwu"] console.log(person2.friends); //["zhangsan", "lisi"] console.log(person1.friends === person2.friends) //false console.log(person1.sayName === person2.sayName) //true
相关文章推荐
- JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
- js数据类型隐式转换笔记以及js包装对象
- 笔记:js高级程序设计第五章,函数的引用类型与基本类型
- JavaScript高级程序设计之面向对象的程序设计之创建对象之工厂模式第6.2.1讲笔记
- js创建对象的几种方法---js的高级程序设计
- JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
- JavaScript高级程序设计之面向对象的程序设计之创建对象之寄生构造函数模式 第6.2.6讲笔记
- JS高级程序设计学习笔记之第三章基本概念(语法,数据类型,流控制语句,函数)——查漏补缺
- JavaScript高级程序设计之面向对象的程序设计之创建对象之稳妥构造函数模式 第6.2.7讲笔记
- JS高级程序设计笔记(一)-数据类型
- JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
- JavaScript高级程序设计 阅读笔记(十三) js定义类或对象
- JavaScript高级程序设计之引用类型之单体内置对象之Global对象第5.7.1讲笔记
- AJAX笔记一创建XMLHttpRequest对象,以及XMLHttpRequest对象的常用属性
- JavaScript高级程序设计(第3版)学习笔记10 再访js对象
- 《JavaScript高级程序设计 第三版》学习笔记 (四) 对象创建详解
- javascript高级程序设计笔记--js数据类型
- JavaScript高级程序设计(第3版)学习笔记6 初识js对象
- JS高级程序设计笔记(五):引用类型
- JS高级程序设计--读书笔记(js对象创建)