javascript之原型、原型链
一、原型:
1. 任何函数都有prototype属性(对象才有属性,函数也是对象);
2. 函数的prototype属性的值是个对象,这个对象就是原型(对象);
3. 作用:通过构造函数创建出来的对象可以直接去访问这个构造函数的prototype属性上的任意成员;
function Person(){} /*function fn(){} console.dir(Person); // 以对象形式打印 console.dir(fn); */ // 给原型对象添加color属性 Person.prototype.color = "red"; Person.prototype.legs = 2; // sayHi方法在内存中只有一份,在Person.prototype原型对象中 // 内存浪费问题 Person.prototype.sayHi = function () { console.log("hello is me"); } console.log( Person.prototype ); var p1 = new Person(); console.log(p1.color); // lime p1.sayHi(); var p2 = new Person(); console.log(p2.legs); // 2 p2.sayHi(); // p1的sayHi和p2 的sayHi方法是同一个,地址是相同的 // 这个sayHi方法在 原型对象中 console.log(p1.sayHi == p2.sayHi); // true
小结:
原型:函数的prototype属性的值(对象)
作用:通过构造函数创建出来的实例对象可以直接去访问这个构造函数的prototype属性上的任意成员;
可以使用原型对象来解决构造函数创建对象造成的内存浪费问题;
把需要的方法添加到原型对象中;
原型对象是函数自带的;
二、构造函数 原型对象 实例对象 三者关系
// 构造函数 function Person(){} // Person.prototype 原型对象 Person.prototype.color = "red"; Person.prototype.legs = 2; Person.prototype.sayHi = function () { console.log("hello is me"); } // 实例对象 var p1 = new Person(); console.log(p1.color); // red console.log(p1.legs); // 2 p1.sayHi(); // Person创建的实例 var p2 = new Person(); console.log( p2.color ); console.log( p2.legs ); p2.sayHi(); console.log(p1.sayHi === p2.sayHi);
拟人化理解:
拟人化理解原型三角关系
构造函数 和 原型对象来说:配偶关系
1. 构造函数 通过 prototype属性来访问到原型对象
2. 原型对象 通过 constructor属性来访问到构造函数
构造函数 和 实例对象的关系: 母子关系
1. 构造函数通过new创建出来实例对象
2. 实例对象不能去直接访问到构造函数
原型对象 和 实例对象的关系: 父子关系
1. 实例对象通过__proto__属性访问原型对象上的任意成员
2. 实例对象通过原型对象的constructor属性可以间接的访问构造函数
三、__proto__属性1. 任何对象都有__proto__属性;
2. 对象的__proto__属性的值是指向了当前构造函数的原型对象;
function Person(){} var p = new Person(); console.log(p); console.log( p.__proto__ ); // 原型对象 console.log( p.__proto__ == Person.prototype ); // true
要想访问原型对象,有两种途径:
1. 对于构造函数来说,通过prototype属性可以来访问到原型对象
2. 对象实例对象来说,通过__proto__属性可以来访问到原型对象
该属性的注意点:
__proto__属性 私有属性,不是个标准属性(存有兼容问题,IE678不识别该属性)
不推荐这么去操作原型对象
// p.__proto__.color = "lime";
// 推荐方式: Person.prototype.color = "red"; console.log( Person.prototype );
四、constructor属性
1. 该属性是原型对象自带的;
2. 原型对象的constructor属性的值指向了当前的构造函数;
function Person(){} console.log( Person.prototype ); console.log( Person.prototype.constructor ); // Person 练习题: function Person(){} var p = new Person(); console.log( p.constructor == Person ); // true // p Person的实例对象 // p.constructor ==> p实例对象去原型对象上拿到constructor属性去用的 // ==> Person console.log( p.constructor == Person.prototype.constructor ); // true // Person.prototype.constructor ==> Person // p.constructor ==> Person
五、原型链
// 问题: function Person(){} var p = new Person(); // 问:p实例对象去调用toString方法,这个toString方法在哪? console.log( p.toString() ); // 原型链:对象有 __proto__ 属性, 指向了当前的原型对象,原型对象也是对象,原型对象有__proto__属性,指向了原型对象的原型对象,这样一环套一环形成的链式结构,叫做原型链。 // 形象理解: 孩子有自己的爸爸,自己的爸爸也有爸爸,族谱(原型链) function Person(){} var p = new Person(); console.log( Person.prototype.__proto__ ); // 找爸爸 console.log( Person.prototype.__proto__.constructor );// 找妈妈 console.log( Person.prototype.__proto__ == Object.prototype ); console.log( Object.prototype.__proto__ ); // null // 实例对象p的原型链: // p ==> Person.prototype ==> Object.prototype ==> null;
六、内置对象的原型链
// Array var arr = new Array(); // 实例对象arr的原型链: // arr ==> Array.prototype ==> Object.prototype ==> null; // console.log( Array.prototype.__proto__ ); // console.log( Array.prototype.__proto__.constructor ); // Date var d = new Date(); // 实例对象d原型链: // d ==> Date.prototype ==> Object.prototype ==> null; // Math 本身就是个对象(孩子),不是个构造函数,所以不能new /*var m = new Math(); // error m ==> */ // Math ==> Object.prototype ==> null; // 规律: 任何对象的原型链上都有Object.prototype
七、属性查找原则
// 1. 查找对象的属性的时候,首先会在对象自身上来查找是否有该属性,如果有,就返回属性的值 // 2. 如果没有,去原型对象上去查找,如果有,就返回属性的值 // 3. 如果没有,就会沿着对象的原型链继续在往上找,直到Object.prototype,如果有,就返回属性的值 // 4. 如果还没有,返回undefined // 简单记忆:沿着对象的原型链往上查找 // 注意点:关键看对象身上是否有该属性,而不在乎其值 function Person(name, age){ this.color = "red"; this.name = name; this.age = age; } Person.prototype.name = "lw"; Person.prototype.color = "lime"; Object.prototype.gender = "male"; var p = new Person("xm", 20); console.log(p); // p的原型链: // p ==> Person.prototype ==> Object.prototype ==> null; console.log( p.color ); console.log( p.name ); // xm console.log( p.age ); // 20 console.log( p.gender ); // male console.log( p.sex ); // undefined
案例:
/*function Person(name, age){ this.name = name; this.age = age; } Person.prototype.name = "lw"; Object.prototype.gender = "male"; var p = new Person(0, 0); console.log(p); // p的原型链: // p ==> Person.prototype ==> Object.prototype ==> null; console.log( p.name ); // undefined console.log( p.age ); // undefined console.log( p.gender ); // male console.log( p.sex ); // undefined*/ // 2. function Person(name) { // 有形参,无实参,形参的值undefined if (name) { // if没有执行 this.name = name } } Person.prototype.name = 'ls' Person.prototype.money = 100 var p = new Person() console.log(p.name) console.log(p.money)
八、属性设置原则
// 1. 如果对象有该属性,在设置的时候,其实就是把原来的值给覆盖掉,不会影响到原型上的属性 // 2. 如果对象没有该属性。在设置的时候,其实就是在添加该属性,不会影响到原型上的属性 // 简化理解: 有就覆盖,没有就添加。 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.name = "lw"; Object.prototype.gender = "male"; var p = new Person("xm", 20); // 修改name属性 ==> 因为p自身有 // p.name = "ww"; // 给p添加gender属性,自身本来没有 p.gender = "不清楚"; console.log(p.gender); // 不清楚 console.log(Person.prototype.gender); // male console.log(Object.prototype.gender); // male /*console.log(p.name); // ww console.log(Person.prototype.name); // lw console.log(Object.prototype.name); // undefined*/

浙公网安备 33010602011771号