JavaScript -> 面向对象编程
1. JavaScript中的面向对象
-
面向对象:
- 类:是对象的类型模板,如student
- 对象:是根据类创建的对象实例,如xiaoming
-
在JavaScript中,面向对象的概念有所不同,JavaScript不区分类和对象实例的概念,而是通过
原型
(prototype)来实现面向对象编程var student = { name:'student', age:19, run: function (){ console.log(this.name+' is running...'); } }; var xiaoming = { name:'xiaoming' }; xiaoming.__proto__ = student; //把xiaoming的原型指向了对象student,看上去xiaoming仿佛是从student继承下来的
- xiaoming没有定义run()方法,由于把xiaoming的原型指向了对象student,只要student定义了run()方法,xiaoming就可以调用:
xiaoming.run() xiaoming is running...
-
JavaScript的原型和Java的Class区别在于,它没有Class概念,所有的对象否是实例,继承关系不过是把一个对象的原型指向另一个对象而已
- 如果再把xiaoming的原型指向其他对象,如Bird,此时xiaoming已经无法run()了,只能fly()
var student = { name:'student', age:19, run: function (){ console.log(this.name+' is running...'); } }; var xiaoming = { name:'xiaoming' }; xiaoming.__proto__ = student; var Bird = { name:'bird', fly: function (){ console.log(this.name + " is flying...") } }; xiaoming.__proto__ = Bird;
xiaoming.run() VM272:1 Uncaught TypeError: xiaoming.run is not a function xiaoming.fly() xiaoming is flying...
- 在JavaScript代码运行期间,可以把对象指向任何原型
2. 创建对象
-
JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。
-
当用
obj.xxx
访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype
对象,最后,如果还没有找到,就只能返回undefined
。 -
例如,创建一个
Array
对象:var arr = [1, 2, 3];
- 其原型链是:
arr-->Array.prototype-->Object.prototype--> null
Array.prototype
定义了indexOf()
、shift()
等方法,因此你可以在所有的Array
对象上直接调用这些方法。
-
当创建一个函数时:
function foo() { return 0; }
- 函数也是一个对象,它的原型链是:
foo --> Function.prototype --> Object.prototype --> null
- 由于
Function.prototype
定义了apply()
等方法,因此,所有函数都可以调用apply()
方法。
-
如果原型链太长,那么访问一个对象的属性就会因为花更多的时间查找而变得更慢,因此要注意不要把原型链搞得太长。
-
构造函数
-
除了直接用{…}创建一个对象外,JavaScript还可以用一种构造函数的方法来创建对象,
-
先定义一个构造函数:
function Student(name){ this.name = name; this.hello = function (){ alert('hello, ' + this.name + '!'); } }
-
这看起来是一个普通函数,但在JavaScript中,可以用关键字new调用这个函数,并返回一个对象,此时这个普通的后汉书就变成了一个构造函数:
var xiaoming = new Student('小明'); xiaoming.name; xiaoming.hello();
-
创建的xiaoming对象的原型链是:
xiaoming --> Student.prototype --> Object.prototype --> null
-
为了节省内存,可以让创建的对象共享同一个函数hello,只需要把hello函数移动到对象的共同的原型上,即Student.prototyp。代码修改如下:
function Student(name) { this.name = name; } Student.prototype.hello = function (){ alert('Hello, ' + this.name + '!'); }
-
3. 原型继承
4. class继承
-
ES6后,引入了class关键字
-
定义一个类,属性,方法
class Student{ constructor(name) { this.name = name; } hello(){ alert('hello') } } var xiaoming = new Student("xiaoming"); var xiaohong = new Student("xiaohong");
-
继承
class Student{ constructor(name) { this.name = name; } hello(){ alert('hello') } } class XiaoStudent extends Student{ constructor(name,grade) { super(name); //调用父类的构造方法 this.grade = grade; } myGrade(){ alert('我是一名小学生!') } } var xiaoming = new Student("xiaoming"); var xiaohong = new XiaoStudent("xiaohong");