JS原型链

1. 构造函数,原型与实例

JavaScript诞生的时候,为了使语言简单易学,没有引入当时流行的面向对象编程中的“类”class,为了实现继承,作者做了一个简化的设计,由于C++和Java使用new命令时,都会调用"类"的构造函数,在Javascript语言中,new命令后面跟的不是类,而是直接写构造函数(constructor)。

function Man(){
      
 this.name = name;
}

let man1 = new Man('张三');

但是用构造函数生成实例对象时,无法共享属性和方法。并且,如果我们在构造函数中定义了方法,那么这个方法会在每个实例上都重新创建一遍,会产生不同的作用域和标识符,导致不同实例上的同名函数是不相等的。

function Man(){
      
 this.name = name;
 this.sex = "male";
 this.sayName = function(){
     
 	return this.name
 }
}

let man1 = new Man('张三');
let man2 = new Man('李思');

//如果修改man2的sex属性,man1不会改变
man2.sex = "female";
console.log(man1.sex);   //male
//不同实例上的同名函数不相等
console.log(man1.sayName == man2.sayName);  //false

为了节省资源和数据共享,引入了prototype原型对象。用来存放所有实例对象需要共享的属性和方法,而不需要共享的方法就放在构造函数中。实例对象一旦创建,将自动引用prototype对象的属性和方法。

function Man(){
      
 this.name = name;
}

Man.prototype.country = ‘china’
let man1 = new Man('张三');
let man2 = new Man('李思');

console.log(man1.country);   //china
console.log(man2.country);   //china

2.原型链的基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。

每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针__proto__。 如果我们将原型对象等于另一个类型的实例,此时的原型对象包含指向另一个原型的指针,另一个原型对象中也包含指向另一个构造函数的指针,假设另一个原型对象又是其他类型的实例,像这样层层递进,就形成了实例与原型的链条,这就是原型链。

JS原型链_第1张图片

function Man(){
      
 this.name = name;
}

//在构造函数man的原型上定义一个属性
Man.prototype.needFoods = true;

function chinese(){
     
  this.country = 'china';
}

//将men的实例作为chinese的原型
chinese.prototype = new Man()

//在chinese的原型上添加一个属性,添加的属性一定要放在原型替换语句之后,否则会undefined
chinese.prototype.speak = "chinese"

let man1 = new chinese('张三');
console.log(man1.needFoods); //true
console.log(man1.speak); //chinese

构造函数的原型是Function.prototype
Function.prototype的原型是Object.prototype

console.log(Man.__proto__ == Function.prototype); // true
console.log(Man.__proto__.__proto__ == Object.prototype); // true

3.判断对象类型的方法

  1. A instanceof B 检测B构造函数的 prototype 属性是否出现A的原型链上
console.log(man1 instanceof Man) //true
console.log(man1 instanceof chinese) //true
console.log(man1 instanceof Object) //true
  1. B.isPrototypeOf(A)用于检测B的原型对象是否存在于A的原型链上,与instanceof 不同的是,它是通过[[Prototype]](_proto_)来直接判断。需要带上prototype。
console.log(Man.prototype.isPrototypeOf(man1)) //true
console.log(chinese.prototype.isPrototypeOf(man1)) //true
console.log(Object.prototype.isPrototypeOf(man1)) //true
  1. Object.getPrototypeOf(A)该方法会直接返回A.__proto__的值
console.log(Object.getPrototypeOf(man1)) //  Man {name: "", speak: "chinese"}
console.log(Object.getPrototypeOf(man1) == chinese.prototype) //true
  1. hasOwnProperty用于检测一个属性是存在于实例中
console.log(man1.hasOwnProperty('country')) // 实例属性 true
console.log(man1.hasOwnProperty('speak')) // speak定义在原型上 false

但是,在hasOwnProperty返回false的时候,也有可能是不存在该属性,如何判断该属性在原型上呢?
in操作符用来判断一个对象能否访问到某个属性

console.log('country' in man1) // true
console.log('speak' in man1) // true

如果某个属性在in操作符下返回true&&在hasOwnProperty下返回false,就可以确定该属性是原型上定义的属性了。

你可能感兴趣的:(JS)