Javascript 之 Prototype

node.js中看javascript的prototype 编写node.js的代码时常常写Comment.prototype.save=function(callback){....},这个的意义是是什么,这里总结一下!! 阅读详情

1. Prototype 属性

JavaScript 中的 function 本质就是一个 object 对象,它本身包含了一些方法(apply(),call())和一些属性(length, constructor),这其中还包含一个名为 prototype 的属性。
当你定义了一个 function 后,你就能访问到这个 prototype 属性,它的初始值是一个”空”的 object 对象:

function foo() { ... }

typeof foo.prototype;
// "object"

你可以随意设定这个对象,给它加上属性或者方法,但是这不会对这个 function 本身造成任何影响,除非你把它作为构造函数来使用。

使用 prototype 来添加方法和属性

当使用 new 来实例化一个对象时,在 function 内可以通过 this 关键字来对这个对象进行成员追加:

function Gadget(name, color) {
  this.name = name;
  this.color = color;
  this.whatAreYou = function () {
    return 'I am a ' + this.color + ' ' + this.name;
  };
}

另外我们也可以在 function 的 prototype 属性上进行相同的处理:

Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function () {
  return 'Rating: ' + this.rating + ', price: ' + this.price;
};

prototype 对象甚至可以被整个替换:

Gadget.prototype = {
  price: 100,
  rating: ... /* 其他成员... */
};

2. 使用 prototype 的方法和属性

prototype 上添加的方法和属性都能够在实例化后的对象上调用:

var newtoy = new Gadget('webcam', 'black');
newtoy.name;
// "webcam"

newtoy.color;
// "black"

newtoy.whatAreYou();
// "I am a black webcam"

newtoy.price;
// 100

newtoy.rating;
// 3

newtoy.getInfo();
// "Rating: 3, price: 100"

object 对象在 Javascript 中都是以引用方式传递的,所以 prototype 并非在每个实例对象中保存一份。当你改变 prototype 时,所有的实例对象都能立即“察觉”这些变动。假设我们再增加一个新的方法:

Gadget.prototype.get = function (what) {
  return this[what];
};

前文的 newtoy 虽然在此前已经被实例化,但他仍然能使用到这个新方法:

newtoy.get('price');
// 100
newtoy.get('color');
// "black"

自有属性 与 prototype 属性

先前我们定义过一个 getInfo() 方法,它修改为以下的方式后也能获得同样的输出结果:

Gadget.prototype.getInfo = function () {
  return 'Rating: ' + Gadget.prototype.rating + ', price: ' + Gadget.prototype.price;
};

这个原由需要从头说起,先来看 newtoy 对象是怎样实例化的:

var newtoy = new Gadget('webcam', 'black');

当你访问 newtoy 的某个属性的时候(这里假设是 newtoy.name),JavaScript 引擎会搜索它的所有名为 name 的属性,如果发现了就返回它的值:

newtoy.name;
// "webcam"

当你访问 rating 属性时情况变了,JavaScript 引擎在 newtoy 上找不到名为 rating 的属性,然后他就会到 newtoy 的构造函数(Gadget) 的 prototype 属性上继续查找:

newtoy.rating;
// 3

以下的代码验证了这一点:

newtoy.constructor === Gadget;
// true
newtoy.constructor.prototype.rating;
// 3

我们知道每个 object 对象都有一个构造函数,那么作为 object 对象的 prototype 也必然存在一个构造函数。这就形成了一个 prototype chain (prototype 链),这个链的最上层就是内置的 Object() 对象。 要验证这一点很容易,newtoy 没有 toString() 方法,它的 prototype 上也没有,但是你却能调用 newtoy.toString() ,因为 object 对象有这个方法:

newtoy.toString();
// "[object Object]"

自有属性复写 prototype 属性

当自有属性与 prototype 属性重名时,自有属性优先:

function Gadget(name) {
  this.name = name;
}
Gadget.prototype.name = 'mirror';
var toy = new Gadget('camera');
toy.name;
// "camera"

使用 hasOwnProperty() 可以知道某个属性知否是自有属性:

toy.hasOwnProperty('name');
// true

我们把自有属性 name 删了再瞧瞧什么情况:

delete toy.name;
// true
toy.name;
// "mirror"
toy.hasOwnProperty('name');
// false

Enumerating properties

使用 for-in 语句能够遍历出一个对象的所有属性:

虽然 for-in 也适用于数组,但建议遍历数组时采用 for,遍历对象时采用 for-in。

var params = {
  productid: 666,
  section: 'products'
};
var url = 'http://example.org/page.php?',
i,
query = [];
for (i in params) {
  query.push(i + '=' + params[i]);
}
url += query.join('&');

