引用类型-Object

什么是引用类型

在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起,这常被称为类。但是在ECMAScript中不具备传统的面向对象语言所支持的类和接口等基本结构,所以在ECMAScript中成为类是不妥当的。

引用类型的值是引用类型的实例。引用类型的实例也就是对象,描述的是一类对象所具有的属性和方法。

 

var colors = new Array('blue', 'yellow', 'green');

 

这里colors对象是Array引用类型的实例,新对象通过new操作符后面跟随构造函数来创建的。在面向对象中可以了解到,构造函数就是函数,只不过是用来创建对象的函数。

Object类型

Object类型的实例不具备很多功能,但是在程序中储存和传输数据是很好的选择。并且其它对象都继承自这个对象,本身也是一个构造函数可以用来生成新的对象。

创建Object类型的方式

传统的方式:new操作符跟随Object构造函数

 

var preson = new Object();
preson.name = 'liuhaixiao';
preson.age = 18;
preson.showName = function() {  
    alert(this.name);
}

 Object作为构造函数使用可以接受一个参数,如果这个参数是一个对象,则返回这个对象。如果参数是一个基本类型值,则返回对应的基本包装类型对象。

var preson1 = new Object();
preson1.name = 'zhangxueyou';
preson1.age = 19;
var preson2 = new Object(preson1);
alert(preson1 == preson2)  //这里会返回true;

var number = new Object(123);
var boolean = new Object(true);
alert(number instanceof Number);
alert(boolean instanceof Boolean);
//inscanceof用于检测某个对象是不是某个引用类型的实例,所有其它对象都继承自Object所以任何对象instanceof Object都为true。

 

对象字面量方式:

使用对象字面量方式创建对象的时候,不会调用Object构造函数。任何使用字面量方式创建对象的时候,都不会调用相应的构造函数。

var preson = {
    name : 'liuhaixiao',
    age : 18,
    showName : function() {
        alert(this.name);
    }  
}    

对象中的属性值都是字符串类型,即使是数字也会被转换为字符串。

var preson = {
  name : 'liuhaixiao',
  true : 18,
  124 : function() {
    alert(this.name);
  }
}
for(var i in preson) {
  alert(typeof i);              //无论属性是字符串布尔值或者数字都会被转换为stirng,属性的本质就是字符串,在定义的时候也可以直接加引号
}

 

 使用对象字面量的方式将花括号留空:

var preson = {};
preson.name = 'liuhaixiao';
preson.age = 18;
preson.showName  = function() {
    alert(this.name);  
}
var preson = {}和var preson = new Object()完全相同。
 

对象属性的访问

 访问对象的属性一般使用点表示法,只有在特殊情况下才使用方括号表示发,在使用方括号表示法的时候应该将访问的属性以字符穿的形式放在方括号中。

 

alert(preson['name'])

 

方括号方法可以使用变量访问对象属性

var preson = {
    name : 'liuhaixiao',
    age : 18
}
var presonName = 'name';  //将对象的属性值赋值给一个变量
alert(preson[presonName]);  //通过这个变量来访问属性值

属性名可以是包含非数字或者字母的,或者属性名使用的是关键字或者保留字,或者包含导致语法错误的字符,这时候就需要用方括号来访问属性了。

