0:前提知识在函数上下文中,this的指向有很多需要注意的地方:
也就是说,如果函数是作为构造函数的,构造函数中的this指向实例对象,构造函数中定义的方法(不要使用箭头函数)中使用到的this也指向实例对象。 1 function Person (name) { 2 this.name = name; // 如果函数是作为构造函数被调用,this操作符指向该实例。 3 this.sayHello = function() { 4 // 如果函数是作为一个实例对象的方法被调用,this操作符指向该实例。 5 console.log(this.name); // wangting 6 // 如果函数是作为一个实例对象的方法被调用,this操作符指向该实例。 7 console.log(this === person1) // true 8 } 9 this.sayThis = function() { 10 // 打印出此时的this,这里需要特别注意的是,实例对象的原型对象上的属性不在this对象上 11 console.log(this); // Person {name: 'wangting',sayHello: [Function],sayThis: [Function],age: '25' } 12 } 13 } 14 Person.prototype.sayName = function() { 15 // 如果函数是作为一个实例对象的方法被调用,this操作符指向该实例。 16 console.log(this.name); // wangting 17 // 如果函数是作为一个实例对象的方法被调用,this操作符指向该实例。 18 console.log(this === person1); // true 19 }; 20 21 let person1 = new Person('wangting'); 22 // 在实例对象上添加属性(相当与在this对象上添加属性) 23 person1.age = '25'; 24 person1.sayHello(); 25 person1.sayName(); 26 person1.sayThis();
一言以蔽之,
一、原型对象的定义每个函数都有一个prototype属性(原型属性),它是一个指针,指向一个对象,叫作原型对象。 这个对象保存着由函数创建的所有实例(使用new操作符)共享的属性和方法。 有下面几点需要说明:
看下面的代码: 1 function Person (name) { 2 this.name = name; 3 } 4 Person.prototype.age = '25'; 5 Person.prototype.name = 'wangying'; 6 Person.prototype.sayName = function() {console.log(this.name)}; 7 8 let person1 = new Person('wangting'); 9 person1.job = 'IT Engineer'; 10 11 console.log(person1.job); // IT Engineer 12 console.log(person1.age); // 25 13 console.log(person1.name); // wangting 14 person1.sayName(); // wangting job属性的查找过程: person1实例对象本身(找到) age属性的查找过程: person1实例对象本身(没找到) ==》person1实例对象的prototype属性指向的原型对象(找到) name属性的查找过程: person1实例对象本身(找到) sayName方法的查找过程: person1实例对象本身(没找到) ==》person1实例对象的prototype属性指向的原型对象(找到) 用图形表示: 可以理解为,在使用构造函数创建好实例对象后,实例对象与构造函数已经没有直接的联系了,但是,实例对象与原型对象之间一直保持类型,并且在搜索过程中也会去原型对象中寻找。 我们来看一下更复杂的例子,在例子中会有属性覆盖的应用。 1 function Person (name) { 2 this.name = name; // 给实例对象上添加属性name(这个属性会被实例对象本身添加的name属性覆盖) 3 this.age = '25'; // 给实例对象上添加属性age 4 // 给实例对象上添加方法saySex 5 this.saySex = function() { 6 // 获取实例对象的_proto_属性指向的原型对象上的属性sex的值(注意,这里的sex属性并不在实例对象即this对象上) 7 console.log(this.sex); // male 8 } 9 } 10 // 给实例对象的原型对象添加age属性,这个属性会被构造函数中添加的age属性覆盖 11 Person.prototype.age = '55'; 12 // 给实例对象的原型对象添加sex属性 13 Person.prototype.sex = 'male'; 14 Person.prototype.sayName = function() { 15 // 获取实例对象上(实例对象本身添加的)的name属性 16 console.log(this.name); // wangting 17 // 获取实例对象上(构造函数中添加的)的age属性 18 console.log(this.age); // 25 19 // 获取实例对象的_proto_属性指向的原型对象上的属性sex的值(注意,这里的sex属性并不在实例对象即this对象上) 20 console.log(this.sex); // male 21 }; 22 23 let person1 = new Person('othername'); 24 // 在实例对象上添加属性(相当与在this对象上添加属性) 25 person1.name = 'wangting'; 26 person1.saySex(); 27 person1.sayName(); 28 // 打印出person1的this的值 29 (function () {console.log(this)}).call(person1) // { name: 'wangting', age: '25', saySex: [Function] } 30 // 打印出person1的原型对象的值 31 console.log(person1.__proto__) // { age: '55', sex: 'male', sayName: [Function] }
分析
总结:实例对象的搜索过程可以理解为: 实例对象本身定义的属性 =》 构造函数中定义的属性 ==》 原型对象中定义的属性。(实例对象本身定义的属性和构造函数中定义的属性共同组成this对象的属性) 二、原型链通过上面的例子,我们知道,获取实例对象的属性有一个搜索过程, 先在实例对象中查找,然后去实例对象的__proto__属性对应的原型对象上查找。 如果,原型对象中也有一个__proto__属性,那么,在查找完原型对象没有找到属性的情况下,系统会继续查找原型对象的__proto__属性对应的对象,这就形成了搜索属性的链,这个搜索链是由另外一个链组成的,它叫做原型链。 看下面的代码: 1 // Person 2 function Person (name) { 3 this.name = name; 4 } 5 Person.prototype.sayName = function() { 6 console.log(this.name); 7 }; 8 // Student 9 function Student(school) { 10 this.school = school; 11 } 12 // 继承Person 13 Student.prototype = new Person('wangting'); 14 Student.prototype.saySchool = function() { 15 console.log(this.school); 16 } 17 18 let studenta = new Student('NT'); 19 // 实例对象的属性 20 console.log(studenta.school); // NT 21 // 实例对象的__proto__属性对应的原型对象的属性(继承自Person) 22 console.log(studenta.name); // wangting 23 // 实例对象的__proto__属性对应的原型对象的方法 24 studenta.saySchool(); // NT 25 // 实例对象的__proto__属性对应的原型对象的__proto__属性对应的原型对象(继承自Person) 26 studenta.sayName(); // wangting 27 // 打印this对象 28 (function() {console.log(this)}).call(studenta); // { school: 'NT' } 29 // 打印实例对象的原型对象 30 console.log(studenta.__proto__); // { name: 'wangting', saySchool: [Function] } 31 // 打印实例对象的原型对象的原型对象(继承Person) 32 console.log(studenta.__proto__.__proto__); // { sayName: [Function] }
分析:
上面就是使用原型对象实现继承。这也typescript中class的extends的继承方式。
参考: 《javascript高级程序设计》 来源:http://www./content-1-116401.html |
|