以上代码输出:
http://example.org/page.php?productid=666&section=products

以下几点需要注意:

  • 并非所有属性能够在 for-in 中遍历到,譬如 constructor 属性等等。所有能遍历到的属性称为 enumerable。你可以用 propertyIsEnumerable() 方法来区分,在 ES5 中你甚至可以自定义哪些属性是 enumerable。
  • Prototype 链上的 enumerable 属性也会被遍历到。
  • 由 Prototype 链上而来的 enumerable 属性,被传入 propertyIsEnumerable() 方法时总返回 false。

通过实例来看一下:

function Gadget(name, color) {
  this.name = name;
  this.color = color;
  this.getName = function () {
    return this.name;
  };
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;

var newtoy = new Gadget('webcam', 'black');

for (var prop in newtoy) {
  console.log(prop + ' = ' + newtoy[prop]);
}

// 输出
name = webcam
color = black
getName = function () {
  return this.name;
}
price = 100
rating = 3

再试一下 propertyIsEnumerable() 方法:

// 自有属性
newtoy.propertyIsEnumerable('name');
// true

// 内置属性
newtoy.propertyIsEnumerable('constructor');
// false

// prototype 链上的属性
newtoy.propertyIsEnumerable('price');
// false

// 改变调用对象后
newtoy.constructor.prototype.propertyIsEnumerable('price');
// true

isPrototypeOf()

isPrototypeOf() 可以用来确认某个对象是否另一个对象的 prototype。

var monkey = {
  hair: true,
  feeds: 'bananas',
  breathes: 'air'
};

function Human(name) {
  this.name = name;
}
Human.prototype = monkey;

var george = new Human('George');
monkey.isPrototypeOf(george);
// true

那么当你对 prototype 一无所知时,怎么办呢?对于支持 ES5 的环境,你可以使用 getPrototypeOf() 方法。

> Object.getPrototypeOf(george).feeds;
"bananas"
> Object.getPrototypeOf(george) === monkey;
true

如果遇到不支持 ES5 的环境,你可以使用 __proto__ 这个特殊的属性。

__proto__ 连接

前文提到当你访问一个非自有属性时, 引擎通过 prototype 继续查找:

var monkey = {
  feeds: 'bananas',
  breathes: 'air'
};
function Human() {}
Human.prototype = monkey;

var developer = new Human();
developer.feeds = 'pizza';
developer.hacks = 'JavaScript';

developer.feeds;
// "pizza"

developer.breathes;
// "air"

在现今许多 JavaScript 环境中,都是通过一个名为 __proto__ 的属性来实现的:

developer.__proto__ === monkey;
// true

需要注意的是 __proto__ 与 prototype 是不同的,__proto__ 是一个实例对象的属性,而 prototype 是一个构造函数的属性。

typeof developer.__proto__;
// "object"
typeof developer.prototype;
// "undefined"
typeof developer.constructor.prototype;
// "object"

你应当仅在调试环境中使用这个 __proto__ 属性来获取信息


3. 内置对象的扩展

内置的构造函数(诸如:Array,String 以及 Object)都可以通过 prototype 来进行扩展。见示例:

Array.prototype.inArray = function (needle) {
  for (var i = 0, len = this.length; i < len; i++) {
    if (this[i] === needle) {
      return true;
    }
  }
  return false;
};

var colors = ['red', 'green', 'blue'];
colors.inArray('red');
// true
colors.inArray('yellow');
// false

上面的方法与 apply() 等函数的灵活结合可以写出非常高效的代码。譬如我们为 String 增加一个字符串反转的函数:

String.prototype.reverse = function () {
  return Array.prototype.reverse.apply(this.split('')).join('');
};

代码是不是简洁得出乎你的意料?

内置对象的扩展 – 注意点

扩展内置对象是一个强大的功能,但不应当过度使用,因为对这些内置对象的修改会对使用者和维护者造成困惑。
另外随着各个浏览器的升级,JavaScript 环境也会对这些内置对象进行扩展,这就可能与你的扩展造成冲突。
目前有一些类库致力于在不同的 JavaScript 环境中提供一致的调用接口,这些类库被称之为 shims 或 polyfills。
自行对内置对象的扩展应当谨慎,以下提供一种比较保险的做法:

if (typeof String.prototype.trim !== 'function') {
  String.prototype.trim = function () {
    return this.replace(/^\s+|\s+$/g,'');
  };
}

" hello ".trim();
// "hello"

Prototype 陷阱

当你操作 prototype 时应当牢记以下两点:

  • 如果你替换了整个 prototype 对象,那么你也打断了 prototype 链
  • prototype.constructor 是不可靠的

非常抽象难懂对不对,看个例子你就明白了:

function Dog() {
  this.tail = true;
}
var benji = new Dog();

此时如果你扩展 Dog(),prototype 链能保证已经实例化的 benji 能够使用到新的扩展:

Dog.prototype.say = function () {
  return 'Woof!';
};

benji.say();
// "Woof!"

benji.constructor === Dog;
// true

接着我们整个替换掉 Dog() 的 prototype 会怎样呢?

Dog.prototype = {
  paws: 4,
  hair: true
};

typeof benji.paws;
// "undefined"
benji.say();
// "Woof!"

typeof benji.__proto__.paws;
// "undefined"
typeof benji.__proto__.say;
// "function"

早先实例化的 benji 对象无法访问到扩展成员(paws, hair),但它仍然能调用替换前的成员。

那么对于新的实例对象是什么情况呢?

var lucy = new Dog();
lucy.say();
// TypeError: lucy.say is not a function
lucy.paws;
// 4
typeof lucy.__proto__.say;
// "undefined"
typeof lucy.__proto__.paws;
// "number"

这个新的实例对象显然可以调用到最新的扩展方法,如果你检查一下 constructor 属性你会发现返回值为 Object(),而不是预期的 Dog()。

lucy.constructor;
// function Object() { [native code] }
benji.constructor;
// function Dog() {
//   this.tail = true;
// }

你可以在整个替换 prototype 属性后强行改正 constructor 属性来避免发生这样的困扰。

function Dog() { ... }
Dog.prototype = { ... };
new Dog().constructor === Dog;
// false

// 强行改正 constructor
Dog.prototype.constructor = Dog;
new Dog().constructor === Dog;
// true

强烈建议每次整个替换 prototype 属性后强行设置一下 constructor 属性。


4. 总结

  • 所有 function 都有一个名为 prototype 的属性,初始化时他只是一个空对象。
  • 你可以在这个 prototype 对象上增加属性或方法,也可以整个替换掉它。
  • 当你使用一个 function 来实例化一个对象时,这个对象会保存一个指向 function 的 prototype 属性的链接。
  • 对象的自有属性优先于 prototype 属性。
  • hasOwnProperty() 可以用来区分自有属性和 prototype 属性。
  • JavaScript 的查找本质是在 prototype 链上查找。
  • 内置的构造函数可以扩展,但扩展是需要注意不同的 JavaScript 环境,并在扩展前做好确认检查。
逆变器母线电容选型与均压电阻设计实战指南 本文为逆变器母线电容选型与均压电阻设计提供了实战指南。文章从工程角度出发,详细解析了母线电容耐压值、容值的计算方法,并重点强调了纹波电流热设计的重要性。同时,深入探讨了串联电容均压电阻的设计原则与功率计算,通过5.5kW变频器案例,系统演示了从参数确定到最终选型的完整流程,旨在帮助工程师设计出稳定可靠的逆变器系统。 阅读详情

相关推荐

CSM中一些常见问题的解决方式

CSM中一些常见问题的解决方式 抖动 摄像机在每帧移动或者旋转时,会产生较严重的抖动问题。

小龙虾的博客 2130

理解 JavaScript 中的 Array.prototype.slice.apply(arguments)

这个语法其实不难理解,只是它有些不好看。Array 是 JavaScript 的基本类型,你可以使用 Array.prototype 获取它的属性值,在这里我假设你已经了解了 prototype 的概念。slice 是 JavaScript 的一个方法,用于选取一个数组的一部分数据,并返回一个新的数组。它可以接收两个参数,startIndex(必选)和 endIndex。因此:var a = [“a

陈开心的博客 664

华为开发岗暑期实习笔试(2025年4月16日)

第一题怀疑测试样例不完整,贪心法不应该能够解决该题。第二题使用0-1BFS解决单源最短路径的问题,往往搭配双端队列实现。第三题是运用动态规划解决最大不重叠子区间个数的问题,难点在于满足3重判断规则,所需数据结构及相关操作较多。

csy031117的博客 3661

JS中Array方法中常用方法六:Array.prototype.reverse()

Array.prototype.reverse()颠倒数组中元素的位置。第一个元素会成为最后一个,最后一个会成为第一个。返回该数组的引用。 语法:arr.reverse() 例子:颠倒数组中的元素 var myArray = ['one', 'two', 'three']; myArray.reverse();  console.log(myArray) // ['three', 'tw

...... 811

从厘米级到公里级:北斗网格10级精度在ArcPro中的完整应用指南

本文提供了北斗网格十级精度体系在ArcGIS Pro中的完整应用指南。详细解析了从660公里到1.5厘米的十级网格尺度及其编码逻辑,并重点演示了如何在ArcPro中生成网格、计算编码,以及根据项目需求(如滑坡监测)选择合适精度层级的实战策略。指南旨在帮助GIS专业人士利用这套统一的网格框架,高效管理多尺度空间数据并优化分析工作流。

Black的专栏 470

【AI大模型应用开发】教你用AI轻松将你的知识库变为知识图谱(附完整代码,直接运行)

本文我们来介绍如何使用AI,将自己的知识库自动转换为知识图谱,并进行可视化展示。

同学小张的博客 3925

prototype.js-JavaScript包开发笔记

1. Prototype是什么?或许你还没有用过它, prototype.js(立即下载) 是一个由Sam Stephenson写的JavaScript包。这个构思奇妙编写良好的一段兼容标准的一段代码将承担创造胖客户端, 高交互性WEB应用程序的重担。轻松加入Web 2.0特性。如果你最近体验了这个程序包,你很可能会发现文档并不是它的强项之一。像所有在我之前

baggio785的专栏 2561

ComfyUI 本地部署指南:概念、部署过程、生成图片、共享 WebUI 模型

ComfyUI 是一个基于节点的 Stable Diffusion 图形化用户界面。您可以通过将不同的节点连接在一起来构建生成图像的工作流程。一些常用的节点包括加载检查点模型(Load Checkpoint)、输入提示词(CLIP Text Encode)、指定采样器(KSampler)等。ComfyUI 将工作流程分解为可重新排列的元素,以便您可以轻松创建自己的元素。

水滴的博客 5032

JS中prototype介绍

转载 原文点这里 用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性, 可以为其添加函数供实例访问,其它的就不清楚了,最近看了一些 JavaScript高级程序设计,终于揭开了其神秘面纱。 每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数...

你就是我的世界 3万+

《DeepJIT: An End-To-End Deep Learning Framework for Just-In-Time Defect Prediction》论文笔记

软件工程任务:即时缺陷预测(涉及SE+AI知识)

weixin_43646592的博客 700

matlab 质心重合法实现点云配准【2026最新版】

质心重合法是将源点云和目标点云的质心重合,以此缩小两点云集之间的平移误差,从而为下一步粗配准提供更好的初始位置姿态。

点云侠的博客 509

prototype.js---超强的javascript类库

prototype.js是一个非常优雅的javascript基础类库,对javascript做了大量的扩展,而且很好的支持Ajax,国外有多个基于此类库实现的效果库,也做得很棒。prototype.js不仅是一个有很大实用价值的js库,而且有很高的学习价值。-----------------摘自谭振林(THIN)的prototype.js 1.4版开发者手册。今天才刚刚知道prototy...

deform0032的博客 341

金融数字化——详解2025年金融智能体深度应用报告【附全文阅读】

《2025年金融智能体深度应用报告》显示,金融智能体已实现80%部署率,推动行业效率提升30%-50%。报告指出智能体通过"感知-推理-规划-执行-进化"机制突破大模型局限,在风控、客服、投研等100+场景实现自动化。典型案例显示,工商银行信贷审批效率提升60%,蚂蚁数科智能客服解决80%问题。尽管面临系统协同、标准缺失等挑战,未来趋势将向多模态交互、自主进化和ESG投资等方向拓展。

cdfunlove的博客 203

javascript-js 的prototype原型理解讲解

起初接触到这个prototype我是拒绝的,我还是花了一部分时间来理解这个东西,算不上精通,有什么问题回复在下面毕竟我是板砖挨惯了(滑稽);在我理解看来,prototype不外乎就两个基础的作用: 1.动态的添加类的属性和方法 2.复制原类的内容我们先来看第一个: 首先来定义一个简单的Person类;var Person = function(name,age){ //指定该类的属性为

小辣抓 905

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

prototype.js

prototype.js 是Sam Stephenson写的一个Javascript的小框架(实际上是一个函数库),该框架首页是:http://prototype.conio.net/   prototype.js是一个非常优雅的javascript基础类库,对javascript做了大量的扩展,而且很好的支持Ajax,国外有多个基于此类库实现的效果库,也做得很棒。   pr...

dengyang0029的博客 259

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

prototype 源码解读 之 prototype.js

时间: 2005-7-16 周六, 上午12:34    标题: prototype 源码解读 之 prototype.js 醒来>http://prototype.conio.net/ 我喜欢Javascript,热衷于 Ajax 应用。我把自己阅读prototype源码的体会写下来,希望对大家重新认识 Javascript 有所帮助。 代码:/**  * 定义一个全局对象, 属性 Versio

xiaocon的专栏 2450

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

js 中prototype的使用

js 中prototype的使用  function f() { // body... console.log("事件发生啦!!!"); } f.prototype.a = 1; var f1 = new f(); console.log(f1.a);  

f522011649的博客 852

探索Prototype.js:强大而灵活的JavaScript库

探索Prototype.js:强大而灵活的JavaScript库 去发现同类优质开源项目:https://gitcode.com/ 是一个开放源代码的JavaScript框架,旨在简化和加速Web开发。它通过提供一套丰富的DOM操作API、强大的对象扩展机制和事件处理功能,让开发者能够更高效地编写可维护的JavaScript代码。 技术分析 DOM操作 Prototype.js 提供了一套直观且高...

gitblog_00065的博客 534

使用Javascript和prototype.js框架创建类型及其相关的prototype属性的简单介绍

Javascript中创建对象可归纳为三种方式:工厂函数、构造函数和原型方式。工厂函数方式利用javascript基础类Object,对Object的一个实例增加相应的属性和方法以达到新类型所期望的结果。如下代码展示了类型NewClassType1含有一个属性attribute1。 //工厂函数方式,返回特定类型的对象实例 functionNewClassType1(){

指尖思维 1981

prototype.js ajax,Prototype JavaScript Framework | Introduction to Ajax

Introduction to AjaxPrototype enables you to deal with Ajax calls in a very easy and fun way that is also safe (cross-browser). Besides simple requests, this module also deals in a smart way with Java...

weixin_35299004的博客 292

prototype.js详解

prototype.js是什么? 万一你没有使用过大名鼎鼎的prototype.js,那么让我来告诉你,prototype.js是由Sam Stephenson写的一个javascript类库。这个构思奇妙,而且兼容标准的类库,能帮助你轻松建立有高度互动的web2.0特性的富客户端页面。 如果你最近尝试使用它,你大概了解到文档并不是作者的一个强项。和在我以前使用这个类库...

叶落啼莺 1064

JavaScript :: Prototype

JavaScript :: Prototype Prototype 是一个面相对象的 JavaScript 库,目标是轻松实现动态 WEB 开发。其使用 JavaScript 模拟了 OO 的抽象、继承等特性,还提供了对表单、效果、Ajax 等的 OO 操作方式,使用起来很自然、方便。最初 Prototype 的开发是为了 Ruby on Rails 框架,但对于 JavaScript 库而言,其

xiaocon的专栏 1163

Prototype教程(prototype框架和js中的prototype对象的区别)

http://prototypejs.org/learn/ http://api.prototypejs.org/ https://github.com/prototypejs/prototype

nmj2008的博客 237

prototype.js ajax.request,prototype

在JavaScript中,prototype对象是实现面向对象的一个重要机制。每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。中文名实现面向对象机制外文名prototype性质JS对象应用JavaScript人物Sam Stephensonpro...

weixin_32431435的博客 388

用 RomM 管理 CHD 光盘镜像,一张 PS2 镜像从 4.7GB 压到约 2GB

RomM 能把光盘类镜像识别并转换成 CHD 压缩格式,PS1 镜像体积通常缩掉约一半,1TB 硬盘装得下原本 2.5TB 的收藏。下面的教程教你怎么把这件事跑通,以及参数该怎么选。 ## 先算笔账:改造前后的硬盘账本 🔍 一张 PS2 光盘镜像(bin/cue)约 4.7GB,实际游戏数据往往不到一半。换成 CHD 之后: - PS1 镜像:约 1.4GB → 0.6~0.8GB,缩掉

gitblog_00568的博客 353

简述 JavaScript 中 prototype

这篇笔记主要捋一下这么几个概念:JS 是通过 prototype chaining 实现继承的语言,所有的基类都会绑定在 prototype chain 上如: 本身就暴露了当前对象的 ,它所指向的是另一个对象,也就是 prototype chain 上的继承 (粗暴的理解一下就是父类)。返回的对象又可以通过调用 继续获得父类的 ,一步步向上追溯一直到 为 为止,一般到这个时候,也是获取到 Object 了——JS 之中,除了 primitive type,万物皆对象。需要注意的是, 返回的对象是

GoldenaArcher的博客 1163
上一篇: 最佳 .NET 资源清理策略
下一篇: Javascript 继承篇
sqlchen
博客等级 码龄24年 10粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值