目录
完整的链条
原型
function User(name){
this.name = name;
this.sayHi = function(){
console.log("123");
};
}
let u1 = new User("a");
let u2 = new User("b");
console.log(u1.sayHi === u2.sayHi);
//结果为false
通过构造函数可以创建一个用户对象
这种做法有一个严重的缺陷,就是每个用户对象中都拥有一个sayHi方法,对于每个用户而言,sayHi方法时完全一样的,没必要为每个用户单独生成一个
虽然二者的方法相同,但是占据不同的内存空间,造成浪费,这种问题应该怎么解决呢?
1. 原型
每个函数都会自动附带一个属性prototype,这个属性的值是一个普通对象,称之为原型对象
2. 实例
instance,通过new产生的对象称之为实例
//由于JS中所有对象都是通过new产生的,因此,严格来说,JS中所有对象都称之为实例
3. 隐式原型
每个实例都拥有一个特殊的属性_ _ proto _ _,称之为隐式原型,它指向构造函数的原型
例:
function User(name){} //构造函数
let u1 = new User("a"); //实例
console.log(User.prototype);//构造对象原型
console.log(u1.__proto__);//实例原型
console.log(u1.__proto__ === User.prototype);//true他俩一样
所以,我们可以这样做
function User(name){
this.name = name;
}
User.prototype.sayHi = function(){
console.log(1);
}
let u1 = new User("a");
u1.sayHi();
原型链
Object.prototype._ _ proto _ _比较特殊,它固定指向null
当读取对象成员时,会先看对象自身是否有该成员,如果没有,就依次在其原型链上查找
例1:
function User(){}
let u = new User();
console.log(u.hasOwnProperty);//虽然User里啥都没有,但是原型链上有所以u可以使用hasOwnProperty
例2:
Object.prototype.a = 1;
let b = [1,2,3];
console.log(b.a);//这样会输出结果1
完整的链条
更改构造函数的原型会对所有原型链上有该构造函数的原型的对象产生影响
原型链上函数的调用
//toString方法属于Object.prototype,它会把对象转换为字符串的形式[object Object]
let a = [1,2,3];
console.log(a.toString());//上一级的toString//1,2,3
console.log(Object.prototype.toString.call(a));//这样写就可以使用上上一级的toString//[object Array]
原型链的应用场景
1. 利用原型链判断类型
let arr = [1,2,3];
console.log(arr instanceof Array);//常用
console.log(Object.getPrototypeOf(arr) === Array.prototype);//不常用
2. 创建空原型的对象
let obj1 = Object.create(null); //两种方法
let obj2 = {}
Object.setPrototypeOf(obj2,null);