前言
这篇文章是关于原型的基础知识篇章
原型对象
每个对象都有一个原型 prototype
对象, 通过函数创建的对象也拥有这个原型对象,原型是一个指向对象的指针。
- 可以将原型理解为对象的父亲。对象从原型对象上继承属性
- 原型就是对象,除了是某个对象的父母外没有什么特别的地方
- 所有函数的原型是
Object
的实例 - 使用原型对象为多个对象共享属性或方法
- 如果对象本身不存在属性或方法将到原型上面去查找
- 使用原型可以解决通过构建函数创建对象时复制多个函数造成的内存占用问题
- 原型包含
constructor
属性 指向构造函数 - 对象包含
__proto__
指向他的原型对象
eg: 1.使用数组原型对象上的contact
方法完成链接操作
const list = ['name'];
console.log(list.contact('sex'));
console.log(list)
2.默认情况下创建的对象都有原型
3.以下user
对象和food
对象的原型是一样的
let user= {};
let food = {};
console.log(Object.getPrototypeOf(user) == Object.getPrototypeOf(food)); //true
4.可以创建没有原型的对象
const user = {name:'LL'};
console.log(user.hasOwnProperty('name'));
const food = Object.creat(null,{name:'RR'}) ;
console.log(food.hasOwnProperty(name));//Error
5.对象方法的优先级大于原型方法的优先级
const user = {
show(){console.log('user.show')}
};
user.__proto__.show = function(){console.log('user.__proto__.show')};
user.show();//user.show
6.函数拥有多个原型 prototype
用于实例对象使用 ,__proto__
用于函数对象使用
function User(){}
User.__proto__.show = function(){console.log('user.__proto__.show')};
User.prototype.show = function(){console.log('user.prototype.show')};
const user = new User();
user.show();//user.prototype.show
User.show();//user.__proto__.show
console.log(User.prototype == user.__proto__);//true
Object.prototype.view = function() {
console.log(Object view method");
};
console.log(User.prototype.__proto__ == User.__proto__.__proto__);//true
console.log(User.prototype.__proto__ == Object.prototype);//true
通过上面的案例可以整理出原型关系如下所示
7.使用构造函数创建对象的原型分析
- 构造函数拥有原型
- 创建对象时构造函数吧原型赋值给对象
function User() {}
let t = new User();
console.log(t.__proto__ == User.prototype);
8.constructor
存在于 prototype
原型中,用于指向构建函数的引用
function T() {
this.show = function() {
return "show method";
};
}
const o = new T();
console.log(o instanceof T);//true
const o2 = new o.constructor();
console.log(o2.show()); //show method
9.使用对象的 constructor
创建对象
function User(name, age) {
this.name = name;
this.age = age;
}
function createByObject(obj, ...args) {
const constructor = Object.getPrototypeOf(obj).constructor;
return new constructor(...args);
}
let xb = new User("xb");
let ami = createByObject(xb, "艾米", 12);
console.log(ami);
原型链
通过引用类型的原型,继承另一个引用类型的属性与方法,这就是实现继承的步骤
Object.setPrototypeOf
用于置对象的原型
Object.getPrototypeOf
用于获取一个对象的原型
const eh = { name: 'eh' };
const dog = { move: 'move' };
const animal = { food: 'food' };
Object.setPrototypeOf(eh, dog);
Object.setPrototypeOf(dog, animal);
console.log(eh.move);
console.log(Object.getPrototypeOf(dog) == animal);
原型检测
instanceof
运算符用来检测 constructor.prototype
是否存在于参数 object
的原型链上
function A() {}
function B() {}
function C() {}
const c = new C();
B.prototype = c;
const b = new B();
A.prototype = b;
const a = new A();
console.log(a instanceof A); //true
console.log(a instanceof B); //true
console.log(a instanceof C); //true
console.log(b instanceof C); //true
console.log(c instanceof B); //false
使用isPrototypeOf
检测一个对象是否是另一个对象的原型链中
const a = {};
const b = {};
const c = {};
Object.setPrototypeOf(a, b);
Object.setPrototypeOf(b, c);
console.log(b.isPrototypeOf(a)); //true
console.log(c.isPrototypeOf(a)); //true
console.log(c.isPrototypeOf(b)); //true
属性遍历
使用in
检测原型链上是否存在属性,使用 hasOwnProperty
只检测当前对象
let user= { name: "xb" };
let sex = { type: "n" };
Object.setPrototypeOf(sex, user);
console.log("type" in a);
console.log(user.hasOwnProperty("name"));
console.log(user.hasOwnProperty("type"));
使用 for/in
遍历时同时会遍历原型上的属性
let user = { name: "xb" };
let t = Object.create(user, {
url: {
value: "csdn",
enumerable: true
}
});
for (const key in t) {
console.log(key);
}
借用原型
使用 call
或 apply
可以借用其他原型方法完成功能
let list = {
data: [1, 2, 3, 4, 5]
};
console.log(Math.max.apply(null, Object.values(list.data)));
let list2 = {
lessons: { js: 100, php: 78, node: 78, linux: 125 }
};
console.log(Math.max.apply(null, Object.values(list2.lessons)));
this
this
不受原型继承影响,this
指向调用属性时使用的对象
let user = {
name: "xb"
};
let car= {
name: "bmi",
show() {
return this.name;
}
};
user.__proto__ = car;
console.log(user.show()); //xb