js中原型、原型链、继承的理解(透彻)
- 1、前言
- 1.1 什么是函数对象
- 1.2 什么是实例对象
- 1.3 什么是原型对象
- 1.4 构造函数、原型对象、实例对象的关系
- 2、原型
- 3、原型链
- 4、原型的相关属性及方法
- 5、总结
1、前言
1.1 什么是函数对象
普通函数:
function person(){console.log(this); // Window
}
person()
构造函数:
function Person() {console.log(this); // Person{}
}
let p = new Person();
1.2 什么是实例对象
ES5:
// ES5:生成实例对象的传统方法是通过构造函数
function Person(name, age) {this.name = name;this.age = age;
}Person.prototype.sayName = function () {alert(this.name);
};var person1 = new Person("张三", 29);
var person2 = new Person("李四", 27);
ES6:
// ES6可通过class关键字定义类
class Person {constructor(name, age) {this.name = name;this.age = age;}sayName() {alert(this.name);}
}// ES6使用类时也是直接对类使用new命令
var person1 = new Person("Nicholas", 29);
var person2 = new Person("Greg", 27);
person1和person2都是Person类的实例对象(实例都是对象)
1.3 什么是原型对象
我们在创建函数的同时,浏览器会在内存中创建一个对象。这个函数中默认有一个prototype属性,指向了该对象。这个对象就是函数的原型对象,简称函数的原型。
每个构造函数都有一个原型对象存在,这个原型对象通过构造函数的prototype属性来访问。原型对象默认会有一个constructor属性指向构造函数。
1.4 构造函数、原型对象、实例对象的关系
构造函数、原型对象、实例对象的关系:
2、原型
3、原型链
4、原型的相关属性及方法
★ prototype:每个函数都有一个prototype属性,这个属性指向函数的原型对象。
★ proto:每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。
★ constructor:每一个原型都有一个constructor属性,指向该关联的构造函数。
prototype 和 proto 区别是什么?
● prototype是构造函数的属性
● __proto__是每个实例都有的属性,可以访问 [[prototype]] 属性
● 实例对象的__proto__与其构造函数的prototype指向的是同一个对象
★ hasOwnProperty() 方法
它的作用是判断函数的原型所在位置。一个对象本身添加的属性返回true,在原型中的属性和不存在的属性都会返回false。
//创建构造函数
function Person(){}
//使用Person.prototype直接访问到原型对象
// 给Person函数的原型对象中添加一个属性name,值是"小明"
// Person.prototype.name = "小明";
Person.prototype = {constructor:Person, //让constructor重新指向Person函数/*如果直接给Person的原型指定对象字面量(没有上面这一行),这个对象的constructor属性不再指向Person函数*/name: "小明"
};//创建一个实例对象p1
var p1 = new Person();//访问p1对象的属性name
p1.age = 18;console.log(Person.prototype.constructor === Person); // true//如果在Person.prototype中没有constructor:Person这一行代码则输出flase
//Person.prototype.name = "小明";这种写法输出也是trueconsole.log(p1.__proto__ === Person.prototype); // true//如果在Person.prototype中没有constructor:Person这一行代码则输出flase
//Person.prototype.name = "小明";这种写法输出也是trueconsole.log(p1.name); // 小明 /*虽然在p1对象中没有明确的添加属性name,但是仍然可以成功打印的原因是:p1的__proto__属性指向的原型中有name属性,所以可以访问到属性name值。*/console.log(p1.hasOwnProperty("age")); // true
//因为age属性是直接在p1属性中添加的console.log(p1.hasOwnProperty("name")); // false
//因为name属性是在原型中添加的console.log(p1.hasOwnProperty("sex")); // false
//因为sex属性不存在
5、总结
- JavaScript中的对象,都有一个内置属性[Prototype],指向这个对象的原型对象。当查找一个属性或方法时,如果在当前对象中找不到,会继续在当前对象的原型对象中查找;如果原型对象中依然没有找到,会继续在原型对象的原型中查找(原型也是对象,也有它自己的原型);直到找到为止,或者查找到最顶层的原型对象中也没有找到,就结束查找,返回undefined。这个查找过程是一个链式的查找,每个对象都有一个到它自身原型对象的链接,这些链接组建的整个链条就是原型链。拥有相同原型的多个对象,他们的共同特征正是通过这种查找模式体现出来的。
- 在上面的查找过程,我们提到了最顶层的原型对象,这个对象就是Object.prototype,这个对象中保存了最常用的方法,如toString、valueOf、hasOwnProperty等,因此我们才能在任何对象中使用这些方法。
本文链接:https://my.lmcjl.com/post/1558.html
展开阅读全文
4 评论