资讯专栏INFORMATION COLUMN

JavaScript学习总结——原型

Winer / 3115人阅读

摘要:构造函数,实例对象和原型对象的关系实例对象就是通过构造函数创造的,默认拥有一个属性指向其构造函数。

什么是原型

首先,原型是一个对象。而且所有的对象都有一个原型(有一种例外:当把对象的原型设为null时),并且任何对象都可以成为一个原型。

当我们定义一个对象时 var a = new Object(); 默认的原型在原型链的顶端。

原型有什么好处

原型最大的好处体现在它的 共享 的特性。所有原型对象的实例对象共享它所包含的属性和方法。所以我们常用利用原型来创建对象,也就是 原型模式

原型模式

原型模式 是一种用来创建多个实例对象的方法,我们常常把它和 构造函数结合起来用来创建特定类型的对象。

我们创建的每一个函数都有一个 prototype 属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。这个对象就是实际上通过调用构造函数而创建的 实例对象 的原型对象。看代码:

// 构造函数
function Person(){};

Person.prototype.name = "darko";
Person.prototype.age = 21;
Person.prototype.sayName = function(){
    alert(this.name);
}

var person1 = new Person();
person1.sayName();  // "darko"

var person2 = new Person(); 
person2.sayName();  // "darko"

我们将所有的属性和sayName()方法添加到了构造函数Personprototype属性中,构造函数成了空函数。但是即便如此,我们也可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。

构造函数,实例对象和原型对象的关系

实例对象就是通过构造函数创造的,默认拥有一个constructor属性指向其构造函数。

原型对象就是构造函数的属性prototype指向的那个对象,同时也是基于构造函数生成的实例对象的原型对象。在默认情况下,所有的原型对象都会自动获得一个constructor属性,这个属性是一个指针,指向其构造函数。

实例对象可以访问原型对象上的属性和方法。在实例对象的内部有一个属性(内部属性)[[Prototype]]指向其原型对象。有一种非标准方法__proto__访问[[Prototype]]

在上面的例子中person1person2就是实例对象,构造函数为Person,原型对象为Person.prototype

来,看个栗子(还是上面那段代码):

alert(person1.constructor === Person);  // true

alert(Person.prototype.constructor === Person);  // true

alerta(person1.__proto__ === Person.prototype); // true

来看个图你就什么都懂了:

理解prototype,getPrototypeOf和 proto 之间的不同

prototype是函数的一个默认属性,只有函数对象才有

Object.getPrototypeOf()方法用来返回实例对象内部属性[[prototype]]的值。这是ES5中定义的用来获取原型对象的标准方法。

__proto__属性是获取原型对象的非标准方法(IE不支持)
看个栗子(还是上面那段代码):

alert(Object.getPrototypeOf(person1) === Person.prototype); // true
alert(Object.getPrototypeOf(person1).name); // "darko"

alert(person1.__proto__ === Person.prototype);    // true
alert(person1.__proto__.name);  // "darko"
原型模式下的对象

每次查找对象的每个属性,都是一次搜索。搜索从实例对象本身开始,如果在实例对象中找到,停止查找,返回值。如果没有则继续搜索实例对象指向的原型对象。

若实例对象中属性和其指向的原型对象的属性重名,实例对象中的属性屏蔽原型对象中的那个属性。
举个栗子:

function Person(){};

Person.prototype.name = "darko";
Person.prototype.age = 21;
Person.prototype.sayName = function(){
    alert(this.name);
}

var person1 = new Person();
var person2 = new Person();

person1.name = "leon";
person1.sayName();   // "leon",来自实例
person2.sayName()   // "darko",来自原型

delete person1.name;
person1.sayName();  // "darko",来自原型

可以利用hasOwnProperty()方法判断一个属性是位于实例中,还是原型中。只有在属性来自实例中时,才会返回true。通常和in操作符配合使用。

// 接上
alert("name" in person1);   // true
alert(person1.hasOwnProperty("name"));  // false
原生对象的原型

所有的原生引用类型都在其原构造函数的原型上定义了方法,例如,Array.prototype.sort()方法,正是由于原型的共享特性,我们定义的数组才可以使用sort()方法等一系列的方法。
举个栗子:

var num = [1, 5, 3, 7, 9];
num.sort(); // 1,3,5,7,9
alert(num.constructor === Array);   // true
alert(num.__proto__ === Array.prototype);    // true
alert(num.__proto__.__proto__ === Object.prototype);    //true

数组对象num本身就是构造器Array的实例对象,而Arrayprototype属性指向的对象上定义了sort()方法,所以新定义了num对象经过搜索找到了sort()方法,并调用了方法。

原型的动态性

由于在原型中查找值的过程是一次搜索,所以对原型对象的任何修改都能立即从实例上反应出来。
举个栗子:

function Person(){};
var firend = new Person();
// 修改原型
Person.prototype.sayHi = function(){
    alert("Hi");
}

firend.sayHi(); // "Hi"

但是若将原型重写,来看看有什么不同:

function Person(){};
Person.prototype.name = "darko";
var firend = new Person();
// 重写了原型对象
Person.prototype = {
    constructor: Person,  // 注意:重写原型对象,所以此时的constructor属性变成了新对象的构造函数,默认为Object构造函数,应该将其设置回适当的值
    sayHi: function(){
        alert("Hi");
    }
}

alert(friend.name); // "darko"
firend.sayHi(); // error

这说明,重写原型对象切断了现有原型和任何之前已经存在的实例对象之间的联系,它们引用的仍是最初的原型。

如果你觉得我写的还可以,点一下推荐吧。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79187.html

相关文章

  • ES6学习总结(三)

    摘要:不同于其他面向对象语言,以前的中中没有类的概念,主要是通过原型的方式来实现继承,中引入了原型链,并且将原型链用来实现继承,其核心是利用原型使得一个对象继承另一个对象的方法和属性,中原型继承的关键是将一个实例的原型对象指向另一个实例,因此前一 不同于其他面向对象语言,ES6以前的JavaScript中中没有class类的概念,主要是通过原型的方式来实现继承,JavaScript中引入了原...

    baoxl 评论0 收藏0
  • JavaScript学习总结(五)原型原型链详解

    摘要:原型对象内部也有一个指针属性指向构造函数实例可以访问原型对象上定义的属性和方法。在创建子类型的实例时,不能向超类型的构造函数中传递参数。 赞助我以写出更好的文章,give me a cup of coffee? 2017最新最全前端面试题 私有变量和函数 在函数内部定义的变量和函数,如果不对外提供接口,外部是无法访问到的,也就是该函数的私有的变量和函数。 function ...

    EscapedDog 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0
  • JavaScript学习总结(二)数组和对象部分

    摘要:属性是一个值或一组值以数组或对象的形式,是对象的成员。可以使用内置构造函数和创建包装对象。因此下面的代码将会使人很迷惑结果结果,此数组长度为应该尽量避免使用数组构造函数创建新数组。给数组对象添加返回数组中最大元素值的方法。 对象部分 Object类型 Object 是一个无序的集合,可以存放任意类型对象,所有其他对象都继承自这个对象。创建Object类型有两种,一种是使用new运算符,...

    Lsnsh 评论0 收藏0
  • JS笔记

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。异步编程入门的全称是前端经典面试题从输入到页面加载发生了什么这是一篇开发的科普类文章,涉及到优化等多个方面。 TypeScript 入门教程 从 JavaScript 程序员的角度总结思考,循序渐进的理解 TypeScript。 网络基础知识之 HTTP 协议 详细介绍 HTT...

    rottengeek 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<