JS(四)中级
一、引言
思维角度:以一个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)
上一篇: 原型模式的不足和解决办法