JavaScript-17
1.构造函数和原型
在ES6之前,对象不是基于类创建的,而是用一种成为构建函数的特殊函数来定义对象和它们的特征
- 创建对象的方式
- 对象字面量
- new Object()
- 自定义构造函数
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>利用构造函数创建对象</title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 /* 10 在JS中,使用构造函数要注意 11 -构造函数用于创建某一类对象,其首字母要大写 12 -构造函数要和new一起使用才有意义 13 构造函数是一种特殊的函数,主要用来初始化对象 14 */ 15 //1.利用new Object创建对象 16 var obj1 = new Object(); 17 //2.利用对象字面量创建对象 18 var obj2 = {}; 19 //3.利用构造函数创建对象 20 function Star(uname,age){ 21 this.uname = uname; 22 this.age = age; 23 this.sing = function(){ 24 console.log("Monroe"); 25 } 26 } 27 var singer = new Star("bbh",30); 28 console.log(singer); 29 singer.sing(); 30 </script> 31 </body> 32 </html>
- 静态成员和实例成员
- 静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身访问
- 实例成员:在构造函数内部创建的对象称为实例成员,只能由实例化对象来访问
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 function Star(uname,age){ 10 this.uname = uname; 11 this.age = age; 12 this.sing = function(){ 13 console.log("Monroe"); 14 } 15 } 16 var singer = new Star("bbh",30); 17 //1.实例成员就是构造函数内部通过this添加的成员 uname,age,sing就是实例成员 18 //实例成员只能通过实例化的对象来访问 19 singer.sing(); 20 //2.静态成员 在构造函数本身添加的成员 21 Star.sex = "男"; 22 //静态成员只能通过构造函数来访问 23 console.log(Star.sex);//男 24 console.log(singer.sex);//undefined 25 </script> 26 </body> 27 </html>
- 原型:prototype
构造函数通过原型分配的函数时所有对象所共享的
JS规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个prototype就是一个对象,它的所有属性和方法都会被构造函数所拥有,我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 function Star(uname,age){ 10 this.uname = uname; 11 this.age = age; 12 // this.sing = function(){ 13 // console.log("Monroe"); 14 // } 15 } 16 Star.prototype.sing = function(){ 17 console.log("Monroe"); 18 }; 19 var singer = new Star("bbh",30); 20 // console.dir(Star); 21 singer.sing(); 22 //一般情况下我们的公共属性定义到构造函数里面,公共的方法放到原型对象上 23 </script> 24 </body> 25 </html>
- 对象原型
对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为随想有__proto__原型存在
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>对象原型</title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 function Star(uname,age){ 10 this.uname = uname; 11 this.age = age; 12 } 13 Star.prototype.sing = function(){ 14 console.log("Monroe"); 15 }; 16 var singer = new Star("bbh",30); 17 console.log(singer);//在对象身上系统自动添加了一个__prototype__属性,指向我们构造函数的原型对象prototype 18 console.log(singer.__proto__===Star.prototype);//true 19 //方法的查找规则:首先看singer对象上是否有sing方法,如果有就执行对象上的sing 20 //如果没有,就去构造函数的原型对象prototype上查找该方法 21 </script> 22 </body> 23 </html>
- constructor构造函数
对象原型(__proto__)和构造函数(prototype)原型对象里面都有一个属性constructor,我们称之为构造函数,因为它指回构造函数本身。用来记录该对象引用与哪个构造函数,它可以让原型对象重新指向原来的构造函数
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>对象原型</title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 function Star(uname,age){ 10 this.uname = uname; 11 this.age = age; 12 } 13 //很多情况下,我们需要利用constructor指回原来的构造函数 14 // Star.prototype.sing = function(){ 15 // console.log("Monroe"); 16 // }; 17 Star.prototype = { 18 //如果我们修改了原来的原型对象,给原型对象赋值的是一个对虾干,则必须手动利用constructor 19 //指回原来的构造函数 20 constructor:Star, 21 sing:function(){ 22 console.log("Monore"); 23 }, 24 dance:function(){ 25 console.log("solo"); 26 } 27 } 28 var singer = new Star("bbh",30); 29 console.log(Star.prototype); 30 console.log(singer.__proto__); 31 </script> 32 </body> 33 </html>
- 构造函数实例和原型对象三角关系
- 原型链
- JavaScript成员查找机制
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
- 如果还没有就查找原型对象的原型(Object的原型对象)
- y依次类推一直找到Object为止(null)\
- 原型对象的this指向
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 function Star(uname,age){ 10 this.uname = uname; 11 this.age = age; 12 } 13 var that; 14 Star.prototype.sing = function(){ 15 that = this; 16 console.log("lalalalalala"); 17 } 18 var singer = new Star("lala",18); 19 //1.在构造函数中里面的this指向的是对象实例singer 20 singer.sing(); 21 console.log(that === singer);//true 22 //2.原型对象函数里面的this指向的是实例对象singer(调用之后才有指向) 23 </script> 24 </body> 25 </html>
- 扩展内置对象
我们可以通过原型对象,对原来的内置对象进行扩展自定义的方法
注意:数组和字符串内置对象不能给原型对象覆盖操作Array.prototype={},只能是Array.prototype.xxx=function(){}
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //原型对象的应用,扩展内置对象的方法 10 console.log(Array.prototype); 11 Array.prototype.sum = function(){ 12 var count = 0; 13 for(var i = 0 ; i < this.length ; i++){ 14 count += this[i]; 15 } 16 return count; 17 } 18 var arr = [1,2,3]; 19 console.log(arr.sum());//6 20 console.log(Array.prototype); 21 </script> 22 </body> 23 </html>
2.继承
ES6之前没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承
- call()
- 调用这个函数,并且修改函数运行时的this指向
- fun.call(thisArg,arg1,arg2…)
- thisArg:当前调用函数this的指向对象
- arg1、arg2:传递的参数
- 利用父构造函数继承属性
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //利用父构造函数继承属性 10 //1.父构造函数 11 function Father(uname,age){ 12 //this指向父构造函数的对象实例 13 this.uname = uname; 14 this.age = age; 15 } 16 //2.子构造函数 17 function Son(uname,age){ 18 //this指向子构造函数的对象实例 19 Father.call(this,uname,age); 20 } 21 var son = new Son("bbt",16); 22 console.log(son); 23 </script> 24 </body> 25 </html>
- 借用原型对象继承父亲类型方法
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //利用父构造函数继承属性 10 //1.父构造函数 11 function Father(uname,age){ 12 //this指向父构造函数的对象实例 13 this.uname = uname; 14 this.age = age; 15 } 16 Father.prototype.money = function(){ 17 console.log("花钱"); 18 } 19 //2.子构造函数 20 function Son(uname,age){ 21 //this指向子构造函数的对象实例 22 Father.call(this,uname,age); 23 } 24 //Son.prototype = Father.prototype;这样直接赋值会有问题 25 //如果修改了子原型对象,父原型对象也会一起变化 26 Son.prototype = new Father(); 27 //如果利用对象的形式修改了原型对象,利用constructor指回原来的构造函数 28 Son.prototype.constructor = Son; 29 var son = new Son("bbt",16); 30 console.log(son); 31 </script> 32 </body> 33 </html>
- 类
ES6之前通过构造函数+原型对象实现面向对象编程
ES6通过类实现面向对象编程
- 类的本质
- 类的本质还是function
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //ES6中的类实际上就是语法糖 10 //所谓语法糖,就是一种便捷写法 11 class Star { 12 13 } 14 console.log(typeof Star); 15 //1.类的本质其实还是一个函数,我们也可以简单的认为类就是构造函数的另外一种写法 16 //(1)类由原型对象prototype 17 console.log(Star.prototype); 18 //(2)类原型对象的constructor指向类本身 19 console.log(Star.prototype.constructor); 20 //(3)类可以通过原型对象添加方法 21 Star.prototype.sing = function(){ 22 console.log("lalalalalala"); 23 } 24 console.log(Star.prototype); 25 //(4)类的实例的对象原型指向类的原型对象 26 var singer = new Star(); 27 console.log(singer.__proto__ === Star.prototype);//true 28 </script> 29 </body> 30 </html>
3.ES5中新增的方法
- 数组方法
- 迭代方法:forEach()、map()、filter()、some()、every()
- forEach(function(currentValue, index, arr))
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
- forEach(function(currentValue, index, arr))
- 迭代方法:forEach()、map()、filter()、some()、every()
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //forEach迭代(遍历)数组 10 var arr = [1,2,3]; 11 var sum =0; 12 arr.forEach(function(value,index,arr){ 13 console.log('每个数组元素'+value); 14 console.log('每个数组元素的索引号'+index); 15 console.log('数组本身'+arr); 16 sum += value; 17 }) 18 console.log(sum); 19 </script> 20 </body> 21 </html>
-
-
- array.filter(function(currentValue,index,arr){})
- filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
- 注意它直接返回一个数组
- currentValue:数组当前项的值
- index:数组当前项的索引号
- arr:数组对象本身
- array.filter(function(currentValue,index,arr){})
-
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 var arr = [12,56,6,88]; 10 var newArr = arr.filter(function(value,index,arr){ 11 return value > 20; 12 }) 13 console.log(newArr); 14 </script> 15 </body> 16 </html>
-
-
- array.some(function(value,index,arr){})
- some()方法用于检测数组中的元素是否满足指定条件
- 注意它返回的是布尔值,如果查找到这个元素,就返回true,反之则返回false
- 如果找到第一个满足条件的元素,则终止循环,不再继续查找
- array.some(function(value,index,arr){})
-
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //some查找数组中是否有满足条件的元素 10 var arr = [56,4,7,28]; 11 var res = arr.some(function(value,index,arr){ 12 return value>20; 13 }) 14 console.log(res); 15 </script> 16 </body> 17 </html>
-
- 查询商品案例
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <style> 7 * { 8 padding: 0; 9 margin: 0; 10 } 11 12 .box { 13 margin: 20px auto; 14 width: 554px; 15 height: 400px; 16 } 17 18 .search input { 19 display: inline-block; 20 width: 50px; 21 } 22 23 .product { 24 margin-top: 10px; 25 } 26 27 td, 28 table { 29 border: 1px solid #000000; 30 border-collapse: collapse; 31 } 32 33 table { 34 width: 400px; 35 margin: 0 auto; 36 } 37 38 .product td { 39 text-align: center; 40 height: 30px; 41 } 42 43 .hide { 44 display: none; 45 } 46 </style> 47 </head> 48 <body> 49 <div class="box"> 50 <div class="search"> 51 按照价格查找: 52 <input class="low" type="text" />- 53 <input class="top" type="text" /> 54 <input class="price" type="button" value="搜索" /> 55 按照商品名称查找: 56 <input class="name" type="text" /> 57 <input class="info" type="button" value="查询" /> 58 </div> 59 <div class="product"> 60 <table cellspacing="0" > 61 <thead> 62 <tr> 63 <td>id</td> 64 <td>产品名称</td> 65 <td>价格</td> 66 </tr> 67 </thead> 68 <tbody> 69 <tr> 70 <td>1</td> 71 <td>小米</td> 72 <td>3999</td> 73 </tr> 74 <tr> 75 <td>2</td> 76 <td>oppo</td> 77 <td>999</td> 78 </tr> 79 <tr> 80 <td>3</td> 81 <td>荣耀</td> 82 <td>1299</td> 83 </tr> 84 <tr> 85 <td>4</td> 86 <td>华为</td> 87 <td>1999</td> 88 </tr> 89 </tbody> 90 </table> 91 </div> 92 </div> 93 </body> 94 <script type="text/javascript"> 95 //1.按照价格查询 96 var price = document.querySelector(".price"); 97 var info = document.querySelector(".info"); 98 var trs = document.querySelectorAll(".product tr"); 99 price.onclick = function(){ 100 var low = document.querySelector(".low").value; 101 var top = document.querySelector(".top").value; 102 if(low == ''){ 103 low = Number.MIN_VALUE; 104 } 105 if(top == ''){ 106 top = Number.MAX_VALUE; 107 } 108 trs.forEach(function(value,index,arr){ 109 if(index > 0){ 110 if(+value.children[2].innerText > top || +value.children[2].innerText < low){ 111 value.className = 'hide'; 112 }else{ 113 value.className = ''; 114 } 115 } 116 }) 117 } 118 //2.按照商品名字查询 119 info.onclick = function(){ 120 var name = document.querySelector(".name").value; 121 if(name === ''){ 122 trs.forEach(function(value){ 123 value.className = ''; 124 }) 125 }else{ 126 trs.forEach(function(value,index){ 127 if(index > 0){ 128 value.className = 'hide'; 129 if(value.children[1].innerText.includes(name)){ 130 value.className = ''; 131 } 132 } 133 }) 134 } 135 } 136 </script> 137 </html>
-
- some和forEach的区别
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 var arr = ['red','orange','yellow','green','blue','purple']; 10 //1.forEach迭代 遍历 11 // arr.forEach(function(value,index,arr){ 12 // if(value === 'green'){ 13 // //在forEach里面return不会终止迭代 14 // console.log("找到该元素"); 15 // } 16 // }) 17 18 //2.some循环 19 arr.some(function(value,index,arr){ 20 if(value === 'green'){ 21 //在some里遇见return true就是终止遍历 迭代 22 console.log("找到该元素"); 23 return true; 24 } 25 console.log(22); 26 }) 27 </script> 28 </body> 29 </html>
- 字符串方法
- str.trim()方法会从一个字符串两侧删除空白字符,该方法不影响原字符串本身,它返回的是一个新的字符串
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //trim方法去除字符串两端空格,并返回一个新的字符串 10 var str = " BBH "; 11 console.log(str); 12 var res = str.trim(); 13 console.log(res); 14 </script> 15 </body> 16 </html>
- 对象方法
- Object.keys()用于获取对象自身所有的属性
- 效果类似for…in…
- 返回一个由属性名组成的数组
- Object.keys()用于获取对象自身所有的属性
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //用于获取对象自身的所有属性 10 var obj = { 11 id: 1, 12 pname: "小米", 13 price: 1999, 14 num: 2000 15 }; 16 var arr = Object.keys(obj); 17 console.log(arr); 18 </script> 19 </body> 20 </html>
-
- Object.defineProperty()定义新属性或修改原有属性,3个参数无法省略
- Object.defineProperty(obj,prop,descriptor)
- 第三个参数,以对象形式书写
- value:设置属性的值,默认为undefined
- writable:值是否可以重写。默认是false
- enumerable:目标属性是否可以被枚举。默认为false
- configurable:目标属性书否可以被删除或是否可以再次修改特性,默认为false
- Object.defineProperty(obj,prop,descriptor)
- Object.defineProperty()定义新属性或修改原有属性,3个参数无法省略
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 </head> 7 <body> 8 <script type="text/javascript"> 9 //Object.defineProperty()定义新属性或修改原有的属性 10 var obj = { 11 id: 1, 12 pname: "小米", 13 price: 1999, 14 }; 15 //1.以前的对象添加或修改属性的方式 16 // obj.num = 1000; 17 // console.log(obj); 18 //2.Object.defineProperty(obj,prop,descriptor)定义新属性或修改原有的属性 19 //prop如果存在,则是修改属性,不存在则是添加属性 20 Object.defineProperty(obj,'num',{ 21 value: 1000, 22 //不允许修改这个值 23 writable: false, 24 //如果值为false,则不允许遍历,默认为false 25 enumerable: false, 26 //如果值为false,则不允许被删除或是再次修改特性,默认是false 27 configurable: false 28 }) 29 obj.num = 2000; 30 console.log(obj); 31 console.log(Object.keys(obj)); 32 delete obj.num; 33 console.log(obj); 34 //不能再次修改 报错:Cannot redefine property: num 35 // Object.defineProperty(obj,'num',{ 36 // writable: true 37 // }); 38 39 </script> 40 </body> 41 </html>