js函数prototype属性学习(一)
W3school上针对prototype属性是这么给出定义和用法的:使您有能力向对象添加属性和方法。再看w3school上给的那个实例,如下图:

仔细一看,原来最基本的作用就是对某些对象的属性、方法来扩展,我对这个实例又多写了几句代码进行测试,如下:
var steve= new empolyee("Steve Jobs","enterpriser",1977);
这里我专门查看了steve这个实体所拥有的属性,发现多了一个salary属性,这个属性是新建实体时未曾定义的,可见由于prototype的作用,employee这个对象有了新的属性salary,那么,prototype到底是何方神圣,它在js对象里到底有着怎样不可或缺的作用呢?
javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。在javascript中并没有类的概念,但JavaScript中的确可以实现重载,多态,继承。这些实现其实方法都可以用JavaScript中的引用和变量作用域结合prototype来解释。原型法的主要思想是,现在有1个类A,我想要创建一个类B,这个类是以A为原型的,并且能进行扩展。我们称B的原型为A。
给人的感觉,A类就特别像java里的被继承的那个基础类,而B类继承后的实体子类,对B类的扩展就像多态,或者已有方法的重写,很面向对象有木有,这就是javascript带给我们最好的礼物,虽没有直接表明自己支持面向对象,但背地里却默默的支持着。再来看javascript的方法都有哪些种类。
1、类方法
var Person = {
};
Person.say = function(){
alert("I can say language");
};
2、对象方法
function Person(name){
this.name = name;
this.interduceSelf= function(){
alert("my name is " + this.name);
};
};
3、原型方法
Person.prototype.interduceSelfChinses = function(){
alert("我的名字是 " + this.name);
};
Person.say();
var person1 = new Person("xiaoming");
person1.interduceSelf(); //结果是my name is xiaoming
person1.interduceSelfChinses(); //结果是 我的名字是 xiaoming
var person2 = new Person("xiaozhang");
person2.interduceSelf(); //结果是my name is xiaozhang
person2.interduceSelfChinese(); //结果是 我的名字是 xiaozhang
由此我们可以看到,只要新增了一个对象的prototype属性中的方法,这个方法就成为了这对象的共有方法,不管你后来新建的是什么实体,都具有了这个共有方法,并且存在于它的_proto_属性里,如图:

可以看到,并没有对所有的人赋予新方法interduceSelfChinese,都自动的就有这个公共方法了,这是因为当一个对象被创建时,构造函数会把它的属性prototype赋给新对象的内部属性_proto_,这个_proto_属性被这个对象用来查找它的prototype属性,包括里面的属性、方法,都被查找出来,该调用时即调用。这样就有一个好处了,你不需要每次在构造一个对象的时候创建并初始化这个函数,继承就这样实现了,只不过严格的说,js并没提供继承这个概念,可以说新建的实体都是原来对象的一个拷贝,并且这个拷贝很活泛,可以重新写里面的属性和方法,同时还可以新增你想要的属性或方法,来看下面这个例子:
function FatherClass(){
this.class = "father";
this.setAuthority = function(){
this.authority = "controller";
};
};
var child = new function(){};
child.prototype = new FatherClass();
child.prototype.class = "child";
child.prototype.setAuthority = function(){
this.authority = "controlled";
};
child.say = function(){ //新增方法,直接针对新对象加上即可
alert("you can't controll me");
};
alert(child.class); //结果为child
alert(child.authority); //结果为controlled
child.say(); //结果为you can't controll me
从上面可以看出,函数式的编程还是博大精深的,这就是一门编程语言的艺术。同时,在外部不能通过prototype改变自定义类型的属性或方法。该例子可以看到:调用的属性和方法仍是最初定义的结果。即当原型方法和对象方法在调用相同的属性和函数时,会执行对象方法里面的属性和函数。再看下面的例子:
function FatherClass(){
this.class = "father";
this.setAuthority = function(){
this.authority = "controller";
};
};
FatherClass.prototype.class = "child";
FatherClass.prototype.setAuthority = function(){
this.authority = "controlled";
};
alert(FatherClass.class); //结果仍然为father
alert(FatherClass.authority); //结果仍然为controller
也就是说,不能直接通过prototype属性来修改对象本身以及有的属性、方法,要么新建一个拷贝它的实体再来修改,要么就新增属性或方法。
再来理解这2个东西,
1、A.prototype = new B();
2、A.prototype = B.prototype;
先来看A.prototype = new B(),理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。
function baseClass(){
this.showMsg = function(){
alert("baseClass::showMsg");
}
} ;
function extendClass(){};
extendClass.prototype = new baseClass();
var instance = new extendClass();
instance.showMsg(); //结果是baseClass:showMsg
这里我们以baseClass的一个实例来做原型,来克隆的extendClass也同时包含了showMsg这个方法。extendClass.prototype = new baseClass()就可以阅读为:extendClass是以baseClass的一个实例为原型克隆创建的。但是当extendClass中有个与showMsg同名同参的函数时,调用这个函数会出现什么情况?再看这个例子:
function baseClass(){
this.showMsg = function(){
alert("baseClass:showMsg base");
}
};
function extendClass(){
this.showMsg = function(){
alert("extendClass:showMsg extend");
}
};
extendClass.prototype = new baseClass();
var extendA = new extendClass();
extendA.showMsg(); // 结果为extendClass:showMsg extend
从这里可以看出,函数运行时会先去本体的函数中去找,如果找到则运行,找不到则去prototype中寻找函数。或者可以理解为prototype不会克隆同名函数。如果要想直接调用原来类里的那个同名方法怎么办?可以用call()方法来实现,再写如下代码:
extendClass.prototype = new baseClass();
var instance = new extendClass();
var baseinstance = new baseClass();
baseinstance.showMsg.call(instance); //结果是baseClass::showMsg base
这里的baseinstance.showMsg.call(instance);阅读为“将instance当做baseinstance来调用,调用它的对象方法showMsg”
再看A.prototype = B.prototype,A的prototype为B的prototype,可以理解A将B的prototype中方法和属性全部克隆了一遍。A能使用B的prototype方法和属性。这里强调的也是克隆而不是继承。请看下面一个例子:
function Blog(url,name){
this.url = url;
this.name = name;
};
Blog.prototype.jumpurl = '';
Blog.prototype.jump = function(){
window.location = this.jumpurl;
};
var blog1 = new Blog('dearxiangxiao', 'https://home.cnblogs.com/u/xiangxiao/');
var blog2 = new Blog('希希里之海', 'http://www.cnblogs.com/weixuqin/');
var webBlog = function(){};
webBlog.prototype = Blog.prototype;
var myWebBlog = new webBlog();

