javascript中的对象
1 创建对象
在js中创建对象非常的简单
var obj={}
这样,我们就创建了一个对象
2 对象的继承
在ES6之前,javascript对象的继承是通过原型(prototype)来实现的。在ES6之后的继承方式类似于java
2.1 方式1 通过prototype创建对象
举例
var student = { name: 'no_name', height: 1.2, run: function () { console.log(this.name + ' is running...'); } }; var xiaoming = { name: '小明' }; xiaoming.__proto__ = student;
访问属性和方法
xiaoming.name; // '小明' xiaoming.run(); // 小明 is running...
xiaoming
有自己的name
属性,但并没有定义run()
方法。不过,由于小明是从student
继承而来,只要student
有run()
方法,xiaoming
也可以调用
需要注意的是,上述示例只用于演示,在平时开发过程中不要直接用obj.__proto__去改变一个对象的原型。
2.2 通过Object.create()创建对象
var xiaoming=Object.create(student) xiaoming.name='小明' //判断原型是否是student xiaoming.__proto__===student // 返回true
2.3 通过构造函数创建对象
定义一个构造函数
function Student(name) { this.name = name; this.hello = function () { alert('Hello, ' + this.name + '!'); } }
咦,这不就是一个普通函数吗。是的,这确实就是一个普通函数,但是如果我们通过如下方式使用,则这个普通函数就是一个构造函数
//通过构造函数创建一个新的对象 var xiaoming=new Student('小明') //调用 xiaoming.name; // '小明' xiaoming.hello(); // Hello, 小明!
新创建的xiaoming
的原型链是:
xiaoming ----> Student.prototype ----> Object.prototype ----> null
3 原型链
当我们用obj.xxx
访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype
对象,最后,如果还没有找到,就只能返回undefined
。
例如
var arr = [1, 2, 3];
其原型链是
arr ----> Array.prototype ----> Object.prototype ----> null
再比如
function foo() { return 0; }
函数也是一个对象,它的原型链是:
foo ----> Function.prototype ----> Object.prototype ----> null
4 constructor属性
用new Student()
创建的对象还从原型上获得了一个constructor
属性,它指向函数Student
本身
xiaoming.constructor === Student.prototype.constructor; // true Student.prototype.constructor === Student; // true Object.getPrototypeOf(xiaoming) === Student.prototype; // true xiaoming instanceof Student; // true
这是什么乱七八糟的,看晕了,请看下图
其中红色箭头是原型链,注意,
构造函数Student.prototype
指向的对象就是xiaoming
的原型对象,这个原型对象自己还有个属性constructor
,指向Student构造
函数本身。
另外,构造函数Student
恰好有个属性prototype
指向xiaoming
的原型对象,但是xiaoming
对象可没有prototype
这个属性,不过可以用__proto__
这个非标准用法来查看。
不过还有个问题
xiaoming.name; // '小明' xiaohong.name; // '小红' xiaoming.hello; // function: Student.hello() xiaohong.hello; // function: Student.hello() xiaoming.hello === xiaohong.hello; // false
xiaoming和xiaohong各自的name不同,这是对的
但是xiaoming和xiaohong各自拥有独立的hello()方法,这就不合理了,这样浪费了很多内存。解决方法是有的,就是通过上图的原型链关系图,我们如果把hello()方法移动到他们共同的原型上就可以了,如下图
把hello()方法移动到上图中的"某个对象"里,而这个"某个对象"就是Student.prototype,因此我们把hello()方法移动到Student.prototype上。
修改代码如下
function Student(name) { this.name = name; } Student.prototype.hello = function () { alert('Hello, ' + this.name + '!'); };