JavaScript之面向对象的概念,对象属性和对象属性的特性简介
一、大家都知道,面向对象语言有一个标志,那就是他们都有类的概念,通过类我们可以创建任意多个具有相同属性和方法的对象。但ECMAScript(指定JavaScript标准的机构,也就是说JavaScript是实现其标准的扩展)并没有类的概念,因此他的对象和基于类的语言中的对象有所不同,ECMAScript把对象定义为:"无需属性的集合,其属性可以包含基本值、对象或者函数"。严格的来说,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正应为这样,我们可以把ECMAScript的对象想象成散列表;无非就是一组键值对,其中值可以是数据或函数。每个对象都是基于一个引用类型创建的。
//JavaScript早期的对象定义方式
var person = new Object();
person.name = "张三";
person.age = 22;
person.job = "coder";
person.sayName = function () {
alert(this.name);
}
//几年后,对象字面量成为创建这种对象的首选模式
var person = {
name: "Nicholas",
age: 22,
job: "coder",
sayName: function () {
alert(this.name);
}
}
person.sayName();
注意:这里的对象,不像真正的面向对象语言那样,对象真的被创建了,这里对象的概念只是一个数据集合(这个数据集合可以存放任何数据)的引用,这个引用值不会改变,而面向对象的类你每new一次,他的引用值都会改变一次。
二、面向对象的属性类型
在ES5中在定义只有内部采用的特性时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问他们,为了表示特性是内部值,ECMA-262规范把它们放在了两对方括号中,例如[[Enumerable]]。
ECMAScript中有两种属性:数据属性和访问器属性。
1、数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。
(1)[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像上面代码中直接在对象上定义的属性,他们的这个特性默认值为true.
(2)[[Enumerable]]:表示能否通过for-in循环返回属性。像上面代码中直接在对象上定义的属性,他们的这个特性值默认为true。
(3)[[Writable]]:表示能否修改属性的值。像上面代码中直接在对象定义的属性,他们的这个特性默认为true。
(4)[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候.把新值保存在这个位置。这个特性的默认值为undefined。也就是说如果你不给属性的该特性赋值,他的值将会是undefined。
现在有如下代码:
var person={
name:"张三"
};
像上面中直接在对象中定义的属性,他们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被设置为true,而[[Value]]被设置为指定的值"张三";按照上面特性的描述,person对象中的name属性可以通过delete删除重新定义该属性,可以修改该属性的特性,可以把该属性修改为访问器属性。可以通过for-in循环返回属性,可以修改属性的值。
应为ECMA-262规范中提到属性的特性是为了实现JavaScript引擎所用到,所以我们不能通过JavaScript直接访问,但是JavaScript给我们提供了了一个方法,来操作我们需要操作的对象的属性的特性;这个方法是
//这个方法接收三个参数:属性所在的对象引用、属性的名字和一个描述符对象
//其中描述符对象的属性必须是上面提到的四个属性的特性(实现JavaScript引擎所用)
//Configurable、Enumerable、Writable、value
Object.defineProperty();
下面是这个方法的应用:
var person = {};
Object.defineProperty(person, "name", {
writable:false, //writable这个特性决定了当前属性的属性值能否被修改,这边设置为false,也就是不能被修改
value:"张三"
});
alert(person.name);
person.name = "李四";//所以给name重新赋值并没有效果,如果将writable的值修改为true,这边的赋值就会成功!
alert(person.name);
两次输出都是"张三"。
alert(person.name);
var person = {};
Object.defineProperty(person, "name", {
configurable: true, //configurable这个特性决定了当前属性能否通过delete删除从而重新定义属性,能否修改属性的特性,能否将属性修改为访问器属性。
//这边设置为true,所以都可以
value:"张三"
});
alert(person.name);
delete person.name;//所以当这边删除name属性后,person对象就不存在了name属性
alert(person.name);//所以这边输出undefined因为此时person对象没有了name属性
输出:"张三","undefined";
var person = {};
Object.defineProperty(person, "name", {
configurable: false, //configurable这个特性决定了当前属性能否通过delete删除从而重新定义属性,能否修改属性的特性,能否将属性修改为访问器属性。
//这边设置为false,所以都不可以
value:"张三"
});
alert(person.name);
delete person.name;//所以当这边执行删除name属性的动作没有效果
alert(person.name);//所以这边输出还是"张三"
输出:"张三","张三"
var person = {};
Object.defineProperty(person, "name", {
configurable: false, //configurable这个特性决定了当前属性能否通过delete删除从而重新定义属性,能否修改属性的特性,能否将属性修改为访问器属性。
//这边设置为false,所以name属性被设置成为无法配置的属性
value:"张三",
});
Object.defineProperty(person, "name", {
configurable: true, //报错
value:"张三",
});
这边需要注意:当我们把属性定义为不给配置的之后,就不能再把它变回可配置的了。此时如果再调用Object.defineProperty()方法修改出writable之外的特性,都会导致错误。
输出:TypeError: can't redefine non-configurable property "name"
注意:当我们调用Object.defineProperty()方法,在指定了对象和对象的属性却没有指定描述符对象的的configurable、writable、Enumerbale的三个特性时,那么他们的默认值都为false;
综上所述:我们可以通过Object.defineProperty()方法来多次修改同一个属性,但是当我们把属性的configurable特性的值设置成false,就会有所限制了,我们只能修改属性的writable特性的值了;
2、访问器属性
访问器属性和数据属性的区别是:访问器属性不包含数据值,且类似与面向对象里面的类属性,他们都包含一对getter和setter函数,在读取访问器属性时,会调用getter函数,这个函数会返回有效的值,在写入访问器属性时,会调用setter函数并写入新值,这个函数负责决定如何处理数据,这个面向对象中的类属性大致一样!
访问器属性和数据属性一样,有4个特性:
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,对于直接在对象上定义的属性,这个特性的默认值为true;
[[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的属性。这个特性的默认值为true。
[[Get]]:在读取属性时调用的函数,默认值为undefined。
[[Set]]:在写入属性时调用的函数。默认值为undefined。
访问器属性不能直接定义,必须使用Object.definneProperty().请看下面代码:
var book = {
_year: 1994,
edition: 1
}
Object.defineProperty(book, "year", {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > 1994) {
this.edition += newValue - this._year;
this._year = newValue;
}
}
});
book.year = 2016;
alert(book.edition);
以上代码创建了一个book对象,并给他定义了两个默认的属性:_year和edition。_year前面的下划线十一找那个常用的标记,用于表示只能通过通过对象方法访问的属性。而访问器属性year则包含一个getter函数和setter函数。getter函数返回_year值.这里不一定要同时指定getter和setter。只指定getter意味着属性是不能写,只指定setter意味着只写,无法获取属性值。
注意:支持ECMAScript 5的get,set方法浏览器只有IE9+(IE8部分实现)、FireFox 4+、Safari 5+、Opera 12+和Chrome,在这之前,要创建访问器属性,一般都使用两个非标准方法,_defineGetter_()和_defineSetter_(),如下代码是早期访问器属性的代码版本:
var book = {
_year: 1994,
edition: 1
}
book._defineGetter_("year", function () {
return this._year;
});
book._defineSetter_("year", function (newValue) {
if (newValue > 1994) {
this.edition += newValue - this._year;
}
this._year = newValue;
});
book.year = 2016;
alert(book.edition);
3、定义多个属性
在开发当中,当我们用到对象的时候,大多数情况下都会用到多个属性,所以ECMAScript 5又定义了一个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 > this._year) {
this.edition += newValue - this._year;
}
this._year = newValue;
}
}
});
book.year = 2016;
alert(book.edition);
上面定义了两个数据属性(_year和edition)和一个访问器属性(year)。最终的对象和上一段代码定义的对象相同。唯一的区别是这里的属性都是在同一时间创建的!上一段代码中定义的对象,实在定义完数据属性之后又定义了一个访问器属性。
4、读取属性的特性
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 > this._year) {
this.edition += newValue - this._year;
}
this._year = newValue;
}
}
});
var attribute = Object.getOwnPropertyDescriptor(book, "_year"); /*获取数据属性_year对象注意:支持这个方法的浏览器有IE9+,fireFox4,Safari 5+,Opera,Chrome*/
alert(attribute.value); /*输出数据属性_year的Value特性*/
alert(attribute.configurable); /*输出数据属性_year的configurable特性*/
alert(typeof attribute.get); /*输出数据属性的get的特性,但是数据属性被没有Get特性,只有访问器属性才有Get和Set特性,所以这里输出undefined*/
var attribute_two=Object.getOwnPropertyDescriptor(book,"year");
alert(attribute_two.get); //输出访问器属性的get方法,get是指向getter函数的指针
alert(attribute_two.value); //输出访问器属性year的value特性,但是访问器属性并没有value特性,value特性属于数据属性,所以输出undefined
alert(attribute_two.enumerable); //因为访问器属性year并不是在对象上直接定义的属性而是通过defineProperties()方法定义的属性,所以他的Enumerable特性为false,所以输出false;
JavaScript之面向对象的概念,对象属性和对象属性的特性简介的更多相关文章
- java类(Class)的概念;对象的概念,声明类的属性 和方法,局部变量和成员变量,面向对象编程思维,抽象的概念
类(Class)的概念 类是对一组具有相同特征和行为的对象的抽象描述. 理解: [1] 类包含了两个要素:特性和行为 => 同一类事物具有相同的特征和行为. [2] 类是一个群体性概念.例如:网 ...
- JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法
1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...
- JavaScript面向对象(二)——成员属性、静态属性、原型属性与JS原型链
前 言 JRedu 上一篇博客中,我们介绍了JS中的面向对象,并详细的解释了this的指向问题.本篇博客,我们继续来学习JS的面向对象.来深入理解一下JavaScript OOP中的成员属性/方 ...
- 深入理解javascript对象系列第二篇——属性操作
× 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...
- JavaScript常用对象的方法和属性
---恢复内容开始--- 本文将简单介绍JavaScript中一些常用对象的属性和方法,以及几个有用的系统函数. 一.串方法 JavaScript有强大的串处理功能,有了这些串方法,才能编写出丰富多彩 ...
- javascript之面向对象程序设计(对象和继承)
总结的文章略长,慎点. 知识点预热 引用类型:引用类型的值(对象)是引用类型的一个实例.在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起.在其他面向对象语言中被称为类,虽然 ...
- javascript . 04 匿名函数、递归、回调函数、对象、基于对象的javascript、状态和行为、New、This、构造函数/自定义对象、属性绑定、进制转换
匿名函数: 没有名字的函数,函数整体加小括号不报错, 函数调用 : a:直接调用 (function (){函数体}) ( ) ; b:事件绑定 document.onlick = functio ...
- -1-2 java 面向对象基本概念 封装继承多态 变量 this super static 静态变量 匿名对象 值传递 初始化过程 代码块 final关键字 抽象类 接口 区别 多态 包 访问权限 内部类 匿名内部类 == 与 equal
java是纯粹的面向对象的语言 也就是万事万物皆是对象 程序是对象的集合,他们通过发送消息来相互通信 每个对象都有自己的由其他的对象所构建的存储,也就是对象可以包含对象 每个对象都有它的类型 也就是 ...
- Javascript高级编程学习笔记(19)—— 对象属性
面向对象的语言有一个标志,那就是语言中都有类的概念 前面的文章中我提到过ECMAScript中没有类的概念(ES6之前) 所以JS中的对象和其他语言中的对象存在着一些区别 ECMA中对对象的定义如下: ...
随机推荐
- ubuntu_安装aptana3
下面记录下偶怎么安装aptana3(aptana2应该也适用). 安装java运行时,偷看这里 说明:实际上偶并没有执行这步,因为发现在安装aptana3之前 java的运行时已经安装过了. 貌似是安 ...
- Codeforces 241B
因为博客园的公式编辑有点坑,所以-- 原题
- nginx源代码分析--配置文件解析
ngx-conf-parsing 对 Nginx 配置文件的一些认识: 配置指令具有作用域,分为全局作用域和使用 {} 创建其他作用域. 同一作用域的不同的配置指令没有先后顺序:同一作用域能否使用同样 ...
- 基于Linux 3.0.8 Samsung FIMC(S5PV210) 的摄像头驱动框架解读(一)
作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 FIMC这个名字应该是从S5PC1x0開始出现的.在s5pv210里面的定义是摄像头接口.可是它相 ...
- 怎样调通微信支付及微信发货通知接口(Js API)
怎样调通微信支付及微信发货通知接口(Js API) 微信支付提供了一个支付測试页面,微信支付正式使用须要測通支付.发货通知接口 .告警接口.维权接口.告警接口.维权接口非常easy.支付界面调通也相对 ...
- 如风一样,飞翔------Day37
我一直都觉得自己是个反应没有那么敏锐的人,而不幸的是其实也是,所以,在菜鸟的头衔上,我不得不再背负上一个笨鸟的"光芒".我不苛求一飞冲天的传奇,却也有着不甘寂寞的激昂,我选择先飞, ...
- 查询SQL中字符串里有多少个逗号
select len(@str)-len(replace(@str,',',''))
- 解析word中的表格
由于word表格的特殊性,其本身中的数据本来就不够完善,不能够很好的知道其具体的合并.跨行的相关属性,表格的单位可能是PT或者是百分比,并且是共存的,为处理带来了一定的负担,本代码实现了一个将Word ...
- clientX,pageX,screenX,offsetLeft,scrollTop
出处:点击打开链接 一直不太明白,今天看了一下,感觉挺详细,先转载过来....... clientX 观点:鼠标相对于WINDOWS的坐标. 这里这个WINDOWS是指我们能看见的浏览器大小.所以不可 ...
- Sublime Text 增加CoffeeScript、Jade and Stylus syntax高亮
切换到Sublime Text Packages 目录: Liunx系统: cd ~/Library/Application\ Support/Sublime\ Text\ /Packages win ...