• 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
    

      

  • 相关阅读:
    CV类数据集高速下载
    pytorch和tensorflow的爱恨情仇之参数初始化
    pytorch和tensorflow的爱恨情仇之定义可训练的参数
    同时打乱数据集和标签的几种方式
    pytorch和tensorflow的爱恨情仇之张量
    解决pip安装pytorch缓慢问题(直接使用命令)
    pytorch和tensorflow的爱恨情仇之基本数据类型
    完美解决xxx网盘上传和下载慢问题
    大学生运动情况调研计划
    dockerFile解析
  • 原文地址:https://www.cnblogs.com/-beyond/p/7932066.html
Copyright © 2020-2023  润新知