从上面的执行结果可以看出,myWebBlog的两个属性jump和jumpUrl分别引用了Blog.prototype.jumpurl和Blog.prototype.jump,由此可见,对象的prototype也可作为另一个对象的prototype的引用。
结束语:感觉js里面对类和实体对象对于方法的声明并无多大讲究,类方法也可直接拿来用,要知道,在java里可必须是抽象方法才允许这么调用的。
js函数prototype属性学习(一)的更多相关文章
- js函数prototype属性学习(二)
继续探讨js对象的prototype属性,前面已经看到在创建完一个对象之后,随时都会有一个_proto_属性伴随所有,那么,这个_proto_又是用来干嘛的,面试时问的高大上的原型链又是怎么回事? 拿 ...
- 简单理解js的prototype属性
在进入正文之前,我得先说说我认识js的prototype这个东西的曲折过程. 百度js的prototype的文章,先看看,W3School关于prototype的介绍: 你觉得这概念适合定义js的pr ...
- js函数的属性和方法
js函数的属性和方法 前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解j ...
- 复习一下js的prototype 属性
<html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</t ...
- js中Prototype属性解释及常用方法
1.prototype的定义 javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用. 每一个构造函数都有一个属 ...
- js的Prototype属性 解释及常用方法
函数:原型 每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译,使用其原文).这个属性非常有用:为一个特定类声明通用的变量或者函数. prototype的定义 你不需要显式地声明一 ...
- JS函数的属性
1.arguments.callee //经典的阶乘(递归)函数 function factorial(num) { if (num <= 1) { return 1; } else { ret ...
- JS的Prototype属性
转载至: http://blog.sina.com.cn/s/blog_7045cb9e0100rtoh.html 函数:原型 每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译, ...
- vue.js的计算机属性学习
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
随机推荐
- JAVA设计模式之单例(singleton)
一.饿汉式 /** * 饿汉式 */public class Singleton01 { private static final Singleton01 instance = new Singlet ...
- MATLAB矩阵的表示
矩阵是matlab中最基本的数据对象. l 矩阵的建立 l 冒号表达式 l 结构矩阵和单元矩阵 1.矩阵的建立 (1)利用直接输入法建立矩阵:将矩阵的元素用中括号括起来,按矩阵行的顺序输入各元素 ...
- C# 基础至集合-数组、List<T>、ArrayList、LinkedList、HashMap的一些区别
1:数组 ]; //赋值 strs[] = "; strs[] = "; //修改 strs[] = "burg"; //删除 没法删除 除非转化为可变数组li ...
- redis 集群安装
redis集群安装 1.下载redis源码 2.解压并进入解压后的文件夹redis内 3.make,生成一系列的文件(mkreleasehdr.sh, redis-benchmark, redis-c ...
- InnoDB的ibd数据文件为什么比data_length+index_length+data_free的总和还要大?
问题描述: 同事在给jiradb做mysqldump时,发现dump出来的文件只有10MB左右,而ibd文件占用磁盘空间100MB左右. 最初,我们猜测可能是delete操作导致了大量的磁盘碎片,以及 ...
- 基于环信SDK的IM即时通讯填坑之路(vue)
公司最近使用第三方环信SDK的进行通信聊天,基本已完成.记录下填坑之路 1.可以通过以下方式引用 WebSDK 1.安装 npm install easemob-websdk --save 2. 先 ...
- [hdu5340]二分,枚举,二进制压位加速
题意:判断一个字符串能否划成三段非空回文串. 思路:先用二分+hash在nlogn的时间内求出以每条对称轴为中心的回文串的最大半径r[i](可以用对称的两个下标之和来表示 ),然后利用r[i]求出pr ...
- [Selenium] 自动侦测浏览器版本并下载对应的浏览器驱动
昨天在群里聊天时,有同学说 Appium 官方支持自动下载兼容的浏览器驱动,想来Selenium也有类似的方法,于是在网上搜索一番.参考了Medium上一篇文章的方法,对步骤进行改进,增加了对多浏览器 ...
- Redis学习笔记(六) 对象
前面我们看了Redis用到的主要数据结构,如简单动态字符串(SDS).双向链表.字典.压缩列表.整数集合等. 但是Redis并没有直接使用这些数据结构来实现键值对,而是基于这些数据结构创建了一个对象系 ...
- Jmeter参数化四种方式
JMeter的三种参数化方式包括: 1.用户参数 2.函数助手 3.CSV Data Set Config/CSV数据配置文件 4.用户自定义变量 一.用户参数 位置:添加-前置处理器-用户参数 操作 ...