• 前端分享学习博客,探究前端相关技术,推动天朝前端发展,有任何问题都可以留言一起探究
  • 由于站内自链接问题,部分pre中的代码首字母使用大写以过滤筛选
  • 欢迎友链互换,还有,如果有大神请不要黑我的站点(o´・ェ・`o)
  • 如果你觉得博客还不错,请Ctrl+D收藏( *︾▽︾)

JavaScript笔记之Prototype

jQuery/JavaScript 薛 陈磊 826次浏览 1个评论 扫描二维码

原型(Prototype)是JavaScript中的基本概念之一,是必须要掌握的内容;在充分理解原型之前要先清楚JavaScript中的对象(Object)和继承的概念,因为在JavaScript中只有一种结构,就是对象(Object),而每个对象都有一个内部链接链接到另一个对象,这就是原型(Prototype);

关于原型的两个基本概念:

1.在JavaScript中,每个对象(object)都有原型属性(prototype property),创建对象时没有定义的情况下是空的,当你调用对象/函数的时候,就可以使用对象/函数上的属性或方法(methods),并且原型属性是不可枚举的,也就是说,它不能在for / in循环中访问使用;但是Firefox、Safari和Chrome都有一个_proto_“伪”属性(替代语法),可以借助_proto_来访问对象的原型属性,这个不常用;原型属性多用于继承(inheritance),可以在对象的原型属性上添加属性和方法,并用对象的实例还使用访问这些属性和方法,看一个例子:

function PrintStuff(myDocuments) {
this.documents = myDocuments;
}

// We add the print() method to PrintStuff prototype property so that other instances (objects) can inherit it:
PrintStuff.prototype.print = function() {
console.log(this.documents);
}

// Create a new object with the PrintStuff() constructor, thus allowing this new object to inherit PrintStuff's properties and methods.
var newObj = new PrintStuff("I am a new Object and I can print.");

// newObj inherited all the properties and methods, including the print method, from the PrintStuff function. Now newObj can call print directly, even though we never created a print () method on it.
newObj.print(); //I am a new Object and I can print.

2.第二个JavaScript中关于原型的概念是prototype attribute(也被译作原型属性,注意与上一条的区别:JavaScript中attribute与property的区别);原型属性prototype attribute是JavaScript对象的特征之一,这个特征指明了一个对象被实例的原始对象:对象的原型属性指向对象的“父”级对象,也就是实例对象继承自的对象;原型属性(prototype attribute)通常被称为原型对象(prototype object),并在创建新对象时自动设置;每一个对象都会继承一些其他对象的属性,可以理解为实例出的新对象通过原型属性prototype attribute来继承对象属性,如果是创建一个全新的对象,不是new 继承自其他父级对象,这个新对象是继承了全局对象window;


关联知识点:构造函数

构造函数(constructor)是被用来构建一个新对象的函数,并且可以用new关键字来调用:

function Account() {
}
// This is the use of the Account constructor to create the userAccount object.
var userAccount = new Account ();

此外,所有的对象会从另一个对象继承,也从构造函数属性继承;And this constructor property is simply a property (like any variable) that holds or points to the constructor of the object;

//The constructor in this example is Object()
var myObj = new Object();
// And if you later want to find the myObj constructor:
console.log(myObj.constructor); // Object()

// Another example: Account() is the constructor
var userAccount = new Account(); 
// Find the userAccount object's constructor
console.log(userAccount.constructor); // Account()

对象的原型属性会通过new Object()和对象字面量的方式来创建(Prototype Attribute of Objects Created with new Object () or Object Literal);使用对象字面量和Object构造函数创建的所有对象都将继承自Object.prototype;因此,Object.prototype是使用new Object()或{ }创建的所有对象的原型属性(或原型对象),Object.prototype本身不继承其他对象的任何方法或属性;

// The userAccount object inherits from Object and as such its prototype attribute is Object.prototype.
var userAccount = new Object ();

// This demonstrates the use of an object literal to create the userAccount object; the userAccount object inherits from Object; therefore, its prototype attribute is Object.prototype just as the userAccount object does above.
var userAccount = {name: “Mike”}

对象的Prototype Attribute 通过构造函数创建,使用new关键字和Object()构造函数以外的任何构造函数创建的对象从构造函数获取它们的原型;

function Account() {

}
var userAccount = new Account() // userAccount initialized with the Account () constructor and as such its prototype attribute (or prototype object) is Account.prototype

比如,任何数组array,如var myArray = new Array(),从Array.prototype获取其原型,并继承了Array.prototype的属性;

所以,有两种创建对象时设置对象的原型属性(prototype attribute)的方式:

1.如果对象是通过对象字面量(var newObj = {})来创建的,它从Object.prototype继承属性,我们说这个对象的原型对象(或prototype属性)是Object.prototype,也就是上面的var myArray=new Array()中实例出的myArray有Array的一切属性;

2.如果一个对象是通过构建函数构建比如new Object()、new Fruit()或者new Anything(),以new Fruit()举例说明,每次我们创建一个新的Fruit实例(var aFruit = new Fruit())时,新的实例aFruit的原型将从Fruit构造函数中继承原型,也就是Fruit.prototype;使用新的Array()创建的任何对象将以Array.prototype作为其原型,使用新的Fruit()创建的对象将以Fruit.prototype作为其原型,所以使用Object构造函数 (Obj(), such as var anObj = new Object())构建的对象从Object.prototype继承;

原型为什么这么重要,什么时候使用?

原型在JavaScript中有两种重要的使用方式,let's note as above:

1.Prototype Property:原型基于继承

原型在JavaScript中很重要,因为JavaScript没有基于类的经典继承,因此,通过prototype property可以实现JavaScript中的所有继承;JavaScript具有基于原型的继承机制,继承是一种编程思想,其中对象(或某些语言的Classes)可以从其他对象(或类)继承属性和方法,在JavaScript中,可以使用prototype property来实现继承;比如,我们可以创建一个Fruit函数(也是一个对象,实际上JavaScript中所有的函数都是对象)并且在这个函数上通过prototype property添加属性和方法,那么所有继承Fruit的实例都会继承Fruit的属性和方法,看一个例子:

function Plant() {
this.country = "Mexico";
this.isOrganic = true;
}

// Add the showNameAndColor method to the Plant prototype property
Plant.prototype.showNameAndColor =  function() {
console.log("I am a " + this.name + " and my color is " + this.color);
}

// Add the amIOrganic method to the Plant prototype property
Plant.prototype.amIOrganic = function() {
if (this.isOrganic)
console.log("I am organic, Baby!");
}

function Fruit(fruitName, fruitColor) {
this.name = fruitName;
this.color = fruitColor;
}

// Set the Fruit's prototype to Plant's constructor, thus inheriting all of Plant.prototype methods and properties.
Fruit.prototype = new Plant();

// Creates a new object, aBanana, with the Fruit constructor
var aBanana = new Fruit("Banana", "Yellow");

// Here, aBanana uses the name property from the aBanana object prototype, which is Fruit.prototype:
console.log(aBanana.name); // Banana

// Uses the showNameAndColor method from the Fruit object prototype, which is Plant.prototype. The aBanana object inherits all the properties and methods from both the Plant and Fruit functions.
console.log(aBanana.showNameAndColor()); // I am a Banana and my color is yellow.

例子中的showNameAndColor方法被对象aBanana继承,即使它是在Plant对象的原型链上定义的;

2.Prototype Attribute: 访问对象上的属性

原型对于访问对象中的属性和方法也很重要,所有对象的prototype attribute都是指向了被继承的父级对象;类似于一个人的姓氏来自他的父亲,一个刚出生的小娃娃身上找不到姓氏痕迹,找到他的父亲也就可以了;

同样的,如果要访问一个对象上的属性,会直接从当前对象检索,如果找不到这个属性,然后它会查找对象的原型上的属性,如果在对象的原型上找不到属性,则搜索该属性然后移动到该对象的原型的原型,直到最顶级的原型也被检索,这本质上就是原型链(prototype chain):对象的原型到其原型的原型以及之后原型的链;而JavaScript使用这个原型链来查找对象的属性和方法,如果原型链上也找不到该属性,就会返回undefined;

看一个原型链的示例:

var myFriends = {name: "Pete"};

// To find the name property below, the search will begin directly on the myFriends object and will immediately find the name property because we defined the property name on the myFriend object. This could be thought of as a prototype chain with one link.
console.log(myFriends.name);

// In this example, the search for the toString () method will also begin on the myFriends’ object, but because we never created a toString method on the myFriends object, the compiler will then search for it on the myFriends prototype (the object which it inherited its properties from).

// And since all objects created with the object literal inherits from Object.prototype, the toString method will be found on Object.prototype—see important note below for all properties inherited from Object.prototype.

myFriends.toString();

关联知识点:Object.prototype属性由所有对象继承

JavaScript中的所有对象都继承Object.prototype的属性和方法,继承的属性和方法是constructor、hasOwnProperty(),isPrototypeOf(), propertyIsEnumerable(), toLocaleString(), toString(), and valueOf();

原型链的另一个例子:

function People () {
this.superstar = "Michael Jackson";
}
// Define "athlete" property on the People prototype so that "athlete" is accessible by all objects that use the People () constructor.
People.prototype.athlete = "Tiger Woods";

var famousPerson = new People ();
famousPerson.superstar = "Steve Jobs";

// The search for superstar will first look for the superstar property on the famousPerson object, and since we defined it there, that is the property that will be used. Because we have overwritten the famousPerson’s superstar property with one directly on the famousPerson object, the search will NOT proceed up the prototype chain.
console.log (famousPerson.superstar); // Steve Jobs

// Note that in ECMAScript 5 you can set a property to read only, and in that case you cannot overwrite it as we just did.

// This will show the property from the famousPerson prototype (People.prototype), since the athlete property was not defined on the famousPerson object itself.
console.log (famousPerson.athlete); // Tiger Woods

// In this example, the search proceeds up the prototype chain and find the toString method on Object.prototype, from which the Fruit object inherited—all objects ultimately inherits from Object.prototype as we have noted before.
console.log (famousPerson.toString()); // [object Object]

所有内置构造函数(Array(),Number(),String()等)都是从Object构造函数创建的,因此它们的原型是Object.prototype;


reference:http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language

如翻译/理解有误,欢迎指出:)

PS:es6中有了class的概念,在很多场景下prototype的使用和考察并不是必须的了,可以去了解class部分,毕竟要跟得上技术的更新啊;


薛陈磊的博客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明JavaScript笔记之Prototype
喜欢 (0)
[905044086@qq.com]
分享 (0)
作者薛陈磊
关于作者:
非著名前端Coder,中二非文艺闷骚少年,喜欢动漫、历史、暗荣三国志和游山玩水,关注互联网发展,期待遇到更多小伙伴一起吹水玩耍;
说点什么...
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. 您好,您的网站做的很不错,很漂亮,我已经收藏了,方便我随时访问.
    混砂机2017-06-09 16:41 回复 Windows 7 | Chrome 47.0.2526.108