JQuery选择器大全 前端面试送命题:面试题篇 对IOC和DI的通俗理解 c#中关于协变性和逆变性(又叫抗变)帮助理解
JQuery选择器大全
jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法
$("#myELement") 选择id值等于myElement的元素,id值不能重复在文档中只能有一个id值是myElement所以得到的是唯一的元素
$("div") 选择所有的div标签元素,返回div元素数组
$(".myClass") 选择使用myClass类的css的所有元素
$("*") 选择文档中的所有的元素,可以运用多种的选择方式进行联合选择:例如$("#myELement,div,.myclass")
层叠选择器:
$("form input") 选择所有的form元素中的input元素
$("#main > *") 选择id值为main的所有的子元素
$("label + input") 选择所有的label元素的下一个input元素节点,经测试选择器返回的是label标签后面直接跟一个input标签的所有input标签元素
$("#prev ~ div") 同胞选择器,该选择器返回的为id为prev的标签元素的所有的属于同一个父元素的div标签
基本过滤选择器:
$("tr:first") 选择所有tr元素的第一个
$("tr:last") 选择所有tr元素的最后一个
$("input:not(:checked) + span")
过滤掉:checked的选择器的所有的input元素
$("tr:even") 选择所有的tr元素的第0,2,4... ...个元素(注意:因为所选择的多个元素时为数组,所以序号是从0开始)
$("tr:odd") 选择所有的tr元素的第1,3,5... ...个元素
$("td:eq(2)") 选择所有的td元素中序号为2的那个td元素
$("td:gt(4)") 选择td元素中序号大于4的所有td元素
$("td:lt(4)") 选择td元素中序号小于4的所有的td元素
$(":header") 选择h1、h2、h3之类的
$("div:animated") 选择正在执行动画效果的元素
内容过滤选择器:
$("div:contains('John')") 选择所有div中含有John文本的元素
$("td:empty") 选择所有的为空(也不包括文本节点)的td元素的数组
$("div:has(p)") 选择所有含有p标签的div元素
$("td:parent") 选择所有的以td为父节点的元素数组
可视化过滤选择器:
$("div:hidden") 选择所有的被hidden的div元素
$("div:visible") 选择所有的可视化的div元素
属性过滤选择器:
$("div[id]") 选择所有含有id属性的div元素
$("input[name='newsletter']") 选择所有的name属性等于'newsletter'的input元素
$("input[name!='newsletter']") 选择所有的name属性不等于'newsletter'的input元素
$("input[name^='news']") 选择所有的name属性以'news'开头的input元素
$("input[name$='news']") 选择所有的name属性以'news'结尾的input元素
$("input[name*='man']") 选择所有的name属性包含'news'的input元素
$("input[id][name$='man']") 可以使用多个属性进行联合选择,该选择器是得到所有的含有id属性并且那么属性以man结尾的元素
子元素过滤选择器:
$("ul li:nth-child(2)"),$("ul li:nth-child(odd)"),$("ul li:nth-child(3n + 1)")
$("div span:first-child") 返回所有的div元素的第一个子节点的数组
$("div span:last-child") 返回所有的div元素的最后一个节点的数组
$("div button:only-child") 返回所有的div中只有唯一一个子节点的所有子节点的数组
表单元素选择器:
$(":input") 选择所有的表单输入元素,包括input, textarea, select 和 button
$(":text") 选择所有的text input元素
$(":password") 选择所有的password input元素
$(":radio") 选择所有的radio input元素
$(":checkbox") 选择所有的checkbox input元素
$(":submit") 选择所有的submit input元素
$(":image") 选择所有的image input元素
$(":reset") 选择所有的reset input元素
$(":button") 选择所有的button input元素
$(":file") 选择所有的file input元素
$(":hidden") 选择所有类型为hidden的input元素或表单的隐藏域
表单元素过滤选择器:
$(":enabled") 选择所有的可操作的表单元素
$(":disabled") 选择所有的不可操作的表单元素
$(":checked") 选择所有的被checked的表单元素
$("select option:selected") 选择所有的select 的子元素中被selected的元素
选取一个 name 为”S_03_22″的input text框的上一个td的text值
$(”input[@ name =S_03_22]“).parent().prev().text()
名字以”S_”开始,并且不是以”_R”结尾的
$(”input[@ name ^='S_']“).not(”[@ name $='_R']“)
一个名为 radio_01的radio所选的值
$(”input[@ name =radio_01][@checked]“).val();
$("A B") 查找A元素下面的所有子节点,包括非直接子节点
$("A>B") 查找A元素下面的直接子节点
$("A+B") 查找A元素后面的兄弟节点,包括非直接子节点
$("A~B") 查找A元素后面的兄弟节点,不包括非直接子节点
1. $("A B") 查找A元素下面的所有子节点,包括非直接子节点
例子:找到表单中所有的 input 元素
HTML 代码:
1
2
3
4
5
6
7
8
9
|
< form > < label >Name:</ label > < input name="name" /> < fieldset > < label >Newsletter:</ label > < input name="newsletter" /> </ fieldset > </ form > < input name="none" /> |
jQuery 代码:
$("form input")
结果:
[ <input name="name" />, <input name="newsletter" /> ]
2. $("A>B") 查找A元素下面的直接子节点
例子:匹配表单中所有的子级input元素。
HTML 代码:
1
2
3
4
5
6
7
8
9
|
< form > < label >Name:</ label > < input name="name" /> < fieldset > < label >Newsletter:</ label > < input name="newsletter" /> </ fieldset > </ form > < input name="none" /> |
jQuery 代码:
$("form > input")
结果:
[ <input name="name" /> ]
3. $("A+B") 查找A元素后面的兄弟节点,包括非直接子节点
例子:匹配所有跟在 label 后面的 input 元素
HTML 代码:
1
2
3
4
5
6
7
8
9
|
< form > < label >Name:</ label > < input name="name" /> < fieldset > < label >Newsletter:</ label > < input name="newsletter" /> </ fieldset > </ form > < input name="none" /> |
$("label + input")
结果:
[ <input name="name" />, <input name="newsletter" /> ]
4. $("A~B") 查找A元素后面的兄弟节点,不包括非直接子节点
例子:找到所有与表单同辈的 input 元素
HTML 代码:
1
2
3
4
5
6
7
8
9
|
< form > < label >Name:</ label > < input name="name" /> < fieldset > < label >Newsletter:</ label > < input name="newsletter" /> </ fieldset > </ form > < input name="none" /> |
jQuery 代码:
$("form ~ input")
结果:
[ <input name="none" /> ]
前言
前端入门很容易,简单地用html搭一个页面框架;会用一些css基本样式;懂得用jquery的dom交互,就基本可以挺着胸说自己是个前端工程师了。
但是前端提升异常艰难,算法、数据结构、oop;javascript、dom、css、html5这些仅仅是标配;性能优化、安全性、代码优雅性、seo,这些也是必然需要了解的。前端开发环境很轻便,也很繁琐,各种框架、架构模式的应用也是衡量专业程度的标准。
在这里总结了一些面试题供前端们参考。
内容
JavaScript中如何检测一个变量是字符串类型?
typeof(obj) === "string" //true obj.constructor === String //true
trim()的使用场景
var str = " hello word "; str = str.trim(); console.log(str); //hello word,trim只会去掉字符中前后的空格,不会去除文字中的空格
this的典型应用
//1 input点击,获取值 <input type="button" id="text" value="点击一下" /> <script type="text/javascript"> var btn = document.getElementById("text"); btn.onclick = function() { alert(this.value); //此处的this是按钮元素 } </script> //2 构造函数 function Hello(name, color) { this.name = name; this.color = color; } //3 在html元素事件属性中使用 <input type=”button” onclick=”showInfo(this);” value=”点击一下”/>
instanceof还是typeof?
//相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。 //细节区别: //1.typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。 //2.typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错。 //3.对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。 var a = new Array(); alert(a instanceof Array); // true alert(a instanceof Object) // true
什么是跨域?
由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。存在跨域的情况: 1.网络协议不同,如http协议访问https协议。 2.端口不同,如80端口访问8080端口。 3.域名不同,如qianduanblog.com访问baidu.com。 4.子域名不同,如abc.qianduanblog.com访问def.qianduanblog.com。 5.域名和域名对应ip,如www.bb.com访问8.8.8.8.
JavaScript面向对象?
//面向对象的基本特征:多态,继承,封包(完全参考java) //prototype 原型链来达到继承的效果 function animal(name){ this.name = name; } animal.prototype.sayName = function(){ console.log("name is "+this.name); } var animal1 = new animal("动物"); animal1.sayName(); //动物 function dog(name){ this.name = name; } dog.prototype = new animal() var dog1= new dog("哈士奇"); dog1.sayName(); //哈士奇
//call()/apply()方法 function teacher(name,age){ this.name = name; this.age = age; this.sayhi = function(){ alert('name:'+name+", age:"+age); } } function student(){ var args = arguments; teacher.call(this,args[0],args[1]); // teacher.apply(this,arguments); } var teacher1 = new teacher('xiaoming',23); teacher1.sayhi(); var student1 = new student('xiaolan',12); student1.sayhi(); // alert: name:xiaoming, age:23 // alert: name:xiaolan, age:12
function teacher(name,age){ this.name = name; this.age = age; } teacher.prototype.sayName = function(){ console.log('name:'+this.name); } teacher.prototype.sayAge = function(){ console.log('age:'+this.age); } function student(){ var args = arguments; teacher.call(this,args[0],args[1]); } student.prototype = new teacher(); var student1 = new student('xiaolin',23); student1.sayName(); student1.sayAge(); // name:xiaolin // age:23
function Person(name,age){ this.name = name; this.age = age; this.show = function(){ console.log(this.name+", "+this.age); } } function Student(name,age){ this.student = Person; //将Person类的构造函数赋值给this.student this.student(name,age); //js中实际上是通过对象冒充来实现继承的 delete this.student; //移除对Person的引用 } var s = new Student("小明",17); s.show(); var p = new Person("小花",18); p.show(); // 小明, 17 // 小花, 18
写一个方法,去掉重复的元素
//方法1 var arr = [0,2,3,4,4,0,2]; var obj = {}; var tmp = []; for(var i = 0 ;i< arr.length;i++){ if( !obj[arr[i]] ){ obj[arr[i]] = 1; tmp.push(arr[i]); } } console.log(tmp); //方法2 var arr = [2,3,4,4,5,2,3,6], arr2 = []; for(var i = 0;i< arr.length;i++){ if(arr2.indexOf(arr[i]) < 0){ arr2.push(arr[i]); } } console.log(arr2); //方法3 var arr = [2,3,4,4,5,2,3,6]; var arr2 = arr.filter(function(element,index,self){ return self.indexOf(element) === index; }); console.log(arr2);
Jquery 属性的几种操作方式
//addClass $(selector).addClass(class):为每个匹配的元素添加指定的类名 //removeClass $(selector).removeClass(class):从所有匹配的元素中删除全部或者指定的类,删除class中某个值; //toggleClass $(selector).toggleClass(class):如果存在(不存在)就删除(添加)一个类 //removeAttr $(selector).removeAttr(class);删除class这个属性;
$(document).ready与window.onload()?
1.window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。 2.$(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。
$.get,$.post与$.ajax
相同点:都是异步请求的方式来获取服务端的数据; 不同点: 1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。 2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。 3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多 4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。
Ajax:
Ajax 是一种用于创建快速动态网页的技术。Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
$.get 与 $.post 都是$.ajax的语法糖。 例子 $.ajax({ url:'http://www.baidu.com', type:'POST', data:data, cache:true, headers:{}, beforeSend:function(){}, success:function(){}, error:function(){}, complete:function(){} });
jquery事件bind
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数; 语法:bind(type,[data],function(eventObject)); 特点: (1)、适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件。 (2)、当页面加载完的时候,你才可以进行bind(),所以可能产生效率问题。 实例如下:$( "#members li a" ).bind( "click", function( e ) {} );
jquery事件live
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数; 语法:live(type, [data], fn); 特点: (1)、live方法并没有将监听器绑定到自己(this)身上,而是绑定到了this.context上了。 (2)、live正是利用了事件委托机制来完成事件的监听处理,把节点的处理委托给了document,新添加的元素不必再绑定一次监听器。 (3)、使用live()方法但却只能放在直接选择的元素后面,不能在层级比较深,连缀的DOM遍历方法后面使用,即$(“ul”).live...可以,但$("body").find("ul").live...不行; 实例如下:$( document ).on( "click", "#members li a", function( e ) {} );
jquery事件delegate
定义和用法:将监听事件绑定在就近的父级元素上 语法:delegate(selector,type,[data],fn) 特点: (1)、选择就近的父级元素,因为事件可以更快的冒泡上去,能够在第一时间进行处理。 (2)、更精确的小范围使用事件代理,性能优于.live()。可以用在动态添加的元素上。 实例如下: $("#info_table").delegate("td","click",function(){/*显示更多信息*/}); $("table").find("#info").delegate("td","click",function(){/*显示更多信息*/});
jquery事件on
定义和用法:将监听事件绑定到指定元素上。 语法:on(type,[selector],[data],fn) 实例如下:$("#info_table").on("click","td",function(){/*显示更多信息*/});参数的位置写法与delegate不一样。 说明:on方法是当前JQuery推荐使用的事件绑定方法,附加只运行一次就删除函数的方法是one()。 总结:.bind(), .live(), .delegate(),.on()分别对应的相反事件为:.unbind(),.die(), .undelegate(),.off()
什么是盒子模型
在网页中,一个元素占有空间的大小由几个部分构成,其中包括元素的内容(content),元素的内边距(padding),
元素的边框(border),元素的外边距(margin)四个部分。这四个部分占有的空间中,有的部分可以显示相应的内容,而有的部分只用来分隔相邻的区域或区域。
4个部分一起构成了css中元素的盒模型。
三种降低页面加载时间的方法
压缩css、js文件 合并js、css文件,减少http请求 外部js、css文件放在最底下 减少dom操作,尽可能用变量替代不必要的dom操作
三种常见的web攻击
1.XSS(Cross-Site Scripting,跨站脚本攻击):指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或者JavaScript进行的一种攻击。 2.SQL注入攻击 3.CSRF(Cross-Site Request Forgeries,跨站点请求伪造):指攻击者通过设置好的陷阱,强制对已完成的认证用户进行非预期的个人信息或设定信息等某些状态更新。
针对页面内容的优化
1.减少 HTTP 请求 (Make Fewer HTTP Requests) 2.减少 DOM 元素数量 (Reduce the Number of DOM Elements) 3.使得 Ajax 可缓存 (Make Ajax Cacheable)
针对修饰文件的优化
1.把 CSS 放到代码页上端 (Put Stylesheets at the Top) 2.从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External) 3.精简 JavaScript 与 CSS (Minify JavaScript and CSS) 4.避免 CSS 表达式 (Avoid CSS Expressions)
针对脚本的优化
1. 脚本放到 HTML 代码页底部 (Put Scripts at the Bottom) 2. 从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External) 3. 精简 JavaScript 与 CSS (Minify JavaScript and CSS) 4. 移除重复脚本 (Remove Duplicate Scripts)
针对图片类文件的优化
1.优化图片 2 不要在 HTML 中使用缩放图片 3 使用恰当的图片格式 4 使用 CSS Sprites 技巧对图片优化
图像格式的区别
矢量图:图标字体,如 font-awesome;svg 普通图:gif,jpg(jpeg),png 区别: 1、gif:是是一种无损,8位图片格式。具有支持动画,索引透明,压缩等特性。适用于做色彩简单(色调少)的图片,如logo,各种小图标icons等。 2、JPEG格式是一种大小与质量相平衡的压缩图片格式。适用于允许轻微失真的色彩丰富的照片,不适合做色彩简单(色调少)的图片,如logo,各种小图标icons等。 3、png:PNG可以细分为三种格式:PNG8,PNG24,PNG32。后面的数字代表这种PNG格式最多可以索引和存储的颜色值。 关于透明:PNG8支持索引透明和alpha透明;PNG24不支持透明;而PNG32在24位的PNG基础上增加了8位(256阶)的alpha通道透明; 优缺点: 1、能在保证最不失真的情况下尽可能压缩图像文件的大小。 2、对于需要高保真的较复杂的图像,PNG虽然能无损压缩,但图片文件较大,不适合应用在Web页面上。
浏览器渲染页面流程
1.解析HTML文件,创建DOM树。 自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。 2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式; 3.将CSS与DOM合并,构建渲染树(Render Tree) 4.布局和绘制,重绘(repaint)和重排(reflow)
学习过spring框架的人一定都会听过Spring的IoC(控制反转) 、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解。首先要分享的一位技术牛人对Spring框架的IOC的理解,写得非常通俗易懂,以下内容全部来自原文,原文地址:http://jinnianshilongnian.iteye.com/blog/1413846。
1、IOC是什么
IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOc容器来控制对象的创建而不再显式地使用new;谁控制谁?当然是IOC容器控制了对象;控制什么?那就是主要控制了外部资源获取和生命周期(不只是对象也包括文件等)。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
用图例说明一下,传统程序设计如图1,都是主动去创建相关对象然后再组合起来:
图1 传统应用程序结构图
当有了IOC的容器后,在客户端类中不再主动去创建这些对象了,程序的结构图变成如图2所示:
图2 有IOC容器后的程序结构图
2、IoC能做什么
IOC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IOC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IOC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IOC/DI思想中,应用程序就变成被动的了,被动的等待IOC容器来创建并注入它所需要的资源了。
IOC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IOC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
3、IOC和DI
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
谁依赖于谁:当然是应用程序依赖于IOC容器;
为什么需要依赖:应用程序需要IOC容器来提供对象需要的外部资源;
谁注入谁:很明显是IOC容器注入应用程序某个对象,应用程序依赖的对象;
注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IOC和DI有什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IOC 而言,“依赖注入”明确描述了“被注入对象依赖IOC容器配置依赖对象”。
看过很多对Spring的Ioc理解的文章,好多人对Ioc和DI的解释都晦涩难懂,反正就是一种说不清,道不明的感觉,读完之后依然是一头雾水,看完这位技术牛人的博客后有一种豁然开朗的研究,他清楚地解释了IOC(控制反转) 和DI(依赖注入)中的每一个字,读完之后给人一种豁然开朗的感觉。我相信对于初学Spring框架的人对IOc的理解应该是有很大帮助的。
4、IOC和DI的意义
在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象或者依赖对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
所以控制反转IOC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IOC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IOC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IOC容器了,通过IOC容器来建立它们之间的关系。
DI(依赖注入)其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结道:控制的什么被反转了?就是获得依赖对象的方式反转了。
c#中关于协变性和逆变性(又叫抗变)帮助理解
今天回忆了之前看的《深入理解C#》这本书中的泛型章节,其中对泛型的可变性的理解。泛型可变性分两种:协变和逆变。逆变也又称为抗变。
怎么理解这两个名词的意思:
①:协变即为在泛型接口类型中使用out标识的类型参数。协变的字面意思是“与变化的方向相同”②逆变那就是用in来标识的泛型接口类型的类型参数。逆变的字面意思是“与变化的方向相反”
需要注意的是无论是协变还是逆变也只能在泛型接口中来使用。
先来举个基本的例子,来加强你对可变性的理解。在C#中有隐式类型转换,比如:
1
2
3
|
string str = "nibian" ; object str1 = str; Console.WriteLine(str1); |
大家都知道string类型是object类型的子类型,即string->object为子->父;从子类型到父类型的转换是隐式类型转换。
举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
interface IDemo< out T> { T Method( string str); } class One : IDemo< string > { public string Method( string str) { return str; } } class Two : IDemo< object > { public object Method( string str) { return str; } } class Program { static void Main( string [] args) { IDemo< string > one = new One(); IDemo< object > two; two = one; Console.WriteLine(two.Method( "2222" )); } } |
因为string是object类型的子类,在这里IDemo<string>和IDemo<object>类型之间也存在着类型转换的,从IDemo<string>向IDemo<object>进行的转换可以看成是子类型向父类型的隐式转换,它的这个用法就是协变。(这里必须要用out)
相反的我们在来看一下有关逆变的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
interface IDemo< in T> { string Method(T str); } class One : IDemo< string > { public string Method( string str) { return str; } } class Two : IDemo< object > { public string Method( object str) { return str.ToString(); } } class Program { static void Main( string [] args) { IDemo< object > two = new Two(); IDemo< string > one; one = two; Console.WriteLine(one.Method( "2222" )); } } |
同样的从IDemo<object>类型向IDemo<string>类型的转换,但是在这里我们却将父类型隐式转换为子类型的用法叫逆变。(这里必须要用in)
总结:协变和逆变就是在泛型接口类型将类型参数作为输入和输出的情况下,对类型间进行隐式转换的规律。