什么是面向对象 学过java的都懂 简单来说就是将 变量 方法 等 封装到对象里
我们在其他地方 只需要通过这个对象就能调用 对象里的 内容
用法也和java 差不多
第一种 通过new Object(); 来创建对象的方式
<script> //第一种创建对象的方式 属性和方法 都用引号隔开 var flpwer = new Object(); //给对象添加 属性 flpwer.name = "长花村"; flpwer.genera = "鸡爪萨达"; //给对象添加方法 flpwer.show = function() { alert(this.name); } flpwer.show1 = function() { alert(this.genera); } //调用对象内的方法 flpwer.show(); </script>
第二种 创建对象的方式 使用{ }
<script type="text/javascript"> //第二种创建对象的方法 属性 和方法 都要用逗号隔开 var flower = { name: "hello", gender: "男", show: function() { var str = this.name + "<br>" + this.gender document.write(str); }, show1: function() { alert("你好") } } //调用 对象内的方法 flower.show() </script>
第三种方式 模板方式
我们可以观察上面案例中 创建对象的2种方式 都是直接生成一个对象了
而我们修改直接就是在修改这个对象内的数据 就和java中被 static 修饰的属性感觉一样
这样的好处就是 可以实现数据同步 在某一个地方 将此对象内的数据修改后 其他调用的地方都会被修改
但是在很多情况下 都不需要数据同步 但是我也不想在创建一个新的了 怎么办 ?
很简单 我们可以 先创建一个模板 就行了
<script type="text/javascript"> //创建一个模板 function Flower() { this.name; this.gender="男"; //给模板添加 方法 this.show = function() { alert("姓名:"+this.name+"___"+"年龄:"+this.gender); }; } // 创建对象 1 var f= new Flower(); f.name="hell" f.show() // 创建对象 2 var f1= new Flower(); f1.name="abc" f1.show() </script>
在上面的创建方法 都有各自的缺陷 比如直接创建的对象 无法复用 使用模板创建的对象就无法数据共享了
我们就可以使用原型对象 来满足这个要求 既能复用 还能共享
演示:
需要创建一个空模板
内部不需要添加任何东西 否则报错 就是一个空函数就行了
给模板添加 属性和方法
语法:模板名称.prototype.属性或方法
//创建一个空模板 function Flower() {} //给模板 添加属性 Flower.prototype.name ; Flower.prototype.gender = "男"; //给模板添加 方法 Flower.prototype.show = function() { alert("姓名:"+this.name+"___"+"年龄:"+this.gender); } //创建对象 var flower1 = new Flower(); //给对象 赋值 flower1.name="曼陀罗"; //调用对象内的 方法 flower1.show() var flower2 = new Flower(); flower2.name="白鹤湖"; flower2.show()
我们想要通过模板模型 实现数据同步怎么办 就和java中被static修饰的 效果一样
语法:
模板名称.prototype.属性或者方法 等同于java中的 类名.属性或者方法
这种方式 是全局共享的 和对象无关
演示:
<script type="text/javascript"> //创建一个模板 function Flower() {} //给模板 添加属性 Flower.prototype.name ; Flower.prototype.gender = "男"; //给模板添加 方法 Flower.prototype.show = function() { alert("姓名:"+this.name+"___"+"年龄:"+this.gender); } // 静态的调用方式 Flower.prototype.name = "长存2312"; Flower.prototype.name = "长存"; Flower.prototype.show() //对象调用方式 var f1=new Flower(); f1.name="hell"; f1.show() </script>
总结:
**定义方式: **原型对象和普通对象 在定义方面的区别 就是 原型对象必须在模板后面手动声明prototype的方法
而普通对象直接在模板内部定义普通方法就行
调用方式 : 如果没有使用 prototype定义方法那么 调用的时候也就不能使用 prototype来调用方法
构造就和 java使用效果一样 主要作用就是能在 new 对象的时候进行初始化
在js 中 构造参数不必都进行赋值 当然也可以指定默认值
普通构造对象
<script type="text/javascript"> //创建构造对象 function Fow(name, gender = "男") { //创建属性 this就是指向这个新的对象属性 this.name = name; this.gender = gender; //创建方法 this就是指向这个新的对象方法 this.show = function() { alert(this.name + "___" + this.gender); } } //给构造赋值 var fow1 = new Fow("haha"); //调用对象方法 fow1.show(); //给构造赋值 fow1 = new Fow("ha", "女"); //调用对象方法 fow1.show(); </script>
原型构造对象
和普通构造的区别就是 方法不能在内部定义 必须在外部指定 prototype
<script type="text/javascript"> //创建构造对象 function Fow(name, gender) { //创建属性 this就是指向这个新的对象属性 this.name = name; this.gender = gender; } //创建方法 this就是指向这个新的对象方法 Fow.prototype.show = function() { alert(this.name); } Fow.prototype.name = "hello" Fow.prototype.show() var f1=new Fow("word"); f1.show() </script>
在 JavaScript 中, 判断一个变量的类型尝尝会用 typeof 运算符, 在使用 typeof 运算符时采用引用类型存储值会出现一个问题, 无论引用的是什么类型的对象, 它都返回“ object”。 ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。 instanceof 运算符与 typeof 运算符相似, 用于识别正在处理的对象的类型
<script type="text/javascript"> function Fow(name,gender){ //创建属性 this.name=name; this.gender=gender; } //给将带参函数赋值 并且 给一个对象 var fow1=new Fow("haha","男"); var fow2=new Fow("ha","男"); document.write(fow1 instanceof Fow); //true document.write(fow1 instanceof Object); //true </script>
就和java中的逻辑一样 就是语法不同而已
普通对象方式继承
<script type="text/javascript"> //创建一个模板 function Flower() { this.name="hu"; //给模板添加 方法 this.Name = function() { alert("姓名:"+this.name+"___"); }; } function Flower1() { this.gender="男"; //给模板添加 方法 this.Genter= function() { alert("年龄:"+this.gender); }; } Flower1.prototype=new Flower(); var ff1=new Flower1(); ff1.Name() ff1.Genter() </script>
原型对象继承
//创建一个原型Humans function Humans() { this.foot = 2; } //给原型添加 方法 Humans.prototype.getFoot = function() { return this.foot; } //创建一个原型Man function Man() { this.head = 1; } Man.prototype.getHead = function() { return this.head; } // 使Man原型继承 Humans所有 Man.prototype = new Humans(); //Map 继承了 Humans的所有 var man1 = new Man(); document.write(man1.getFoot() + "<br>") //使用map 读取Humans 里面 的 getFoot方法 结果 2 document.write(man1.getHead() + "<br>") //读取自身 的 getHead方法 结果 1 //进行判断 判断 man1是否是 Humans的实现类 或者是其子类 document.write(man1 instanceof Humans, "<br>") //true //进行判断 判断 man1是否是 Man的实现类 或者是其子类 document.write(man1 instanceof Man) //true
子类继承父类 有时候要重写父类 的方法 或者 添加新的方法 但是不管怎么样 给原型添加方法的代码一定要放在 继承语句的后面
普通对象
<script type="text/javascript"> //定义父类 function Humans() { this.foot = 2; //给父模板创建方法 this.getFoot = function() { return this.foot; } } //定义子类 function Man() { this.head = 1; //给Map添加新的方法 this.getHead = function() { return this.head; } } //Map 继承了 Humans的所有 Man.prototype = new Humans(); //重写父类方法 要和父类的方法名一样 Man.prototype.getFoot = function() { //使用本类的 属性 return this.head; } var man1 = new Man(); //调用重写后的Man里的getFoot方法 不是调用Humans里的getFoot方法 document.write(man1.getFoot()) //结果1 </script>
原型对象
<script type="text/javascript"> //定义父类 function Humans() { this.foot = 2; } //给父模板创建方法 Humans.prototype.getFoot = function() { return this.foot; } //定义子类 function Man() { this.head = 1; } //Map 继承了 Humans的所有 Man.prototype = new Humans(); //给Map添加新的方法 Man.prototype.getHead = function() { return this.head; } //重写父类方法 要和父类的方法名一样 Man.prototype.getFoot = function() { //使用本类的 属性 return this.head; } var man1 = new Man(); //调用重写后的Man里的getFoot方法 不是调用Humans里的getFoot方法 document.write(man1.getFoot()) //结果1 </script>
继承 数组时候 会出现的问题<br> <script type="text/javascript"> function Humans() { this.foot = 2; this.cloo = ["sadsa", "dadsff"]; } Humans.prototype.getFoot = function() { return this.foot; } function Man() { this.head = 1; } //Map 继承了 Humans的所有 Man.prototype = new Humans(); var man1 = new Man(); //给man1对象内的数组添加值 man1.cloo.push("ggg"); var man2 = new Man(); document.write(man1.cloo + "<br>"); document.write(man2.cloo) </script>
结果:
//sadsa,dadsff,ggg
//sadsa,dadsff,ggg
可以发现我只在man1 对象中添加了ggg 我man2 怎么也出现了ggg 因为数组是对象
我们保存的只是地址而已 这就会造成 所有对象的数组地址 都是一样 也就是说某一个对象 修改了 数组
那么其他 对象中的数组也发生变化了
为了解决此问题 出现了借用构造函数
使用 父类.call(this,”参数1”,”参数2” ………) 调用父类的带参函数
和java中的super()一样的效果 调用父类构造
无参构造
<script type="text/javascript"> //创建父类 function Humans() { this.coo = ["dsadaf", "fagga"]; } //创建子类 function Man() { //调用父类无参构造 Humans.call(this); //定义属性 this.name="abc"; } //对象1 var man1 = new Man(); man1.coo.push("aaaa"); //对象2 var man2 = new Man(); console.log(man1.coo ); console.log(man2.coo) console.log(man2.name) </script>
结果:
[“dsadaf”, “fagga”, “aaaa”]
[“dsadaf”, “fagga”]
abc
<script type="text/javascript"> //父类 function Humans(age) { //带参 this.coo = ["dsadaf", "fagga"]; this.age=age; } //子类 function Man(name,age) { //调用父类带参构造 Humans.call(this, age); //定义属性 this.name=name; } //对象1 var man1 = new Man("hell",12); man1.coo.push("aaaa"); console.log(man1.coo ); console.log(man1.name) //对象2 var man2 = new Man("wolr",14); console.log(man2.coo) console.log(man2.name) </script>
结果:
[“dsadaf”, “fagga”, “aaaa”]
hell
[“dsadaf”, “fagga”]
wolr
和java一样的效果 前提必须保证是继承关系 否则就会报错了
向下转型
创建一个父类对象 然后在创建一个子类对象 将父类对象付给子类对象
向上转型
创建一个父类对象 然后在创建一个子类对象 将子类对象付给父类对象
<script type="text/javascript"> function Humans(name){ this.name=name; } Humans.prototype.sayname=function(){ console.log(this.name); }; function Man(name,age){ Humans.call(this,name); //继承构造 this.age=age; } // Man 继承 Humans Man.prototype=new Humans(); //创建父类对象 var hu=new Humans("hu"); //创建子类对象 var man=new Man("wo",12); man.sayname() //wo //----------父向子转--------向下转型 man=hu man.sayname() //hu //-----------子向父转----- 向上转型 hu=man hu.sayname() //hu </script>
是不是感觉 好像 是覆盖了 但是 其实并没有
我们来判断先对象的类型
//创建父类对象 var hu=new Humans("hu"); //创建子类对象 var man=new Man("wo",12); man.sayname() //结果wo //----------父向子转--------向下转型 man=hu man.sayname() //结果hu console.log(man instanceof Humans)//true console.log(man instanceof Man)//false //-----------子向父转----- 向上转型 hu=man hu.sayname() //hu console.log(hu instanceof Humans)//true console.log(hu instanceof Man)//false
可以发现类型 也变了 变成 转换后的类型