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 + '!');
};