JavaScript的原型与原型链

原型与原型链

什么是原型?

在声明定义函数时,函数都会有一个prototype属性,这个属性就是一个指针,指向一个对象,而这个对象就是原型对象(简称原型)

原型的作用?

通过构造函数创建的实例对象,可以直接访问到构造函数的prototype属性上(即原型对象)的属性和方法

什么是原型链?

对象有__proto__属性, 属性值指向了当前的原型对象, 原型对象也是对象, 原型对象也有__proto__属性,原型对象的__proto__属性值指向了原型对象的原型对象, 这样一环套一环,形成的链式结构叫做原型链

原型链图解

image

原型链特点:

  • 实例对象的隐式原型(__proto__)等于构造函数的显示原型(prototype
 f1.__proto__ === Foo.prototype //true
  • 所有的函数都是Function的实例,即函数都是通过new Function产生的
 Foo.__proto__ === Function.prototype //true  
 Date.__proto__ === Function.prototype //true  
 Object.__proto__ === Function.prototype //true
  • Function也是new自己产生的,即Function的隐式原型等于自己的显示原型
 Function.__proto__ === Function.prototype //true
  • 原型对象也是对象,所以原型对象也是new Object产生的,即原型对象的隐式原型指向Object的显示原型
 Foo.prototype.__proto__ === Objecct.prototype //true  
 Function.prototype.__proto__ === Objecct.prototype //true
  • Object的原型,是原型链的尽头
 Object.prototype.__proto__ === null //true
  • 原型对象自带constructor,该属性指向当前的构造函数
 Foo.prototype.constructor === Foo  //true  
 Object.prototype.constructor === Object  //true  
 Function.prototype.constructor === Function  //true

注意点:

  • 实例对象上只有__proto__属性
  • 函数上有prototype属性和__proto__属性
  • 原型对象上有constructor属性和__proto__属性

属性查找原则

  1. 首先在对象自身上来查找是否有该属性, 如果有, 就返回属性值.
  2. 如果没有, 就去对象的原型对象上来查找, 如果有, 就返回属性值.
  3. 如果也没有, 就沿着对象的原型链继续往上找, 直到Object.prototype, 如果有, 就返回属性值.
  4. 如果还没有, 返回undefined

    简化记忆: 沿着对象的原型链往上找

注意点: 关键看对象上是否有该属性, 而不在乎其值是啥

属性设置原则

  1. 如果对象自身有该属性, 设置的话就是在修改操作, 只会影响到对象自身, 不会影响到原型和原型链上的属性.
  2. 如果对象自身没有该属性, 设置的话就是在给对象添加该属性, 只会影响到对象自身, 不会影响到原型和原型链上的属性.

简单记忆: 有就修改, 没有就添加

面试题:

 

function Person(name, age){  
  // ****有形参, 无实参, 形参是undefined*****  
  this.name = name;  
  this.age = age;  
 }  
 ​  
 Person.prototype.name = "lw";  
 Object.prototype.gender = "male";  
 ​  
 // 变化的点  
 var p = new Person();  
 ​  
 console.log(p);  
 ​  
 // p实例对象的原型链  
 //  p ==> Person.prototype ==> Object.prototype ==> null;  
 ​  
 console.log(p.name); // undefined ****  
 console.log(p.age); // undefined  ****  
 console.log(p.gender); // male  
 console.log(p.sex); // undefined
 function Person(name) {  
  // name ==> undefined  
  if (name) {  
  this.name = name;  
  }  
 }  
 ​  
 Person.prototype.name = "ls";  
 Person.prototype.money = 100;  
 ​  
 var p = new Person();  
 ​  
 console.log(p);  
 ​  
 // p实例对象自身没有name属性  
 ​  
 console.log(p.name); // ls      undefined   
 console.log(p.money); // 100    100
 function A() {  
 ​  
 }  
 A.prototype.n = 1;  
 ​  
 var b = new A();  
 ​  
 A.prototype = {  
  n:2,  
  m:3  
 }  
 ​  
 var c = new A();  
 ​  
 console.log(b.n, b.m, c.n, c.m) //1 undefined 2 3
 function F() {}  
 Object.prototype.a = function () {  
  console.log('a()')  
 }  
 Function.prototype.b = function () {  
  console.log('b()')  
 }  
 ​  
 var f = new F();  
 f.a() //a()  
 f.b() //报错   
 F.a() //a()  
 F.b() //b()

补充

  • instanceof判断复杂数据的具体类型的原理是什么?
A intanceof B

如果B的显示原型属性指向的对象在A的原型链上,则返回true,否则返回false

  • instanceof的底层原理,手动实现一个instanceof
 /*   
  封装一个instanceof的具体实现  
  参数:  
  A: 实例对象  
  B: 构造函数  
  返回值:true或者false  
  */  
 function myInstanceof(A, B) {  
  // 判断A的数据类型,如果A是简单数据类型或者null,则直接返回false  
  var styleA = typeof A  
  if((styleA !== 'function' && styleA !== 'object') || styleA === null) {  
  return false  
  }  
  // 判断B构造函数的显示原型是否在A实例对象的隐式原型上  
  var protoA = A.__proto__  
  while(protoA !== null) {  
  if(protoA === B.prototype) {  
  return true  
  }  
  protoA = protoA.__proto__  
  }  
  return false  
 }
阅读 220

推荐阅读