2.js原型的基本概念
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 /** 12 1.什么是原型 13 1-1:构造函数的prototype属性就是原型 14 1-2:只有构造函数才有prototype属性 15 1-3:构造函数一旦被创建,js引擎就帮我们自动创建好了prototype属性 16 1-4:prototype属性的值就是一个对象,主要作用就是用来共享数据 17 */ 18 19 /** 20 2.原型的使用原则 21 2-1:将公用的属性或者方法放在原型上(如果直接放在构造函数上会比较占用内存,浪费资源) 22 2-2:由构造函数创建出来的对象,会默认链接到它的原型上,也就是构造函数的prototype属性上 23 */ 24 // ex 25 var demoObj = function (obj) { 26 this.name = obj.name 27 } 28 console.log(demoObj.prototype, typeof demoObj.prototype) // prototype属性的值是一个对象 29 30 // 尝试给构造函数的prototype属性添加属性 31 demoObj.prototype.siHi = function () { 32 console.log(`哈哈`) 33 } 34 // 实例化对象 35 var newObj = new demoObj({ 36 name: 'ethans' 37 }) 38 // 我们发现实例化的对象直接可访问到构造函数的prototype属性上(这里有一个属性搜索原则的问题(即先去构造函数中查看,如果没有就会上他的原型中去找)) 39 newObj.siHi() 40 41 /** 42 3.非标准属性__proto__ 43 3-1: 实例化出来的对象都有一个__proto__属性 44 3-2:这个属于是非标准的,是浏览器提供的 45 3-3:对象的__proto__和构造函数的prototype指向同一个对象 46 */ 47 console.log(newObj.__proto__ === demoObj.prototype) // true 48 49 /** 50 4.prototype和__proto__的区别于联系 51 4-1:实例对象具有__proto__属性 52 4-2:构造函数具有prototype属性 53 4-3:实例对象的__protp__属性和构造函数的prototype属性指向同一个对象即:newObj.__proto__ === demoObj.prototype 54 4-4: __proto__是一个非标准属性,不要再实际项目中使用,可以再开发阶段用来查看的对象的原型是哪一个 55 */ 56 57 /** 58 5.constructor 59 5-1: 只要是构造函数就会有一个prototype属性; 60 5-2:默认情况下prototype中会有一个constructor属性; 61 5-3:prototype中的constructor属性又指向了当前的构造函数 62 */ 63 console.log(demoObj.prototype.constructor === demoObj) // true 64 </script> 65 </body> 66 </html>
6.prototype和__proto__和constructor三者的关系图
7.属性搜索原则
7.1 先会在对象本身查找,如果找到了该属性,就直接返回
7.2 如果没有找到就会到 原型对象 中查找属性,如果找到了就会返回
7.3 如果在原型中没有找到该属性,会会到 原型对象 的 原型对象 中查找
7.4 直到搜索到 Object.prototype ,如果找到了,就直接返回, 如果还没有找到,就会返回undefined
var Person = function(){}
var p = new Person();
// 给构造函数的原型添加属性
// Person.prototype.name = '小明';
// 给构造函数的原型的原型对象添加属性
// Person.prototype.__proto__.name = '小明';
// 构造函数的原型的原型对象其实质就是Object.prototype
console.log(Person.prototype.__proto__===Object.prototype);//=>true
Object.prototype.name='小明';
console.log(p.name);
// 属性搜索原则,
// 先去构造函数中去找,如果找到了就直接返回,如果没有
// 再去构造函数的原型中去找,如果找到了,就直接返回,如果没有
// 再去构造函数的原型的原型对象中去找,找到了就返回,如果没有
// 再去原型对象的原型对象的原型对象中去找,如果找到了就直接返回,如果还没有就返回undefined
// 翻译成代码就是,Person.prototype=>Person.prototype.__proto__(Object.prototype)=>null
8.查找toString的过程
function Person() { } var p1 = new Person(); // 查找toString方法的过程: // 1 在 p1 中找 // 2 在 Person.prototype 中查找 // 3 在 Person.prototype 的原型中查找 p1.toString(); console.log(p1.__proto__) console.log(p1.__proto__.__proto__) console.log(p1.__proto__.__proto__.__proto__) console.log('toString' in p1.__proto__);//true
9.面向对象的三大特征
封装
将复杂的代码逻辑进行封装,将简单的调用暴露出来
使用函数进行封装;
函数是对一段代码逻辑的封装
目的:是为了对一段代码逻辑进行复用
对象:无序键值对的集合
对象是对数据(属性)和行为(方法的)封装
继承
子类会从父类中继承属性和方法,这样子类就可以使用父类中的方法和属性
多态