深入总结Javascript原型及原型链

本篇文章给大家详细分析了javascript原型及原型链的相关知识点以及用法分享,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。

《深入总结Javascript原型及原型链》

我们创建的每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个原型对象,而这个原型对象中拥有的属性和方法可以被所以实例共享

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true
//欢迎加入前端全栈开发交流圈一起学习交流:864305860

一、理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 第 5 版中管这个指针叫 [[Prototype]] 。
虽然在脚本中没有标准的方式访问 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性proto ;而在其他实现中,这个属性对脚本则是完全不可见的。
不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。
以前面使用 Person 构造函数和 Person.prototype 创建实例的代码为例,图 6-1 展示了各个对象之间的关系。

《深入总结Javascript原型及原型链》

在此, Person.prototype 指向了原型对象,而 Person.prototype.constructor 又指回了 Person 。
person1 和 person2 都包含一个内部属性,该属性仅仅指向了 Person.prototype ;换句话说,它们与构造函数没有直接的关系。
可以调用 person1.sayName() 。这是通过查找对象属性的过程来实现的。(会先在实例上搜索,如果搜索不到就会继续搜索原型。)

用isPrototypeOf()方法判断实例与原型对象之间的关系<br>alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)) //true
<br><br>用Object.getPrototypeOf() 方法返回实例的原型对象
<br>alert(Object.getPrototypeOf(person1) == Person.prototype); 
//true<br><br>使用 hasOwnProperty() 
方法可以检测一个属性是存在于实例中,还是存在于原型中。<br>alert(person1.hasOwnProperty("name")); //false  
来着原型<br>person1.name = "Greg";
<br>alert(person1.name);
 //"Greg"——来自实例<br>alert(person1.hasOwnProperty("name")); 
/true<br>//欢迎加入前端全栈开发交流圈一起学习交流:864305860

二、更简单的原型语法

前面例子中每添加一个属性和方法就要敲一遍 Person.prototype 。为减少不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象。

function Person(){
}
Person.prototype = {
  name : "Nicholas",
  age : 29,
  job: "Software Engineer",
  sayName : function () {
    alert(this.name);
  }//欢迎加入前端全栈开发交流圈一起学习交流:864305860
};

在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外: constructor 属性不再指向 Person 了。
前面曾经介绍过,每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性。

var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true
//欢迎加入前端全栈开发交流圈一起学习交流:864305860

在此,用 instanceof 操作符测试 Object 和 Person 仍然返回 true ,但 constructor 属性则等于 Object 而不等于 Person 了。
如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。

function Person(){
}
Person.prototype = {
  constructor : Person,
  name : "Nicholas",
  age : 29,
  job: "Software Engineer",
  sayName : function () {
    alert(this.name);
  }//欢迎加入前端全栈开发交流圈一起学习交流:864305860
};

三、原生对象的原型

所有原生引用类型( Object 、 Array 、 String ,等等)都在其构造函数的原型上定义了方法。
例如,在 Array.prototype 中可以找到 sort() 方法,而在 String.prototype 中可以找到substring() 方法。尽管可以这样做,但不推荐修改原生对象的原型。

四、原型对象的问题

原型模式的最大问题是由其共享的本性所导致的。 修改其中的一个,另一个也会受影响。

function Person(){
}
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
friends : ["Shelby", "Court"],
sayName : function () {
alert(this.name);
}//欢迎加入前端全栈开发交流圈一起学习交流:864305860
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

五、原型链

其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。然后层层递进,就构成了实例与原型的链条,这就是所谓原型链的基本概念。

function SuperType(){
  this.property = true;
}//欢迎加入前端全栈开发交流圈一起学习交流:864305860
SuperType.prototype.getSuperValue = function(){
  return this.property;
};
function SubType(){
  this.subproperty = false;
}//欢迎加入前端全栈开发交流圈一起学习交流:864305860
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
  return this.subproperty;
};//欢迎加入前端全栈开发交流圈一起学习交流:864305860
var instance = new SubType();
alert(instance.getSuperValue()); //true

《深入总结Javascript原型及原型链》

property 则位于 SubType.prototype 中。这是因为 property 是一个实例属性,而 getSuperValue() 则是一个原型方法。既然 SubType.prototype 现在是 SuperType的实例,那么 property 当然就位于该实例中了

结语

感谢您的观看,如有不足之处,欢迎批评指正。

加入我们一起聊天吹水学习

为了帮助大家让学习变得轻松、高效,大家可以加入我们vue/react/node交流君吹水学习交流:1018782135欢迎大家进群交流讨论,学习交流,共同进步。

    原文作者:前端攻城小牛
    原文地址: https://www.jianshu.com/p/76595d7346cc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