关于js原型的一些知识点

定义原型

原型实际上就是一个普通对象,继承于 Object 类,由 JavaScript 自动创建并依附于每个函数身上,原型在 JavaScript 对象系统中的位置和关系如图所示。
请添加图片描述

Object 和 Function 是两个不同类型的构造函数,利用运算符 new 可以创建不同类型的实例对象。实例对象、类、Object 和 Function 之间的关系如图所示。请添加图片描述
使用点语法,可以通过 function.prototype 访问和操作原型对象。
示例
在下面代码中为函数 P 定义原型。
下面展示一些 内联代码片

function P (x) {  //构造函数
    this.x = x;  //声明私有属性,并初始化为参数x
}
P.prototype.x = 1;  //添加原型属性x,赋值为1
var p1 = new P (10);  //实例化对象,并设置参数为10
P.prototype.x = p1.x;  //设置原型属性值为私有属性值
console.log(P.prototype.x);  //返回10

访问原型

访问原型对象有 3 种方法,简单说明如下:
obj.proto
obj.constructor.prototype。
Object.getPrototypeOf(obj)。
其中,obj 表示一个实例对象,constructor 表示构造函数。proto(前后各两个下划线)是一个私有属性,可读可写,与 prototype 属性相同,都可以访问原型对象。Object.getPrototypeOf(obj) 是一个静态函数,参数为示例对象,返回值是参数对象的原型对象。

proto 属性是一个私有属性,存在浏览器兼容性问题,以及缺乏非浏览器环境的支持。使用 obj.constructor.prototype 也存在一定风险,如果 obj 对象的 constructor 属性值被覆盖,则 obj.constructor.prototype 将会失效。因此,比较安全的用法是使用 Object.getPrototypeOf(obj)。
示例
下面代码创建一个空的构造函数,然后实例化,分别使用上述三种方法访问实例对象的原型。

var F = function () {};  //构造函数
var obj = new F();  //实例化
var proto1 = Object.getPrototypeOf(obj);  //引用原型
var proto2 = obj.__proto__;  //引用原型,注意,IE暂不支持
var proto3 = obj.constructor.prototype;  //引用原型
var proto4 = F.prototype;  //引用原型
console.log(proto1 === proto2);  //true
console.log(proto1 === proto2);  //true
console.log(proto1 === proto4);  //true
console.log(proto2 === proto3);  //true
console.log(proto2 === proto4);  //true
console.log(proto3 === proto4);  //true

设置原型

设置原型对象有 3 种方法,简单说明如下:
obj.proto=prototypeObj.
Object.setPrototypeOf(obj, prototypeObj)。
Object.create(prototypeObj)。
其中,obj 表示一个实例对象,prototypeObj 表示原型对象。注意,IE 不支持前面两种方法。
示例
下面代码简单演示利用上述三种方法为对象直接量设置原型。

var proto = {name : "prototype"};  //原型对象
var obj1 = {};  //普通对象直接量
obj1.__proto__ = proto;  //设置原型
console.log(obj1.name);
var obj2 = {};  //普通对象直接量
Object.setPrototypeOf(obj2, proto);  //设置原型
console.log(obj2.name);
var obj3 = Object.create(proto);  //创建对象,并设置原型
console.log(obj3.name);

检测原型

使用 isPrototypeOf() 方法可以判断该对象是否为参数对象的原型。isPrototypeOf() 是一个原型方法,可以在每个实例对象上调用。
示例
下面代码简单演示如何检测原型对象。

var F = function () {};  //构造函数
var obj = new F();  //实例化
var proto1 = Object.getPrototypeOf(obj);  //引用原型
console.log(proto1.isPrototypeOf(obj));  //true

也可以使用下面代码检测不同类型的实例。

var proto = Object.prototype;
console.log(proto.isPrototypeOf({}));  //true
console.log(proto.isPrototypeOf([]));  //true
console.log(proto.isPrototypeOf(//));  //true
console.log(proto.isPrototypeOf(function () {}));  //true
console.log(proto.isPrototypeOf(null));  //false

原型属性和私有属性

原型属性可以被所有实例访问,而私有属性只能被当前实例访问。
如果给构造函数定义了与原型属性同名的私有属性,则私有属性会覆盖原型属性值。
如果使用 delete 运算符删除私有属性,则原型属性会被访问。
私有属性可以在实例对象中被修改,不同实例对象之间不会相互干扰。
原型属性将会影响所有实例对象,修改任何原型属性值,则该构造函数的所有实例都会看到这种变化,这样就省去了私有属性修改的麻烦。
prototype 属性属于构造函数,所以必须使用构造函数通过点语法来调用 prototype 属性,再通过 prototype 属性来访问原型对象。原型属性于私有属性之间的关系如图所示。请添加图片描述
Object 和 Function 都可以定义原型,它们的属性与原型关系如图所示。请添加图片描述

应用原型

下面通过几个示例介绍原型在代码中的应用技巧。
示例1
利用原型为对象设置默认值。当原型属性与私有属性同名时,删除私有属性之后,可以访问原型属性,即可以把原型属性值作为初始化默认值。

function p (x) {  //构造函数
    if (x) {  //如果参数存在,则设置属性,该条件是关键
        this.x = x;  //使用参数初始化私有属性x的值
    }
}
p.prototype.x = 0;  //利用原型属性,设置私有属性x的默认值
var p1 = new p ();  //实例化一个没有带参数的对象
console.log(p1.x);  //返回0,即显示私有属性的默认值
var p2 = new p (1);  //再次实例化,传递一个新的参数
console.log(p2.x);  //返回1,即显示私有属性的初始化值

示例2
利用原型间接实现本地数据备份。把本地对象的数据完全赋值给原型对象,相当于为该对象定义一个副本,也就是备份对象。这样当对象属性被修改时,就可以通过原型对象来恢复本地对象的初始值。

function p (x) {  //构造函数
    this.x = x;
}
p.prototype.backup = function () {  //原型方法,备份本地对象的数据到原型对象中
    for (var i in this) {
        p.prototype[i] = this[i];
    }
}
var p1 = new p (1);  //实例化对象
p1.backup;  //备份实例对象中的数据
p1.x = 10;  //改写本地对象的属性值
console.log(p1.x);  //返回10,说明属性值已经被改写
p1 = p.prototype;  //恢复备份
console.log(p1.x);  //返回1,说明对象的属性值已经被恢复

示例3
利用原型进行批量复制。

function f (x) {  //构造函数
    this.x = x;  //声明私有属性
}
var a = [];  //声明数组
for (var i = 0; i < 100; i ++) {  //使用for循环结构批量复制构造类f的同一个实例
    a[i] = new f (10);  //把实例分别存入数组
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值