对象 Object
在js 中创建最简单的对象,然后给它添加属性或者方法 示例如下:
var obj = new Object();
//或者
var obj = {};
obj.name = '张三';
obj.fun = function(){};
上创建的对象 中有 name 属性和一个 fun 方法,也可如下创建
var obj = {
name: '张三',
fun: function(){}
}
这个例子中的 obj 对象与前面例子中的 obj 对象是一样的,都有相同的属性和方法。这些 属性在创建时都带有一些特征值(characteristic),JavaScript 通过这些特征值来定义它们的行为。
1. 属性类型
ECMA-262 第 5 版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。 ECMA-262 定义这些特性是为了实现 JavaScript 引擎用的,因此在 JavaScript 中不能直接访问它们。为了 表示特性是内部值,该规范把它们放在了两对儿方括号中,例如[[Enumerable]]。在ECMAScript 中有两种属性:数据属性和访问器属性。
(1). 数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的特性,如下:
Configurable // 表示能否通过 delete 删除属性从而重新定义属性
Enumerable // 表示能否通过 for-in 循环及枚举返回属性
Writable // 表示能否修改属性的值
Value // 表示这个属性的数据值,这个特性的默认值为 undefined。
对于像前面例子中那样直接在对象上定义的属性,它们的 Configurable 、Enumerable 和 Writable 特性都被设置为 true,而 Value 特性被设置为指定的值。
要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty()方法。这个方法 接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属 性必须是:configurable、enumerable、writable 和 value。设置其中的一或多个值,可以修改 对应的特性值。 如下
var p = {};
Object.defineProperty(p,"name",{
configurable: true,
writable: true,
enumerable: true,
value: ""
})
configurable 属性
var p = {};
Object.defineProperty(p,"name",{
configurable: false, //如果不写该属性或者值为false delete 删除不会生效,在严格模式下会报错
value: ""
})
delete p.name
console.log(p); //{p:'123'}
一旦把属性定义为不可配置的, 就不能再把它变回可配置了。此时,再调用 Object.defineProperty()方法修改除 writable 之外 的特性,都会导致错误:
var p = {};
Object.defineProperty(p,"name",{
configurable: false,
value: ""
})
Object.defineProperty(p,"name",{
configurable: true,
value: ""
})
//跑出错误
也就是说,可以多次调用 Object.defineProperty()方法修改同一个属性,但在把 configurable 特性设置为 false 之后就会有限制了
writable 属性
var p = {};
Object.defineProperty(p,"name",{
writable: false, // 不写该属性 或者值为false 时不能修改值
enumerable: true,
value: ""
})
p.name = ;
console.log(p); //{p:'123'}
enumerable 属性
var p = {};
Object.defineProperty(p,"name",{
enumerable: true, // 不写该属性 或者值为false 时不能遍历得到对象属性值
value: ""
})
for(var i in p){
console.log(p[i]); //未获得值
}
在调用 Object.defineProperty()方法时,如果不指定,configurable、enumerable 和 writable 特性的默认值都是 false。多数情况下,可能都没有必要利用 Object.defineProperty() 方法提供的这些高级功能。不过,理解这些概念对理解 JavaScript 对象却非常有用。
(2). 访问器属性
访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。 在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性。
configurable // 表示能否通过 delete 删除属性从而重新定义属性
Enumerable // 表示能否通过 for-in 循环返回属性
Get // 在读取属性时调用的函数。默认值为 undefined。
Set // 在写入属性时调用的函数。默认值为 undefined。
configurable,Enumerable同数据属性一样的。
var p = {
_year: ,
num :
};
Object.defineProperty(p,"year",{
get: function(){
return this._year;
},
set: function(newValue){
if(newValue > ){
this._year = newValue;
this.num += newValue - ;
}
}
})
p.year = ;
console.log(p.num); //
以上代码创建了一个 p 对象,并给它定义两个默认的属性: _year 和 num。_year 前面 的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性 year 则包含一个 getter 函数和一个 setter 函数。getter 函数返回_year 的值,setter 函数通过计算来确定正确的版本。因此, 把 year 属性修改为 2001 会导致_year 变成 2001,而 num 变为 2。这是使用访问器属性的常见方 式,即设置一个属性的值会导致其他属性发生变化。
不一定非要同时指定 getter 和 setter。只指定 getter 意味着属性是不能写,尝试写入属性会被忽略。 在严格模式下,尝试写入只指定了 getter 函数的属性会抛出错误。类似地,只指定 setter 函数的属性也 不能读,否则在非严格模式下会返回 undefined,而在严格模式下会抛出错误。
支持 ECMAScript 5 的这个方法的浏览器有 IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera 12+和 Chrome。在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法: __defineGetter__()和__defineSetter__()。这两个方法最初是由 Firefox 引入的,后来 Safari 3、 Chrome 1 和 Opera 9.5 也给出了相同的实现。使用这两个遗留的方法,可以像下面这样重写前面的例子。
var p = {
_year: ,
num:
};
//定义访问器的旧有方法
p.__defineGetter__("year", function(){
return this._year;
});
p.__defineSetter__("year", function(newValue){
if (newValue > ) {
this._year = newValue;
this.num += newValue - ;
}
});
p.year = ;
alert(p.num); //
在 不 支 持 Object.defineProperty() 方 法 的 浏 览 器 中 不 能 修 改 Configurable 和 Enumerable 。
2. 定义属性
Object.defineProperty() //方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
var p = {};
Object.defineProperty(p,"name",{
enumerable: true,
value: ""
})
Object.defineProperties()//方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。可以定义哥多个属性
var p = {};
Object.defineProperties(p, {
name: {
value: true,
writable: true
},
name2: {
value: 'Hello',
writable: false
}
});
3 读取属性的特性
使用 ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述 符。这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果 是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;如果是数据属性,这 个对象的属性有 configurable、enumerable、writable 和 value.
var p = {
num :
};
Object.defineProperties(p,{
_year: {
value :
},
year:{
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > ) {
this._year = newValue;
this.num += newValue - ;
}
}
}
})
var obj = Object.getOwnPropertyDescriptor(p,'_year');
console.log(obj.value); //
console.log(obj.configurable); //false
console.log(typeof obj.get); //undefined
var obj1 = Object.getOwnPropertyDescriptor(p, "year");
console.log(obj1.value); //
console.log(obj1.enumerable); //false
console.log(typeof obj1.get); //"function"
对于数据属性_year,value 等于最初的值,configurable 是 false,而 get 等于 undefined。 对于访问器属性 year,value 等于 undefined,enumerable 是 false,而 get 是一个指向 getter 函数的指针。
在 JavaScript 中,可以针对任何对象——包括 DOM 和 BOM 对象,使用 Object.getOwnPropertyDescriptor()方法。
4.创建对象
4.1 工厂模式
function person(name, sex, age){
var obj = new Object();
obj.name = name;
obj.sex = sex;
obj.age = age;
obj.sayName = function(){
console.log(this.name);
}
return obj;
}
var zs = person('zs','M',);
var ls = person('ls','F',);
函数 person()能够根据接受的参数来构建一个包含所有必要信息的 对象。可以无 数次地调用这个函数,而每次它都会返回一个包含三个属性一个方法的对象。工厂模式虽然解决了创建 多个相似对象的问题,但却没有解决对象识别的问题
4.2构造函数模式
function Person(name, sex, age){
this.name = name;
this.sex = sex;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
}
var zs = new Person('zs','M',);
var ls = new Person('ls','M',);
console.log(zs.constructor === Person);//true
Person()中的代码 除了与 person()中相同的部分外,还存在以下不同之处:
没有显式地创建对象;
直接将属性和方法赋给了 this 对象;
没有 return 语句。
要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4 个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
在前面例子的最后,zs 保存着 Person 的一个的实例。这个对象有一个 constructor(构造函数)属性,该属性指向 Person,如下所示。
console.log(zs.constructor === Person);//true
1. 将构造函数当作函数
构造函数与其他函数的唯一区别,就在于调用它们的方式不同。不过,构造函数毕竟也是函数,不 存在定义构造函数的特殊语法。任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数;而 任何函数,如果不通过 new 操作符来调用,那它跟普通函数也不会有什么两样。例如,前面例子中定义 的 Person()函数可以通过下列任何一种方式来调用。
// 当作构造函数使用
var person = new Person("Nicholas", "M", 21); person.sayName(); //"Nicholas"
// 作为普通函数调用
Person("Greg", "M", ); // 添加到window window.sayName(); //"Greg"
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", , "Nurse"); o.sayName(); //"Kristen"
2. 构造函数的问题
构造函数模式虽然好用,但也并非没有缺点。使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,zs 和 ls 都有一个名为 sayName()的方法,但那 两个方法不是同一个 Function 的实例.
this.sayName = new Function("console.log(this.name)"); // 与声明函数在逻辑上是等价的
以这种方式创建函数,会导致不同的作用域链和标识符解析,但 创建 Function 新实例的机制仍然是相同的。因此,不同实例上的同名函数是不相等的.
console.log(person1.sayName == person2.sayName); //false
创建两个完成同样任务的 Function 实例的确没有必要;况且有 this 对象在,根本不用在 执行代码前就把函数绑定到特定对象上面。因此,大可像下面这样,通过把函数定义转移到构造函数外 部来解决这个问题。
function Person(name, sex, age){
this.name = name;
this.sex = sex;
this.age = age;
this.sayName = sayName;
}
function sayName(){
console.log(this.name);
}
var zs = new Person('zs','M',);
var ls = new Person('ls','M',);
console.log( zs.sayName == ls.sayName ); //true
在这个例子中,我们把 sayName()函数的定义转移到了构造函数外部。而在构造函数内部,我们 将 sayName 属性设置成等于全局的 sayName 函数。这样一来,由于 sayName 包含的是一个指向函数 的指针,因此 zs 和 ls 对象就共享了在全局作用域中定义的同一个 sayName()函数。
对象 Object的更多相关文章
- 一个简单的游戏开发框架(五.对象Object)
前面提到我们把行为Action从对象Object中分离了出来,用各种不同的行为组合出对象的功能.大家都知道,面向对象的一个类,就是数据和操作的集合.操作(行为)被分离出来了,数据怎么办呢?操作依赖的数 ...
- Java中的对象Object方法之---wait()和notifiy()
这一篇咋们继续,接着来介绍wait()和notify()方法,我们都知道这两个方法和之前介绍的方法不太一样,那就是这两个方法是对象Object上的,不属于Thread类上的.我们也知道这两个方法是实现 ...
- js内置对象-Object
1)Object构造函数的方法 返回指定对象的原型对象 Object.getPrototypeOf(mymap); /*{featureStyle: {…}, selfLayersCount: nul ...
- 对象Object
功能分类 1. 创建对象 把各对数自身拥有的可枚举属性复制到第一个对象并返回:obj = Object.assign(o1, o2, o3),o1=obj ...
- java的类class 和对象object
java 语言的源代码是以类为单位存放在文件中,已public修饰的类名须和存放这个类的源文件名一样.而 一个源文件中只能有一个public的类,类名的首字母通常为大写. 使用public修饰的类可以 ...
- 1月5日 对象Object, 含过去看的英文档的总结链接
Object 也是一种数据类型,可以有属性,有method. 反之,在Ruby中,每一种数据类型都是Object.如String,Integer,Float,Array,Hash. IN Ruby e ...
- vue props 传入对象Object,如果外层更改属性,默认里面是不更新,需要使用 this.$set(this.datese1, 'xsfaDateYear1', '')
vue props 传入对象Object,如果外层更改属性,默认里面是不更新,需要使用 this.$set(this.datese1, 'xsfaDateYear1', '')
- Java常见对象Object类中的个别方法
Java常见对象Object类 public int hashCode() : 返回该对象的哈希码值. 注意:哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但是不是实际地址值.你可以理解成 ...
- Java - 对象(object) 具体解释
对象(object) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24059545 对象(object)的实例能够是 ...
- JS json对象(Object)和字符串(String)互转方法
[JS json对象(Object)和字符串(String)互转方法] 参考:https://blog.csdn.net/wenqianla2550/article/details/78232706 ...
随机推荐
- MyBatis 值的传递
1.值的传递 - Map传值 可以通过对象获取Map传递值,在配置文件中通过 #{} 或 ${} 进行应用 查询30-40岁的用户 <!-- 值的传递 - Map传值 --> <se ...
- Spring @Async使用方法总结
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...
- 学习笔记之Nearest-Neighbour Searching with PostGIS
PostgreSQL: Documentation: 10: 7.8. WITH Queries (Common Table Expressions) https://www.postgresql.o ...
- linux 查看进程启动路径
在linux下查看进程大家都会想到用 ps -ef|grep XXX 可是看到的不是全路径,怎么看全路径呢? 每个进程启动之后在 /proc下面有一个于pid对应的路径 例如:ps -ef|grep ...
- MySQL 独立表空间恢复案例
创建表的时候就会得到元数据.可以通过定义的方式对表的元数据进行生成 这个地方要注意的是 独立表空间当中 ibd & frm分别存储的是什么数据? 表空间:文件系统,为了更好的扩容数据库的存 ...
- 敏捷软件开发——第8章 SRP:单一职责原则
第8章 SRP:单一职责原则 一个类应该只有一个发生变化的原因. 8.1 定义职责 在SRP中我们把职责定义为变化的原因.如果你想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.同时,我 ...
- lamda匿名函数(与sorted(),filter(),map() 一起用), 递归函数, 二分查找
一. 匿名函数 为了解决一些简单的需求而设计的一句话函数. lambda表示的是匿名函数. 不需要用def来声明, 一句话就可以声明出一个函数 语法: 函数名 = lambda 参数: 返回值 ...
- 2018年最新PHP面试题
面试之前多看看公司的资料,可以看出面试的公司主要做什么,电商,数据库,php函数,sql的优化,接口,session和cookie等经常会问到,都是必问之题,这其中有一部分题目摘抄自网络,回答也不错 ...
- 在线学习和在线凸优化(online learning and online convex optimization)—凸化方法4
一些在线预测问题可以转化到在线凸优化框架中.下面介绍两种凸化技术: 一些在线预测问题似乎不适合在线凸优化框架.例如,在线分类问题中,预测域(predictions domain)或损失函数不是凸的.我 ...
- 关于New,delete
new delete 为表达式.这个过程不能重载,但是分解的步骤可以重载. String* ps = newe String("Hello") 分解为: String* ps; v ...