搜狐前端面试
- 1. 怎么实现div的水平居中和垂直居中
- 2. 构造函数里定义function和prototype定义function有什么区别?
- 3. js怎么实现继承?
- 4. 了解设计模式吗?用js实现观察者模式。
- 5. linux服务器下文件传输命令?如果要断点续传呢?
- 6. js跨域
1. 怎么实现div的水平居中和垂直居中:
综合考量了一下,最好的方法应该是方法4,用css3中的flex来做……但是可能会有兼容性问题
方法1:第一种情况是宽高已定:我用的方法是top:50%,left:50%; margin-top:-高/2;margin-left:-宽/2.。。。。但是忘了position……以及不单要对这个元素设置position,还要对父级元素设置position:relative
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>test</title> 5 <style type="text/css"> 6 .div1{ 7 width: 500px; 8 height: 500px; 9 margin-right: auto; 10 margin-left: auto; 11 border:1px solid red; 12 position: relative; /*很重要,不能忘了*/ 13 } 14 .div2{ 15 width: 200px; 16 height: 200px; 17 margin-left: -100px; 18 top:50%; 19 left: 50%; 20 margin-top:-100px; 21 background: blue; 22 position: absolute; 23 } 24 </style> 25 </head> 26 <body> 27 <div class="div1"> 28 <div class="div2"></div> 29 </div> 30 </body> 31 </html>
但是设置position后就不能用margin-right:auto; margin-left:auto 来做水平居中了。
然后我网上查到父级设置text-align也可以?然而试了下没有效果,又把子div设置成display:inline-block 甚至再加了 line-height:500px都依然无效。
在网上找到一种好办法:!!!!
方法2: 依然是利用position:子div的上下左右都设置成0,然后margin设置auto。关键是要设置position:子absolute,父relative。但是这种方法也只能适应于固定宽高的……试了下发现如果宽高随意,想用内部元素撑开的话,会占满整个父级div
1 .div1{ 2 width: 500px; 3 height: 500px; 4 margin-right: auto; 5 margin-left: auto; 6 border:1px solid red; 7 position: relative; 8 } 9 .div2{ 10 width: 200px; 11 height: 200px; 12 background: blue; 13 top:0px; 14 right: 0px; 15 bottom:0px; 16 left: 0px; 17 position: absolute; 18 margin:auto; 19 }
参考自:http://www.ihref.com/read-17539.html
方法3:再来一个方法: 父级元素设置display:table-cell ,然后vertical-align:middle。但是这种方法好像会使父元素的居中无效。试了下这种方法,在没有设置height的情况下依然适用
.div1{ display: table-cell; width: 500px; height: 500px; margin-right: auto; margin-left: auto; border:1px solid red; vertical-align: middle; } .div2{ width: 100px; height: 200px; background: blue; margin:0 auto; /*为了水平居中*/ }
方法4:flex居中: 这是css3中引入的新布局方法。但是IE9及以下不兼容。
1 .div1{ 2 display: -webkit-flex; 3 display: flex; 4 -webkit-align-items:center; /*使水平居中*/ 5 align-items: center; 6 -webkit-justify-content:center; /*使垂直居中*/ 7 justify-content: center; 8 width: 500px; 9 height: 500px; 10 margin;auto; 11 border:1px solid red; 12 } 13 .div2{ 14 width: 200px; 15 height: 200px; 16 background: blue; 17 18 }
这种方法也可以不指定宽高,由内部内容撑开。所以这个方法应该是最灵活的!!!
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>test</title> 5 <style type="text/css"> 6 .div1{ 7 display: -webkit-flex; 8 display: flex; 9 -webkit-align-items:center; /*使水平居中*/ 10 align-items: center; 11 -webkit-justify-content:center; /*使垂直居中*/ 12 justify-content: center; 13 width: 500px; 14 height: 500px; 15 margin;auto; 16 border:1px solid red; 17 } 18 .div2{ 19 /*width: 200px;*/ 20 /*height: 200px;*/ 21 background: blue; 22 23 } 24 .div3{ 25 height: 20px; 26 width: 100px; 27 } 28 </style> 29 </head> 30 <body> 31 <div class="div1"> 32 <div class="div2"> 33 <div class="div3"></div> 34 <div class="div3"></div> 35 <div class="div3"></div> 36 <div class="div3"></div> 37 <div class="div3"></div> 38 <div class="div3"></div> 39 40 </div> 41 </div> 42 </body> 43 </html>
这种方法灵活运用CSS中transform属性,较为新奇。缺点是IE9下不兼容。
面试官问我问题时,说如果没有指定宽高怎么做垂直居中,我没有答上来,面完后问他应该怎么做,他就说到在css3里面可以使用transform控制,在之前的用js控制……我试了下,如果不指定宽度的话,依旧会占满父元素。这个方法其实和第一个思想上是类似的,只是第一个是通过控制margin来做位移,而这个方法直接使用了CSS3中的transform:translate属性来做平移。
注意这里如果指定子元素position:relative。则父元素设position:relative 设不设好像都可以。而当指定子元素position:absolute时,父元素就要设置relative
1 .div1{ 2 position: relative; /*这里好像设不设都没关系?*/ 3 width: 500px; 4 height: 500px; 5 border: 1px solid red; 6 margin:auto; 7 } 8 .div2{ 9 position: relative; 10 top: 50%; 11 left: 50%; 12 width: 200px; 13 /*height: 200px;*/ 14 transform: translate(-50%,-50%); 15 -webkit-transform: translate(-50%,-50%); 16 -ms-transform: translate(-50%,-50%); 17 -moz-transform: translate(-50%,-50%); 18 background: blue; 19 }
这种不确定宽高的居中,较为灵活。只需要保证left和right的百分数一样就可以实现水平居中,保证top和bottom的百分数一样就可以实现垂直居中。但是这种方法不能由内部元素自动调节div的宽高,而是通过父元素大小控制的
1 .div1{ 2 position: relative; /*这里好像设不设都没关系?*/ 3 width: 500px; 4 height: 500px; 5 border: 1px solid red; 6 margin:auto; 7 } 8 .div2{ 9 position: absolute; 10 left: 30%; 11 right:30%; 12 top: 20%; 13 bottom:20%; 14 background: blue; 15 16 }
方法7:利用button做外容器,内部div会自动垂直居中。另外再设水平居中即可。——这应该不算一个好办法吧
2. 构造函数里定义function和prototype定义function有什么区别?
也就是下面的func1和func2
1 <script type="text/javascript"> 2 function A(){ 3 this.a = "123"; //包括变量的定义……一定一定要用this.变量名,直接var的都是undefined……天哪才发现……面试里都写错了啊 4 this.func1 = function(){ 5 //注意这里定义构造函数内部的对象函数时要用this.funcName,A.funcName和直接function func1都是错误的,不能调用 6 alert("a"); 7 } 8 } 9 A.prototype.func2 = function(){ 10 alert("b"); 11 } 12 var obj = new A(); 13 obj.func1(); 14 obj.func2(); 15 console.log(obj.a); 16 </script>
刚刚尝试才发现面试当做我在构造函数内部的变量声明定义和函数都写错了……心塞塞的。我当时回答的区别是,在内部定义函数的话,类的每个对象都会为这个函数开辟一个新的空间,而使用原型则不会。所以会节省内存空间。
网上查一下,比较全面的说法应该是:
1. 直接调用function,每一个类的实例都会拷贝这个函数,弊端就是浪费内存(如上)。prototype方式定义的方式,函数不会拷贝到每一个实例中,所有的实例共享prototype中的定义,节省了内存。
2. 但是如果prototype的属性是对象的话,所有实例也会共享一个对象(这里问的是函数应该不会出现这个情况),如果其中一个实例改变了对象的值,则所有实例的值都会被改变。同理的话,如果使用prototype调用的函数,一旦改变,所有实例的方法都会改变。——不可以对实例使用prototype属性,只能对类和函数用。
1 function A(){ 2 this.func1 = function(){ 3 console.log("这里是func1"); 4 } 5 A.prototype.func2 = function(){ 6 console.log("这里是func2"); 7 } 8 } 9 var oObj1 = new A(); 10 var oObj2 = new A(); 11 oObj2.func1 = function(){ 12 console.log("这里是改变了的func1"); 13 }; 14 oObj1.func1(); //这里是func1 15 oObj2.func1(); //这里是改变了的func1 16 17 //如果使用原型 18 // oObj1.prototype.func2 = function(){ 19 // console.log("这里是func2"); 20 // } //不可以直接对实例使用原型,原型是函数的属性。所以这里会报错 21 22 oObj1.func2(); //这里是func2 23 A.prototype.func3 = function(){ 24 console.log("这里是func3"); 25 }; 26 oObj2.func3(); //这里是func3
3. js怎么实现继承?
这个问题其实之前总结过了……但是面试时候有点忘……主要思想是记得的,但是不会写,还是基础太不牢靠,写的太少了。一开始因为不知道怎么能继承父类的方法属性,同时又不直接使用其原型,所以先写了一种,子类直接调用父类的原型。但是其中有些过程和方法肯定是写错了的……下面是正确的写法:
1 var Parent = function(name){ 2 this.name = name || "parent"; 3 } 4 Parent.prototype.getName = function(){ 5 return this.name; 6 } 7 8 var Child = function(name){ 9 Parent.apply(this,arguments); //通过apply调用父类的构造函数来进行相同的初始化工作 10 } 11 Child.prototype = Parent.prototype; 12 13 var parent = new Parent("MyParent"); 14 var child = new Child("MyChild"); 15 16 console.log(parent.getName()); //MyParent 17 console.log(child.getName()); //MyChild
//这样我们就只需要在子类构造函数中执行一次父类的构造函数,同时又可以继承父类原型中的属性,这也比较符合原型的初衷,就是把需要复用的内容放在原型中,我们也只是继承了原型中可复用的内容。
然后面试官又问如果只想改变子类的原型而不影响父类呢……我想了半天不知道怎么写,但是因为之前看过,就讲了下思想,就是用一个中间变量来存储其原型,然后给子类new一个……正确方法如下:
//临时构造函数模式(圣杯模式)(别问我为什么会有一个名字这么中二的方法我也不知道) //上面借用构造函数模式最后改进的版本还是存在问题,它把父类的原型直接赋值给子类的原型,这就会造成一个问题,就是如果对子类的原型做了修改,那么这个修改同时也会影响到父类的原型,进而影响父类对象,这个肯定不是大家所希望看到的。为了解决这个问题就有了临时构造函数模式。 var Parent = function(name){ this.name = name || 'parent' ; } ; Parent.prototype.getName = function(){ return this.name ; } ; Parent.prototype.obj = {a : 1} ; var Child = function(name){ Parent.apply(this,arguments) ;//通过apply调用父类的构造函数来进行相同的初始化工作 } ; var F = new Function(); F.prototype = Parent.prototype ; Child.prototype = new F() ; //通过在父类原型和子类原型之间加入一个临时的构造函数F,切断了子类原型和父类原型之间的联系,这样当子类原型做修改时就不会影响到父类原型。 var parent = new Parent('myParent') ; var child = new Child('myChild') ; console.log(parent.getName()) ; //myParent console.log(child.getName()) ; //myChild
其他方法的分析见:js怎么实现继承?
然后第二个面试官又问到除了使用原型还有别的方法吗?我想了想说……call?啊其实我也不知道了~
2. 对象冒充
1 function Parent(name){ 2 this.name = name; 3 this.getName = function(){ 4 return this.name; 5 } 6 } 7 function Child(name,password){ 8 //通过以下3步实现将Parent属性和方法追加到Child中,从而实现继承 9 //第一步:this.method是作为一个临时的属性,并且指向Parent所指的对象 10 //第二步:执行this.method方法,即执行Parent所指向的对象函数 11 //第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法 12 this.method = Parent; 13 this.method(name); 14 delete(this.method); 15 16 this.password = password; 17 this.world = function(){ 18 alert(this.password); 19 } 20 } 21 var child = new Child("Mychild","123456"); 22 console.log(child.getName()); //Mychild 23 child.world(); //123456
4. 了解设计模式吗?用js实现观察者模式。(一脸懵逼)
观察者模式:设计该模式背后的主要动力是促进形成松散耦合。在这种模式中,并不是一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在状态改变后获得通知。订阅者也称为观察者,而补观察的对象称为发布者或主题。当发生了一个重要的事件时,发布者将会通知(调用)所有订阅者并且可能经常以事件对象的形式传递消息。
思路:发布者对象需要一个数组类型的属性,以存储所有的订阅者。订阅(即注册)行为就是将新的订阅者加入到这个数组中去,则注销即是从这个数组中删除某个订阅者。此外,发布消息,就是循环遍历订阅者列表并通知他们。
这里我的大体思路是对的,但是在发布者之外定义了一个新的类即订阅者。在订阅者中定义了一个方法getNews以便在发布者发布消息时调用该方法。然后面试官说这样太麻烦了,万一订阅者没有这个方法呢?然后我不是很懂……于是在发布消息时直接传递了参数:obj.news = msg; 然后面试官说这样不是更麻烦了吗?这样的话如果订阅者没有news这个属性怎么办?还得判断订阅者是否有news这个属性,没有的话就会出现undifined的报错。然后我就不知道该怎么做了……然后面试官为人特别nice,告诉我说可以用继承,或者是在注册时候就传入一个function。
下来后上网查相关,注意点如下:
1. 发送消息即通知,意味着调用订阅者对象的某个方法。故当用户订阅信息时,该订阅者需要向paper的subscribe()提供它的其中一个方法。--------这应该就是面试官所说的注册时候就传入一个方法。
2. 发布对象paper需要具有以下成员:
a、 subscribers:一个数组,存储订阅者
b、 subscribe():注册/订阅,将订阅者添加到subscribers数组中
c、 unsubscribe(): 取消订阅。从subscribers数组中删除订阅者
d、 publish() 循环遍历subscribers数组中的每一个元素,并且调用他们注册时所提供的方法
所有这三种方法都需要一个type参数,因为发布者可能触发多个事件(比如同时发布一本杂志和一份报纸)而用户可能仅选择订阅其中一种,而不是另外一种。
1 //由于这些成员对于任何发布者对象都是通用的,故将它们作为独立对象的一个部分来实现是很有意义的。那样我们可将其复制到任何对象中,并将任意给定对象变成一个发布者。 2 //如下实现一个通用发布者 3 //定义发布者对象...{}是定义一个对象 4 var publisher = { 5 subscribers: { 6 any: [] //事件类型:订阅者 event type: subscribers 7 }, 8 subscribe: function(fn,type){ 9 type = type || 'any'; 10 if(typeof this.subscribers[type] === "undefined"){ 11 this.subscribers[type] = []; 12 } 13 this.subscribers[type].push(fn); 14 }, 15 unsubscribe: function(fn,type){ 16 this.visitSubscribers('unsubscribe', fn, type); 17 }, 18 publish: function(publication, type){ 19 this.visitSubscribers('publish',publication,type); 20 }, 21 visitSubscribers: function(action,arg,type){ 22 var pubtype = type ||'any', //发布的类型 23 subscribers = this.subscribers[pubtype], //这个类型的接受者数组 24 i, 25 max = subscribers.length; 26 27 for(i=0;i<max;i++){ 28 if(action === "publish"){ //发布 29 subscribers[i](arg); 30 } else { //取消订阅 31 if(subscribers[i] === arg){ 32 subscribers.splice(i,1); 33 } 34 } 35 } 36 } 37 }; 38 //定义一个函数makePublisher(),它接受一个对象作为对象,通过把上述通用发布者的方法复制到该对象中,从而将其转换为一个发布者 39 function makePublisher(o){ 40 var i; 41 for(i in publisher) { 42 if(publisher.hasOwnProperty(i) && typeof publisher[i] === "function"){ 43 o[i] = publisher[i]; 44 } 45 } 46 o.subscribers = {any: []}; 47 } 48 //实现paper对象 49 var paper = { 50 daily: function(){ 51 this.publish("big news today"); 52 }, 53 monthly: function(){ 54 this.publish("interesting analysis","monthly"); 55 } 56 }; 57 //将paper构造成一个发布者 58 makePublisher(paper); //makePublisher方法把发布者publisher的方法复制到paper对象中,从而使其成为一个发布者 59 60 //以上已经有了一个发布者。看看订阅对象joe,该对象有两个方法:注册时,将此方法传入paper的订阅方法,完成注册,则在发布消息时会调用该方法 61 var joe = { 62 drinkCoffee: function(paper) { 63 console.log('Just read' + paper); 64 }, 65 sundayPreNap : function(monthly){ 66 console.log('About to fall asleep reading this ' + monthly); 67 } 68 }; 69 70 71 //paper注册joe(即joe向paper订阅) 72 paper.subscribe(joe.drinkCoffee); //订阅any类型 73 paper.subscribe(joe.sundayPreNap,'monthly'); //定义monthly类型 74 //即joe为默认“any”事件提供了一个可被调用的方法,而另一个可被调用的方法则用于当“monthly”类型的事件发生时的情况。现在让我们来触发一些事件: 75 paper.daily(); //Just readbig news today 76 paper.monthly(); //About to fall asleep reading thisinteresting analysis 77 78 var Jack = { 79 readPaper: function(paper){ 80 console.log('Jack read' + paper); 81 } 82 }; 83 paper.subscribe(Jack.readPaper); 84 paper.daily(); //输出: Just readbig news today Jack readbig news today 85 86 //以上代码的好处在于,paper对象并没有硬编码joe,而joe中也并没有硬编码paper。此外,代码中也没有那些知道一切的中介者对象。由于参与对象是松耦合的,我们可以向paper添加更多的订阅者而根本不需要修改这些对象。 87 88 //进一步扩展,让joe成为发布者(比如:博客和微博上任何人都可以是发布者) 89 makePublisher(joe); 90 joe.tweet = function(msg) { 91 this.publish(msg); 92 }; 93 //现在,paper的公关部门决定读取读者的tweet,并订阅joe的信息,那么需要提供方法readTweets(): 94 paper.readTweets = function(tweet){ 95 console.log('Call big meeting! Someone ' + tweet); 96 }; 97 joe.subscribe(paper.readTweets); //paper订阅joe的tweet 98 joe.tweet('hello the world!'); //Call big meeting! Someone hello the world!
5. linux服务器下文件传输命令?如果要断点续传呢?
答:scp传输。scp 源文件 目标文件
但是scp不能实现断点续传。要实现传输中断后从断掉的地方接着来,可以用curl
-C/--continue-at <offset> 断点续转
//如果在下载dodo1.JPG的过程中突然掉线了,可以使用以下的方式续传
# curl -C -O http://www.doiido.com/dodo1.JPG
或者curl -r 可以实现分段下载
6. js跨域
js跨域是因为同源策略导致的。解决方法有:
- 图像Ping:使用<img>标签,因为网页可以从任何网页中加载图片,而不用担心跨域。请求数据通过字符串形式发送,而响应可以是任何内容。这种方法,1)只能发送get请求。2)浏览器无法获取响应数据。3)只适用于浏览器与服务器之间的单向通信
- JSONP:通过动态<script>元素使用,使用时为src指定一个跨域url。有两部分:1)回调函数:响应到来时在页面中使用;2)数据:传入回调函数中的JSON数据
- 后台代理方法:将后台作为代理,每次对其它域的请求转交给本域的后台,本域的后台通过模拟http请求去访问其它域,再将返回的结果返回给前台
- 设置document.domain:只适用于主域相同子域不同
- 使用window.name:+iframe。应用页面创建iframe,src指向数据页面;数据页面把数据附加到window.name上;应用界面监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件;获取数据后销毁iframe
- 使用html5新方法:window.postMessage(message, targetOrigin)