JavaScript的类、对象、原型、继承、引用
以CSS为例,有一种为所有class为"xxxx"的元素添加样式(外联样式),那么所有class为xxx的元素样式就会改变,在css中像下面这么写:
<html>
<head>
<style>
.active{ background:red }
</style>
</head>
<body>
<p class="active">123456789</p>
<p class="active">123456789</p>
<p class="active">123456789</p>
</body>
</html>
CSS中还有一种为单一的元素加样式(行间样式),只会对这一个元素产生效果,像下面这样:
<html>
<head>
<style>
.active{ background:red }
</style>
</head>
<body>
<p style="background:orange">123456789</p>
<p>123456789</p>
<p>123456789</p>
</body>
</html>
以铸造一个铁锅为例:
类:模子,一个锅形状的模具,不可以用来炒菜、煮饭。
对象:用模子造出来的铁锅,可以用来炒菜、煮饭。
对象(铁锅)造出来之后,相互之间就没有太大的关系了,对一个对象(铁锅)进行一些操作,几乎不会影响到其他对象(铁锅),比如将一个铁锅戳个洞,另外一个铁锅依旧完好无损;为一个铁锅加一个把手,另外一个铁锅依旧老样子,没有把手,因为把手只装在了一个铁锅上,这里就类似于上面CSS中的行间样式。
如果做一些操作,让所有的对象(造出的铁锅)都有改变,那么只能在模子也就是模具上做改变,然后就会作用到所有的对象(铁锅)上。这里类似于上面CSS中的外联样式。而这里的模子就是所谓的原型(prototype),如果要做所有的对象都做改变,就将改变对象的原型,即对象的模具,同时原型也是对象的引用。
为了让上面的几句话更好理解,看下面两个例子:
示例1:
<script>
var arr1 = new Array(1,2,3,4,5,6,7,8,9,10);
var arr2 = new Array(8,9,10);
arr1.sum = function(){//类似于加行间样式,只会作用在一个对象上
var sum = 0;
for(var i = 0; i < this.length; i++){
sum += this[i];
}
alert(sum);
}
arr1.sum();//55
arr2.sum();//会报错:arr2.sum is not a function
</script>
示例2:
<script>
var arr1 = new Array(1,2,3,4,5,6,7,8,9,10);
var arr2 = new Array(8,9,10);
Array.prototype.sum = function(){//类似于css的class属性
var sum = 0;
for(var i = 0; i < this.length; i++){
sum += this[i];
}
alert(sum);
}
arr1.sum();//55
arr2.sum();//27
</script>
工厂方式创建对象:这个工厂不是设计模式中的工厂,而是说他生产对象的过程和工厂里面生产产品的过程类似
<script>
function createPerson(name){//构造函数
//找到原料
var obj = new Object(); //进行加工
obj.name = name;
obj.showName = function(){
alert(this.name);
} //出厂
return obj;
} var p1 = createPerson("AAAAA");
var p2 = createPerson("BBBBB");
p1.showName();//AAAAA
p2.showName();//BBBBB alert(p1.showName == p2.showName);//false
</script>
上面的代码,从运行结果可以看出,虽然p1和p2都有showName方法,但是这两个方法是不同的,也就是说,如果有1000个person的对象,用这种方法创建对象,系统就会保存2000个showName方法,但是,我们都知道,这2000个showName方法应该是一样的,不然就太浪费资源了。
用过其他语言看到这种方式也挺别扭,因为其他语言中创建对象会使用new关键字。
js中也支持使用new关键字来创建对象,new后面可以加一个类,如Array,Date....还可以加函数funcName,使用new加函数名的用法,其实和直接使用函数来返回对象是一样的。只不过使用new的时候,会偷偷的找到原料,然后在偷偷地出厂,也就是说,如果使用new创建对象时,我们可以省略这两个步骤,其他的没有什么改变,仍旧存在上面那个1000个对象,2000个showName方法的问题。示例如下:
<script>
function createPerson(name){
//系统自动(偷偷地)找到原料
//var obj = new Object(); //进行加工
//既然是系统自动找原料(生成一个Object对象),那么就要用this指代默认创建的对象。
this.name = name;
this.showName = function(){
alert(this.name);
} //系统自动(偷偷地)出厂
//return obj;
} var p1 = new createPerson("AAAAA");
var p2 = new createPerson("BBBBB");
p1.showName();//AAAAA
p2.showName();//BBBBB alert(p1.showName == p2.showName);//false
</script>
上面的那个使用new来创建对象的做法中,createPerson就是一个类,而p1,p2就是对象,所以类似于var date = new Date()的形式,那么我们就可以对createPerson的原型(prototype)进行操作,让所有的由该类实例化的对象都拥有一样的属性或者方法,并且他们还都是一样,不会出现1000个对象,2000个showName方法的情况。
示例:
<script>
function createPerson(name){
this.name = name;
}
createPerson.prototype.showName = function(){
alert(this.name);
}
var p1 = new createPerson("AAAAA");
var p2 = new createPerson("BBBBB");
p1.showName();//AAAAA
p2.showName();//BBBBB alert(p1.showName == p2.showName);//true
</script>
call()
任意一个函数名后面都可以加一个call(),call()中不加参数的时候,调用的是原函数,如果传一个参数,那么传递的参数就会替换掉函数中的this。如果函数需要传入参数,那么call()的第一个参数为要替代的this,后面才是函数真正的参数,比如下面的例子:
<script>
function say(){
alert(this)
}
say();//[object Window]
say.call();//[object Window]
say.call(12);//12 传递给call的参数替换掉了say()中的this function speak(name){
alert(name);
}
speak("abc");//abc
speak.call(12);//undefined
speak.call(12,"abx");//abx 12替换掉了speak()中的this,abx是传递给speak的参数
</script>
继承
继承可以借助上面的call()来实现。下面这个例子中,只继承了属性,没有继承方法:
<script>
function Parent(){
this.name = "abc";
}
Parent.prototype.showName = function (){
alert(this.name);
} function Child(){
Parent.call(this); //将Parent中的this替换为Child的对象实例
} son = new Child();
alert(son.name);//abc
son.showName();// wrong: s.showName is not a function
</script>
继承方法可以使用将父类的prototype赋值给子类的prototype,但是注意,原型prototype是一个引用,将父类的prototype赋值给子类的prototype之后,两个类的prototype都执行了同一块内存,即通过其中任意一个类来操作prototype都会影响两个类的prototype,如下面的例子:
<script>
function Parent(){
this.name = "abc";
}
Parent.prototype.showName = function (){
alert(this.name);
} function Child(){
Parent.call(this); //将say中的this替换为speak的对象实例
}
Child.prototype = Parent.prototype;
//prototype为引用,两个prototype的指针指向同一个。 Child.prototype.shutUp = function(){
alert("shut up");
} son = new Child();//创建一个子类对象。
alert(son.name);//abc
son.showName();//abc
son.shutUp();//shut up father = new Parent();//创建一个父类对象
father.shutUp();//shut up
//父类的对象示例也可以调用子类原型中添加的方法,因为prototype是引用
</script>
使用组合继承:
function SuperType(){
this.name = "demo";
this.age = 20;
this.sayAge = function(){
console.log(this.age);
}
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(){
SuperType.call(this);
this.gender = "male";
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayGender = function(){
console.log(this.gender);
}
var ins = new SubType();
console.log(ins.age); //20
console.log(ins.name); //demo
console.log(ins.gender); //male
ins.sayAge(); //20
ins.sayName(); //demo
ins.sayGender(); //male
JavaScript的类、对象、原型、继承、引用的更多相关文章
- 关于js的对象原型继承(一)
javascript中,对象的继承是通过原型去继承. 可以这样理解:js中的对象,包含的除了属性和方法,还有一个最基本的原型__proto__对象.这个原型__proto__指向谁,这个对象就继承谁. ...
- javascript中的对象之间继承关系
相信每个学习过其他语言的同学再去学习JavaScript时就会感觉到诸多的不适应,这真是一个颠覆我们以前的编程思想的一门语言,先不要说它的各种数据类型以及表达式的不同了,最让我们头疼,恐怕就是面向对象 ...
- javascript 创建对象及对象原型链属性介绍
我们知道javascript里定义一个普通对象的方法,如: let obj = {}; obj.num = 1; obj.string = 'string'; obj.func = function( ...
- 深入 JavaScript 中的对象以及继承原理
ES6引入了一个很甜的语法糖就是 class, class 可以帮助开发者回归到 Java 时代的面向对象编程而不是 ES5 中被诟病的面向原型编程. 我也在工作的业务代码中大量的使用 class, ...
- php 数组 类对象 值传递 引用传递 区别
一般的数据类型(int, float, bool)不做这方面的解说了 这里详细介绍一下数组和的类的对象作为参数进行值传递的区别 数组值传递 实例代码: <?php function main() ...
- javascript 构造函数类和原型 prototyp e定义的属性和方法的区别
1.把方法写在原型中比写在构造函数中消耗的内存更小,因为在内存中一个类的原型只有一个,写在原型中的行为可以被所有实例共享,实例化的时候并不会在实例的内存中再复制一份而写在类中的方法,实例化的时候会在每 ...
- JavaScript 创建类/对象的几种方式
在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的. JS对象是一种复合类型,它允许你通过变量 ...
- [转载]php 数组 类对象 值传递 引用传递 区别
一般的数据类型(int, float, bool)不做这方面的解说了 这里详细介绍一下数组和的类的对象作为参数进行值传递的区别 数组值传递 实例代码: <?php function main() ...
- 【转】javascript 的类,原型,继承的理解
原文: https://www.cnblogs.com/codernie/p/9098184.html ------------------------------------------------ ...
- 关于js的对象原型继承(二)
本章讨论使用new一个构造函数来创建一个对象. 前期知识点说明: 1.prototype是函数的一个属性,每个函数都有一个prototype属性.这个属性是一个指针,指向一个对象.它是显示修改对象的原 ...
随机推荐
- Excel函数(不定期持续更新)
1.COUNTIF函数 COUNTIF函数用来计算单元格区域内符合条件的单元格个数. COUNTIF函数只有两个参数 COUNTIF(单元格区域,计算的条件) 例如:计算上海市的数量
- smartpass
1.smartpass 是用户注册后,产生的用户名密码 与每个摄像头的用户名密码不一致 2.每个设备初始化登录密码为admin admin,如果需要修改,则在进入该设备IP地址,设置——>用户管 ...
- day14 Python百分号字符串拼接
拼接 # -*- coding:utf8 -*- #%s字符串,%d数字msg = '%s am %s my %s is %s'% (2,"charon","pluto& ...
- centos7之docker安装
下午四点左右,我准备接触docker这个技术.之所以接触它,原因来自tomcat服务器老是挂,也不能说老是挂,一周一次吧,或者不定时,最初出现的问题,分为这么几类? 一类,java代码的问题,某个类导 ...
- MATLAB——神经网络pureline激活函数
- 笔记二:常用的h5语义化标签
0.前言: 所谓语义化标签就是一种 我们仅通过标签名就能判断出该标签内容的语义的标签,见名知意. 总结这部分内容,主要是为了能从繁琐的div嵌套div中,改成带有h5标签码.这样更有利于读写代码. 人 ...
- <转>安全测试思维导图
最近有监控到公司的某些系统在某些时间段出现大量的HTTP或者TCP连接,考虑到安全性,老大让我研究研究安全测试... 正好今晚从订阅的码农周刊(开发者头条)看到了一篇安全测试相关的帖子,做个搬运工,分 ...
- 数据库连接不关闭造成的问题以及RowSet的使用
这几天给项目做性能压力测试,发现一个方法压力200之后就会把整个系统弄停掉.仔细检查发现是开发人员调用数据库的写法有问题.用的是spring的jdbcTemplate,在使用回调的时候,在回调里又做了 ...
- 授人以鱼不如授人以渔——和女儿学一起学成语
女儿二年级了,前段时间背了<小学生必背古诗词75首>,采用几天一篇,然后滚动复习这种方式.磕磕绊绊也把一本古诗背了一遍,效果吗?是有的,但是不怎么明显,前面背,后面忘.当然这是规律,难免的 ...
- CF954I Yet Another String Matching Problem 并查集、FFT
传送门 题意:给出两个由小写$a$到$f$组成的字符串$S$和$T$($|S| \geq |T|$),给出变换$c1\,c2$表示将两个字符串中所有$c1$字符变为$c2$,求$S$的每一个长度为$T ...