原型 & 原型链
- 所有对象都是通过
new 函数
创建 - 所有的函数也是对象
- 函数可以有属性和方法
- 所有对象都是引用类型
原型 prototype
原型: 任何一个JS对象创建时会关联的一个对象 任何根据原型的构造函数创建出来的对象,都会继承原型上的属性
- 所有函数都有一个
prototype
属性 - 默认情况下,
prototype
属性是一个普通的Object对象 - 默认情况下,prototype对象有一个属性
constructor
,它也是一个对象,指向构造函数本身
隐式原型__proto__
- 所有的对象都有一个
__proto__
属性,称为隐式原型 - 默认情况下,隐式原型指向创建该对象的函数的原型
javascript
function test() {}
var obj = new test();
obj.__proto__ === test.prototype // true
javascript
function create() {
if (Math.random() < 0.5) {
return {}
} else {
return []
}
}
var obj = create();
// 得到创建obj的构造函数名称
console.log(obj.__proto__.constructor.name)
当访问一个对象的成员时:
- 看该对象自身是否有该成员,如果有直接使用
- 在原型链中依次查找是否有该成员,如果有直接使用
原型链
原型链: 原型链是一个对象到另一个对象的链接,它是由__proto__属性连接起来的一系列对象,直到到达null(即对象查找属性的过程) 特殊点:
- Function的
__proto__
指向自身的prototype - Object的
prototype
的__proto__
指向null
图解原型链
面试题
javascript
// 面试题一
var F = function() {};
Object.prototype.a = function () {}
Function.prototype.b = function () {}
var f = new F();
console.log(f.a, f.b, F,a, F.b)
// function () {} undefined function() {} function() {}
javascript
// 面试题二
function A() {}
function B(a) {
this.a = a;
}
function C(a) {
if (a) {
this.a = a;
}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a) // 1
console.log(new B().a) // undefined
console.log(new C(2).a) // 2
javascript
// 面试题三
function User() {}
User.prototype.sayHello = function() {}
var u1 = new User();
var u2 = new User();
console.log(u1.sayHello === u2.sayHello); //true
console.log(User.prototype.constructor); //User Function
console.log(User.prototype === Function.prototype); // false
console.log(User.__proto__ === Function.prototype); // true
console.log(User.__proto__ === Function.__proto__); // true
console.log(u1.__proto__ === u2.__proto__); // true
console.log(u1.__proto__ === User.__proto__); // false
console.log(Function.__proto__ === Object.__proto__); // true
console.log(Function.prototype.__proto__ === Object.prototype.__proto__); // false
console.log(Function.prototype.__proto__ === Object.prototype); // true
原型链的应用
基础方法
Object.getPrototypeOf(对象) 获取对象的原型 Object.prototype.isPrototypeOf(对象) 判断当前对象(this)是否在指定对象的原型链上 对象 instanceof 函数 判断函数的原型是否在对象的原型链上 Object.create(原型对象,属性对象) 创建一个对象,其隐式原型指向指定的对象 Object.prototype.hasOwnProperty(属性名) 判断一个对象自身是否拥有某个属性
应用
类数组转换为真数组
javascript
Array.prototype.slice.call(arguments); // arguments为类数组
实现继承 默认情况下,所有构造函数的父类都是Object
javascript
// 实现继承
function inhreit(Son, Father) {
// 第一种方案
// Son.prototype = Father.prototype; // 容易造成原型链污染
// 第二种方案
// Son.prototype = Object.create(Father.prototype); // 创建一个对象,其隐式原型指向父类的原型对象prototype
// 第三种方案
var F = function () {
};
F.prototype = Father.prototype;
Son.prototype = new F();
Son.prototype.constructor = Son; // 修正构造函数指向
// Son.prototype.uper = Father; // 增加父类引用
Son.prototype.uper = Father.prototype; // 增加父类原型对象引用
}
function User(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.fullName = firstName + " " + lastName;
}
User.prototype.sayHello = function () {
console.log(`大家好,我是${this.fullName},今年${this.age}岁了!`)
}
function VipUser(firstName, lastName, age, money) {
User.call(this, firstName, lastName, age)
this.money = money;
}
inhreit(VipUser, User)
VipUser.prototype.upgrade = function () {
console.log(`使用${this.money}元,升级VIP会员!`)
}
const vUser = new VipUser('Tom', 'Hanks', 25, 10000)