var preson = {
    'first name' : 'liuhaixiao',
    $ : 17,
    showName : function() {
        alert(this['first name'];    
    }  
}
alert(preson['first name']);
alert(preson['$']);

 

 将对象当作函数的参数使用

将对象当作参数传递给函数的时候,无论是使用构造函数还是字面量的方式都可以,但是传递大量可选参数首选方式是字面量的方式

function displayInfo(args) {
    var output = '';
    if(typeof args.name == 'string') {
        output += 'name: ' + args.name + '\n';
    }
    if(typeof args.age == 'number) {
        output += 'age: ' + args.age + '\n';
    }
    alert(output);
}
var preson1 = new Object();
preson1.name = 'liudehua';
preson1.age = 18;
var preson2 = {
    name : 'zhangxueyou',
    age : 19
}
displayInfo(preson1);
displayInfo(preson2);
displayInfo({name : 'guofucheng', age : 22});

 为对象添加新方法

在构造函数上添加方法:

 

Object.print = function(obj) {
    console.log(obj);   //在Object构造函数上定义一个方法打印传入对象
}

var preson = new Object();
preson.name = 'liuhaixiao';
Object.print(preson);

 

在Object构造函数上添加方法可能不够直观,这里给Array构造函数添加一个方法,为数组传递一个指定的字符串:

Array.add = function(arr, value) {
    arr.push(value);
}
var colors = ['yellow', 'blue', 'green'];
Array.add(colors, 'red');
console.log(colors);  //这里可以看到数组的内容增加了。

 

在对象原型上添加方法

 

Object.prototype.print = function() {
    console.log(this);   //方法是一个函数,谁调用这个方法this就是谁。 
}
var preson = new Object();
preson.name = 'liuhaixiao';
preson.print();  //同样也会打印这个对象

 

同样的还是为数组后面添加一个指定的字符串这里使用在原型上添加方法的方式

Array.prototype.add = function(value) {
    this.push(value);
}
var colors = ['yellow', 'blue', 'green'];
colors.add('red');
console.log(colors);  //可以看到方法生效

Object构造函数本身

Object是一个构构造函数,构造函数也是函数,可以当作函数使用。这样就相当于转型函数一样。将任意值转换为对象。

 

var preson = Object();  //创建一个空对象
var preson = Object(null);  //创建一个空对象
var preson = Object(undefined);  //创建一个空对象
var number = Object(123);  //创建一个基本包装类型的number等于 new Number(123)
var boolean = Object(true);  //创建一个基本包装类型的boolean等于 new Boolean(true)
var string = Object('string');  //创建一个基本包装类型的string等于 new String('string')

 

如果传递给Object的参数是一个对象,那么就会将对象原封不动的返回。

var colors = ['yellow', 'blue', 'green'];
var objColors = Object(colors);
alert(colors == objColors);
console.log(objColors);
var fn = function() {
    console.log('this is a function');
}
var objFn = Object(fn);
alert(fn == objFn);
console.log(objFn);

利用Object()方法总是将对象返回,可以判断一个变量是否为对象。

function isObject(value) {
    return value === Object(value);
}
var arr = ['color'];
var str = 'this is  a string';
alert(isObject(arr));
alert(isObject(str));

 Object对象的静态方法,即之前在构造函数上添加的方法

返回对象属性的两个方法:Object.keys()和Obeject.getOwnPropertyNames(),这两个方法接受一个参数即对象,返回一个数组,数组保存着对象的属性名(对象自身的而不是继承而来的属性)。两者之间的区别是前者只返回可枚举的属性,自己定义的属性都是可枚举的。而后者同时返回不可枚举的属性。这两个方法不涉及原型中的属性。

 

var preson = new Object();
preson.name = 'liuhaixiao';
preson.age = 17;
preson.showName = function() {
    alert(this.name);
}
alert(Object.keys(preson));
alert(Object.getOwnPropertyNames(preson));
//这种情况下两者返回的值是相同的,因为没有不可枚举的属性。

 

为什么说这两个静态方法不设计原型中的属性呢?我做这样的测试,不知道是否合理。

function Preson(name, age) {
    this.name = name;
    this.age = age;  
}
Preson.prototype.showName = function() {
    alert(this.name);
}
Preson.prototype.firends = ['zhangxueyou', 'liudehua', 'guofucheng'];
var preson1 = new Preson('liuhaixiao', 17);
preson1.showName();
//这里创建了一个构造函数,然后preson1对象是这个构造函数的实例,在原型中有一个属性和方法。
alert(Object.keys(preson1));
alert(Object.getOwnPropertyNames(preson1));
//这两个方法都返回了实例属性,而没有返回原型中的属性。

通过数组来实现返回不可枚举的属性。

var colors = ['yellow', 'blue', 'green'];
alert(Object.keys(colors));
alert(Object.getOwnPropertyNames(colors));  //数组的length属性是不可枚举的,所以Object.keys()没有返回,而Object.getOwnPropertyNames()方法可以返回。
开始我想这两个方法不能返回原型中的属性,那么length属性不是就在原型中吗,后来我一想如果lenth属性在原型中,每个数组都共享一个length那么就乱套了。
所以length属性只是存在实例中,只不过是不可枚举。

通常情况下使用Object.keys()来遍历对象的属性,同时可以通过length属性来获得对象属性的个数。

var colors = ['yellow', 'blue', 'green'];
alert(Object.keys(colors).length);
alert(Object.getOwnPropertyNames(colors).length);

这两个方法还有一个注意的问题,对于对象来说,如果索引是或者能转化为数字类型,那么获取的属性虽然是字符串类型,但是会按照从小到大排序

var obj = {100: 'xiaoming', 50: 'zhangxueyou', 2: 'liudehua'}
alert(Object.keys(obj));
alert(Object.getOwnPropertyNames(obj));
//这两个都返回2,5 ,100
alert(typeof Object.keys(obj)[0]);  //属性必然是字符串类型

在Object构造函数原型中的方法

这些方法定义在Object.prototype对象上,所有的Object实例都会继承这些方法。其它对象的实例也会继承这些方法,有些不继承会重写相应的方法。

valueOf()返回当前对象的对应值

toString()返回当前对象的字符串形式

toLocaleString()返回当前对象的本地字符串形式

hasOwnProperty()判断某个属性是否为当前对象自身的属性,如果是则返回true,如果这个属性在原型中则返回false。另外通过for-in可以判断是否有这个属性,无论是在原型中还是在对象自身中。

isPrototypeOf()判断当前对象是否为另一个对象的原型

propertyIsEnumerable()判断某个属性是否可以枚举

Object的valueOf()方法的作用是返回一个对象的值,默认返回对象本身

 

var  obj = new Object();
obj.name = 'liuhaixiao';
alert(obj.valueOf() === obj);
var arr = [12,12,23];
alert(arr.valueOf() === arr);
var fn = function() {
    alert('tshi si a function');
}
alert(fn.valueOf() === fn); //只要是对象都原封不动的被返回了
var str = 'this is a string';
alert(str.valueOf() === str);  //字符串不是对象,应该没有方法,但是这里应该是访问valueOf()方法的同时,创建了基于这个字符串的基本包装类型,在 原型中寻找这个方法。因为原型链所以会在Object的原型中找到。

 

valueOf()方法的主要用途是,javascript自动类型转换时会默认调用这个方法,更改这个方法的返回值可以获得自己想要的值。

var o = new Object()
var result = 1 + o;
alert(result);  //这里会默认调用o的valueOf()方法,完成字符串拼贴,但是对象的valueOf()方法不就是返回对象本身吗?为什么会拼贴呢?
var o = new Object() o.valueOf = function() { return 10; } var result = 1 + o; alert(reslut); //这里返回的是11,因为对象本身有了valueOf方法,就不会去原型中去寻找,相当与屏蔽了原型中的valueOf()方法。

toString()方法返回对象的字符串形式,默认情况下返回类型字符串

var obj = new Object();
alert(obj.toString()); //'object object'
obj.toString = function() {
    return 'this is a string';  //同样也可以自定义返回的内容,所以之前的字符串拼贴问题,应该是调用了toString()方法完成了操作。尝试后无论是修改valueOf()方法返回数字或者toString()方法返回数字都可以达到效果。  
}

数组、字符串、函数、Date对象分别重写了toString()方法,没有使用继承的方法,其中数组是将每一项以逗号分隔拼贴成一个字符串。其它都是转换为相应的字符串形式。

使用toString()方法判断数据类型

 

var obj = new Object();
alert(obj.toString());  //这个返回的是字符串object Object,前一个object表示是对象,而后一个表示这个对象的构造函数
//typeof运算符能够判断数据类型,但是不能判断对象是何种对象,即一个对象的构造函数是什么。
//任何对象都有toString()方法,但是是返回相应的字符串形式。我们只需要使用Object.prototype上的toString()方法,即Object原型上的toString()方法就可以像obj那样返回object Array(任何类型的构造函数)
var arr = ['mingzi', 12, true];
alert(Object.prototype.toString.call(arr)); //object Array

 

其它数据类型的返回值,因为是toString()方法,所有这些返回值都是字符串格式

数值:object Number

字符串:object String

布尔值:object Boolean

undefined:object Undefined

null: objectNull

数组:object Array

arguments对象(传递给函数实际参数的类数组合集对象):object Arguments

函数:object Function

Error对象:object Error

Date对象:object Date

RegExp对象:object RegExp

其它对象:object Object

 

参考资料:javascript高级程序设计(第三版)

阮一峰老师的博客教程:http://javascript.ruanyifeng.com/

posted @ 2017-02-12 13:17  398883362  阅读(122)  评论(0)    收藏  举报