一、引言
思维角度:以一个Java开发的程序员的视觉,思考JS面向对象语言的特点
思考1:JS是面向对象的语言,但是没有类的概念,如何创建对象?
思考2:JS是面向对象的语言,但是没有类,怎么继承?
二、解决问题
问题1:没有类,如何创建对象?
理解:JS虽然没有类库,也没有class,所以无法通过类的形式创建对象。但是,我们直到对象的本质无非是属性加上方法吗?
例1 一个对象的创建
var animal={ name:"animal", eat:function(){ console.log(this.name+" is eating");//向控制台输出内容 } }; animal.eat();//调用函数
补充:由于对象的并并不和类关联,可以随意的给这个对象添加属性
例2 添加属性
<script type="text/javascript"> var animal={ name:"animal", eat:function(){ console.log(this.name+" is eating");//向控制台输出内容 } }; animal.eat(); animal.color="black";//给对象添加新属性 console.log(animal.color); </script>
至此:对象创建出来了,但是对象太自由了(思考:弊端是什么?)
问题2:没有类怎么继承?
理解:继承无非是让类与类建立关联,那么如何建立关联呢?
关联方式:JS中的每一个对象都有一个特殊的属性"__proto__",通过此属性去关联另外一个对象,这个对象就是所谓的原型
例3
<script type="text/javascript"> //(1)创建一个对象(非new的形式) var animal={ name:"animal", eat:function(){ console.log(this.name+" is eating");//向控制台输出内容 } }; animal.color="black";//对象中添加一个属性 //(2)创建一个对象 var dog={ name:"dog", __proto__:animal //指向animal对象 }; //(3)创建一个对象 var cat={ name:"cat", __proto__:animal //指向animal对象 }; dog.eat();//继承原型的方法 cat.eat();//继承原型的方法 console.log(dog.name);//dog --覆盖原型的属性 console.log(cat.name);//cat --覆盖原型的属性 console.log(cat.color);//black--继承原型的属性 </script>
分析:cat和dog对象的原型都是animal,但是其对象里面都没有定义eat方法,那么是如何调用的呢?
过程:当eat方法被调用时,首先会在自己(调用对象)的方法列表中寻找,如果找不到,则去原型中寻找,如果仍找不到继续往上
层的原型中去寻找,直到找到了Object那里,任然找不到,则就是未定义(undifined)。几个对象会通过__proto__建立如下的原
型链(作用:函数复用):
回顾:JVM虚拟机中,一个对象在执行方法的时候,整个流程:也是先查找方法的定义,查找次序:先从本对象所属的类开始,
然后是父类,祖父类,直到Object,思路是一样的。
补充:关于JS属性的属性,也是如此通过原型链查询的
三、向Java靠拢
我们知道JS本来全名叫LiveScript,为了搭上Java帝国的快班车,改名为JavaScript,向Java示好。
模仿Java的类定义、创建对象、以及调用方法。
具体表现:
例4
function Student(name){ this.name=name,//也可以变成;号,但是JSON形式封装数据不行 this.hello=function(){ console.log("I am "+this.name); } } var jane=new Student("jane");//创建对象(var可以省略!!!) var tony=new Student("tony");//创建对象(hello定义在此对象中,意味着该对象有此方法的实体) jane.hello();//I am jane tony.hello();//I am tony
示好说明:提供了一个家叫做构造函数的东西,可以看到function有点类似class的感觉(雏形),并且有this关键字,而且Student
大写,整个感觉就像是一个Java类。
上面出现小问题:每个新创建的对象都有一个hello函数,函数定义在对象上,意味着每个对象都有一份,太浪费!
高效的解决方法:把hello函数放到自己创建的原型对象中去,然后让jane、tony这些从Student中创建而来的对象指向这个原型
如何指向呢?把原型对象放到Student.prototype这个属性中
例5
<script type="text/javascript"> function Student(name){ this.name=name; } //重点在这!!! Student.prototype={ hello:function(){ console.log("I am "+this.name); } } var jane=new Student("jane");//创建对象 var tony=new Student("tony");//创建对象 jane.hello();//I am jane tony.hello();//I am tony </script>
特点:每次通过Student创建的对象(jane、tony),JS会自动建立原型链!
具体分析:new Student的时候,JS会建立如下的关系链:
实质:所谓的构造函数Student就是一个幌子,每次通过"new Student"创建对象,并且把该对象的原型(__proto__)指向
Student.prototype这个原型对象,这样就能找到hello()方法。
理论基础:当一个对象调用方法的时候,会顺着原型链向上寻找。
四、向Java程序员示好(了解即可)
由于上述的构造函数再加上prototype的概念,让人很是费解,JS提供了一些语法糖来降低程序员(Java)的负担。
例6
//重点是class class Student(name){ this.name=name, this.hello=function(){ console.log("I am "+this.name); } } var jane=new Student("jane");//创建对象 var tony=new Student("tony");//创建对象 jane.hello();//I am jane tony.hello();//I am tony
说明:语法糖已经把JS变得非常像Java(C#、C++)的类了。
注意:class是ES 2015的新特性
思考:原型法对于Java、C#、C++码农不是很直观,引入类的语法糖能吸引更多的码农加入JS王国,但是JS是否远离了初衷?
四、JSON
理解:JOSN封装数据是封装一种格式,这种格式也被其他语言也采用了 。
特点:JSON采用键值对的方式去封装数据(非二进制流);应用场景:JOSN数据占用比较小,一般用于网络传输、交换数据
说明:JSON中的键用引号括起来,值如果是字符串也用引号括气来(数字不括)
应用1:标准JSON数组的遍历
<script type="text/javascript"> //(1)定义JSON的数组对象 var JSON={ name:"jane", age:18, agender:"male" }; document.write(typeof JSON); //(2)遍历JSON数组--特有的for in的形式 for(var i in JSON){ console.log(JSON[i]); } //表示遍历数组,而i表示的是数组的下标值, //JSON[i]表示获得第i个数据 </script>
注意:for in循环的用法(里面参数的含义),普通的for循环方法略
应用2:复杂的标准JSON格式的数组遍历(嵌套)
需求:获取相同JSON格式中的某个字段的内容
//(1)定义JSON的数组对象(嵌套) var JSON=[ {"flag":1,"age":18,"phone":"110","userName":"小红"}, {"flag":0,"age":20,"phone":"119","userName":"小明"}]; //(2)遍历JSON数组--for in的形式 for(var i in JSON){ console.log(JSON[i].userName); //result[i]表示获得第i个json对象即JSONObject //result[i].字段名称--即可获得指定字段的值 }
应用3:复杂的非标准JSON格式的数组遍历(嵌套)
<script type="text/javascript"> //(1)定义非标准的JSON的数组对象(嵌套) var JSON = { "name": "张三", "age": 23, "sex": "男", "score": { "chinese": 100, "math": 90, "english":85 } }; //(2)遍历数据 for(var i in JSON){ //重要:通过typeof 把object转成一个字符串的"object" var v = typeof JSON[i]; if(v=="object"){ //表明又是一个JSON格式的数据,则获取出这个嵌套的json对象 再次进行遍历 var innerJSON= JSON[i]; for(var j in innerJSON){ console.log(innerJSON[j]); } }else{ //说明是基本类型的数据 console.log(JSON[i]); } } </script>
应用4:复杂的非标准JSON格式的数组遍历(嵌套)
var JSON={ "datas": [{"flag":1,"macId":"2","mbId":0,"userName":"XXX"}, {"flag":1,"macId":"1","mbId":1,"userName":"YYY"}] }; //说明:进行遍历之前得先解析出标准的json数组格式即[{},{}] var json=JSON.datas; for(var i in json){ //表示遍历数组,而i表示的是数组的下标值, //data[i]表示获得第i个json对象即JSONObject //data[i]通过.字段名称即可获得指定字段的值 console.log(json[i].userName); }
应用5:对一个内置对象进行一个功能上的扩展(原型属性)
需求:数组本身没有排序的功能,给其内置一个函数,进行功能性的扩展
1、书写一个MyArray.js的文件
Array.prototype.getMax = function() { var max = this[0];//谁调用this就是谁 for(var i = 1; i < arr.length; i++) { if(this[i] > max) { max = this[i]; } } return max; }
2、调用函数
<script src="js/MyArray.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var arr=[10,60,80,90,100]; var max=arr.getMax();//调用扩展的功能 alert(max); arr.reverse(); alert(arr); </script>
注意:扩展方式的书写(两种)
五、延伸
继承链和类加载器的联系、sublime
JS的异步调用比Java的注册监听器好多
原生JS
JS的调试,通过控制台(Google--检查--Console)