Object 对象
上一篇:继承的概念
下一篇:Fountion 对象
主要内容:
-
Object
对象和其他对象的关系 -
Object
对象中已的⽅法 - 字⾯量的类型
-
new
的含义
与其他⾯向对象的编程语⾔ (
Java
,C#
) 类似, 可以说,JavaScript
中所有的对象都来⾃于Object
. 但是⼜不完全是这样.JavaScript
是利⽤原型来实现继承的. 为了弄清楚JavaScript
的继承的本质, 接下来⾸先讨论⼀下Object
对象的⼀些细节.
Object 对象和其他对象的关系
要讨论
Object
对象与其他对象之间的关系, ⾸先来看对象的类型.
typeof 运算符和对象的类型
在
JavaScript
中, 数据类型分为基本类型和复合类型. 基本类型都有⾃⼰的类型名, 但是复合类型都被描述为object
. 可以使⽤typeof
运算符加⼀验证.
console.log(typeof 123); // => number
console.log(typeof 1.23); // => number
console.log(typeof true); // => boolean
console.log(typeof "ly"); // => string
console.log(typeof []); // => object
console.log(typeof new Date()); // => object
console.log(typeof {}); // => object
console.log(typeof /./); // => object
原因很简单, 即使任何对象都直接或间接的继承⾃
Object.prototype
对象.
Object 的原型
了解到所有对象都直接或间接继承⾃
Object.prototype
后, 我们来理⼀理Object
和Object.prototype
以及 其他对象之间的关系.
⾸先来看
Object
对象与Object.prototype
的关系.
Object 对象与它的原型
先来看⼀段代码:
var o = new Object();
_ = null; // ⽤于设置断点调试
设置断点运⾏后:
Object 对象图1.png
可⻅由Object
构造⽅法创建出来的对象没有任何成员.那些对象都共有的⽅法, 实际上都来源于__proto__
Object 对象图2.png
暂时不管这些⽅法的含义. 这⾥o.__proto__
就是Object.prototype
. 因此他们之间的关系就很清楚了.
Object 对象图3.png
注意:__proto__
并⾮标准属性.
其他对象的原型和 Object.prototype
了解了
Object
对象与其原型的关系后, 下⾯来看看⼀般对象与原型的关系, 以及⼀般对象与Object.prototype
的关系.
function Person() {
}
Person.prototype.sayHello = function() {
console.log("Hello, I'm JK!");
};
var p = new Person();
_ = null;
运⾏设置断点后:
![](https://img.haomeiwen.com/i11155724/17e34010ed84e31e.png)
可⻅其结构与
Object
对象和 Object.prototype
的结构⼀样. 然⽽原型对象也是有原型的, 虽然⽆法使⽤构造⽅法, 但是可以使⽤ __proto__
来查看![](https://img.haomeiwen.com/i11155724/c2e654c7b2481a2f.png)
从中可以发现⾃定义构造⽅法创建出来的对象 (
new <构造⽅法>
)有⼀个原型对象, 即 <构造⽅法>.prototype
. ⽽该原型对象也有原型对象. 根据图中可以看到原型对象的原型对象是 Object
类型的. 可⻅, ⾃定义构造⽅法创建对象的原型对象就是 Object
构造⽅法的实例.![](https://img.haomeiwen.com/i11155724/3f3b09dd156db417.png)
从图中可以看出⾃定义对象和
Object
对象, 以及之间原型对象的关系.
内置对象
前⾯讨论了⾃定义对象, 接下来看看内置对象是否也复合这个关系.
⾸先看看数组:
var arr = [];
_ = null;
设上断点后运⾏
Object 对象图7.png
可以看到, 与⾃定义对象⼀致.
同理验证
Date
对象,Error
对象都是如此. 但是Math
对象不同.Math
本⾝
是⼀个Object
类型的对象.
Object 原型中定义的⽅法
接下来讨论
Object
原型对象中定义的⽅法.
var o = Object.prototype;
_ = null;
设定断点, 调试查看
Object 对象图8.png
可⻅原型对象中包含的都是⽅法:
-
__defineGetter__
⽅法 -
__defineSetter__
⽅法 -
__lookupGetter__
⽅法 -
__lookupSetter__
⽅法 -
constructor
⽅法 -
hasOwnProperty
⽅法 -
isPrototypeOf
⽅法 -
propertyIsEnumerable
⽅法 -
toLocaleString
⽅法 -
toString
⽅法 -
valueOf
⽅法 -
get __proto__
读写器 -
set __proto__
读写器
在这些⽅法中, 带有两个下划线开头和两个下划线结尾的⽅法是⾮标准⽅法.因此在部分浏览器中可能没有实现.
constructor
⽅法. 该⽅法即构造⽅法. 调⽤构造⽅法, 可以创建对象. 那么这个属性就是该对象构造⽅法的引⽤.
function Person() {}
var p = new Person();
console.log(typeof p.constructor); // => function
console.log(p.constructor === Person); // => true
hasOwnProperty
⽅法. 该⽅法需要⼀个字符串参数, ⽤来判断该字符串表⽰名字的属性是否为⾮继承属性. 如果是⾮继承属性, 就返回true
, 否则返回false
function Person() {
this.property1 = 1;
}
Person.prototype.property2 = 2;
var p = new Person();
console.log("p.property1 = " +
p.property1 +
", hasOwnProperty = " +
p.hasOwnProperty("property1"));
console.log("p.property2 = " +
p.property2 +
", hasOwnProperty = " +
p.hasOwnProperty("property2"));
console.log("p.toString = " +
p.toString +
", hasOwnProperty = " +
p.hasOwnProperty("toString"));
执⾏结果为
Object 对象图9.png
isPrototypeOf
⽅法. 如果目标对象是参数对象的原型对象, 那么就返回true
, 否则返回false
function Person() {}
var p = new Person();
console.log(p.isPrototypeOf(p)); // => false
console.log(Person.prototype.isPrototypeOf(p)); // => true
console.log({}.isPrototypeOf(p)); // => false
propertyIsEnumerable
⽅法. 该⽅法需要⼀个字符串参数, 如果该字符串表⽰的名字是对象的⾃有属性, 同时该属性可枚举, 那么⽅法就会返回true
, 否则返回false
function Person() {
this.name = "jk";
}
Person.prototype.age = 10;
Object.prototype.gender = "男";
var p = new Person();
for (var k in p) {
console.log(k + ", " + p[k] + ", " + p.propertyIsEnumerable(k));
}
执⾏结果为
Object 对象图10.png
实际上该⽅法与hasOwnProperty
⽅法类似. 在JavaScript
中只有⼀些内置的系统⽅法⽆法枚举. 因此该⽅法⼏乎总是返回true
. 但是在ECMAScript 5
中给出了设置对象特性的⽅法, 可以设置某个属性是否可以枚举.
toString
⽅法和toLocaleString
⽅法. 这两个⽅法都是将对象转换成字符串. 不同的是toLocaleString
是转换为本地字符串. ⼀般对象与toString
⼀样. 但是时间类型不同.
var arr = [1,2,3];
console.log(arr.toString());
console.log(arr.toLocaleString());
var now = new Date();
console.log(now.toString());
console.log(now.toLocaleString());
执⾏结果为
Object 对象图11.png
valueOf
⽅法. 当对象需要转换为数字类型的时候就会调⽤该⽅法. 该⽅法与toString
类似.
var a1 = [1,2];
var a2 = [1,2];
a1.valueOf = function() {
console.log("调⽤了 valueOf");
return 3;
};
a1.toString = function() {
console.log("调⽤了, toString");
return "---";
};
console.log(Number(a1));
console.log(Boolean(a1));
console.log(String(a1));
console.log(Number(a2));
执⾏结果为
Object 对象图12.png
⾄于
get
和set
以及带有两个下划线的⽅法, 后⾯再详细说明.
字⾯量的类型
在实际开发中, 由于字⾯量不需要定义构造⽅法, 也不需要
new
等操作. 因此字⾯量的效率会⽐较⾼, 因此尽量使⽤对象的字⾯量. 但是, 没有构造⽅法, 也就表明⽆法实现复⽤. 因此选择需要权衡.
那么字⾯量的类型是什么呢? 还是利⽤调试来进⾏查看
var o = {};
_ = null;
设断点后:
Object 对象图13.png
可⻅对象的字⾯量是Object
类型的. 它的原型就是Object.prototype
new 以及构造函数的执⾏过程
除了字⾯量以外, 对象也可以使⽤
new
构造函数的形式被创建出来. 使⽤构造函数与使⽤对象字⾯量的最⼤区别在于, 使⽤构造⽅法可以复⽤, 利⽤构造⽅法可以创建出多个对象; 但是使⽤对象的字⾯量, 只会有⼀个对象.
那么构造函数具体做了什么, 下⾯来进⾏说明.
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
var p = new Person("jk", 19, "m");
这⾥定义了构造函数
Person
, 然后调⽤构造⽅法, 创建了⼀个对象p
代码var p = new Person("jk", 19, "m");
可以分成三个步骤:
1, 执⾏new
关键字, 开辟内存控件, 闭关获得内存引⽤
2, 调⽤构造⽅法Person
, 传递参数: 内存引⽤, 字符串 "jk" , 数字 19 , 和字符串 "m" (m 表⽰男, f 表⽰⼥)
3, 执⾏完构造⽅法, 将地址引⽤返回给左边的变量p
上一篇:继承的概念
下一篇:Fountion 对象
⼩结
- 所有的对象都继承⾃
Object.prototype
-
Object.prototype
中常⻅的⽅法有:
constructor
⽅法
hasOwnProperty
⽅法
isPrototypeOf
⽅法
propertyIsEnumerable
⽅法
toLocaleString
⽅法
toString
⽅法
valueOf
⽅法 - 对象字⾯量是
Object
类型的对象 -
new
关键字开辟内存空间 - 构造⽅法调⽤隐含参数
this