最近开始接触js,语法什么的都还行,唯独对于面向对象这一块的概念一直比较模糊,晚上的资料也都对照的看了看,总结了一下自己的理解。
在传统的面向对象的语言如java中,都会有一个class类,class不是对象,它可以理解为是一张图纸。根据这些图纸创建的实例才是可以调用的对象。比方说我们有个锤子图纸,它有锤人的功能。我们只有把这个锤子按照图纸造出来,才能拿来锤人,要不然你拿个图纸去锤人,会被反杀的。
但是在js的世界里面,没有图纸的概念,一切都是对象。可以理解为js对象就是一堆属性和方法的集合。下面就是一个简单的对象。
var Student = { name:'zhangsan', age:13, say:function(){ console.log('my name is '+this.name + ', I am'+this.age+'years old!'); } }
但是这种方法比较麻烦,如果每次创建对象我们都要用这种方式来构建,那就很坑爹了。你可以封装一个函数,传入name和age,函数来帮你构建,如下
function Student(name,age){ return { name:name, age:age, say:function(){ console.log('my name is '+this.name + ', I am'+this.age+'years old!'); } } }
这种方式也可以,但是这个对象每次都会开辟新的内存空间,比较不环保。上面两个方式完全没有面向对象编程的感觉,感觉还是面向函数式编程的样子,我们下面来了解下另外一种创建对象的方法《构造函数模式》。
先看一个简单的栗子
function Student(name,age){ this.name = name; this.age = age; this.say = function(){ console.log('my name is '+this.name + ', I am'+this.age+'years old!'); } } var zhangsan = new Student('zhangsan',13); zhangsan.say();
到这一步已经有点面向对象的意思了,但是依旧没有解决上面栗子中的内存开销问题。这个时候我们需要了解js中另外一个东西,同时结构一下,new 函数的整个过程。
JavaScript中没有类的概念,但是JavaScript中有一个原型的概念prototype。当已存在一个对象的时候,可以通过指定对象的prototype的方法来,来依据已存在的对象创建新的对象。有点绕,直接上代码。
var Student = { name:'zhangsan', age:13, say:function(){ console.log('my name is '+this.name + ', I am'+this.age+'years old!'); } } var Student2 = {name:'lisi'} Student2.__proto__=Student Student2.say()
上面代码中,我们首先有了Student对象,再创建Student2对象,同时指定Student2对象的__proto__属性继承Student对象的age 和 say属性,name其实也继承了只是被重写了。
这就是javaScript中的原型的概念,其实说白了就是当我们调用对象的属性和方法的时候,首先会调用自己的属性方法,当没有找到的时候就会到__proto__中去找有没有相关的属性和方法。
每个对象都有自己的原型链,比如我们定义了一个数组类型arr = [],那么它的原型链就是arr ---->Array.prototype---->Object.prototype---->null。
其实基本上和java的继承类似,那么我们再返回上面的构造函数模式中,创建对象的全过程,我们先看看伪代码
var obj = {} obj.__proto__ = Student.prototype Student.apply(obj, arguments) return obj
第一行代码是创建一个空对象。
第二行是将空对象的原型属性指向构造函数Student的prototype属性,在这里要声明一下,在javaScript的规定里面,每个构造函数都有一个prototype属性。
第三行的代码就是将构造函数的作用域赋予给对新对象,将构造函数中的this指向新对象。
第四行返回对象
通过上面的过程我们大致理解了构造函数创建过程,这个时候我们再思考一下前面的问题,关于对象创建时,重复创建函数的问题。我们可以对构造函数的prototype属性进行赋值,使所有的对象都指向同一个构造函数的prototype属性,这样我们就可以解决之前内存不环保的问题,这就表示我们可以把一些不变的方法或者属性定义在prototype属性上,下面我们上代码
function Student(name,age){ this.name = name; this.age = age; } Student.prototype.say = function(){ console.log('my name is '+this.name + ', I am'+this.age+'years old!'); } student = new Student() student.say()
其实本质上来讲,javascript面向对象的思想和别的语言差不多,只是因为没有使用class所以理解上有点别扭,但是从es6开始,javascript开始支持class关键字,我们可以像使用java一样来创建class,再根据class来new出对象来。但是为啥现在没有流行起来,我看到一些资料是说有些浏览器不支持es6,很多主流项目也没有引入class,如果要改的话,重构的工作应该也比较大。