博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端笔试题[1]
阅读量:4086 次
发布时间:2019-05-25

本文共 9096 字,大约阅读时间需要 30 分钟。

http://www.cnblogs.com/Candybunny/category/811557.html

一.闭包

最开始理解闭包是在一个函数内部定义一个函数,可以在外面的环境里进行调用。现在对于闭包的理解是利用函数来保存作用域内的对象。

理解闭包首先要理解执行上下文,变量对象,活动对象,作用域链。因为执行上下文在函数执行后会销毁,因此变量也同时消失,但是为了一些特殊的应用场景,因此需要在函数执行后依旧可以访问到函数内的变量。js语言将函数作为“一等公民”,可以作为参数进行传递,同时每个函数也拥有其作用域链,如果内部函数作为变量返回,那么它将带着它的作用域链一同返回。因为内部函数的作用域链中包含着外部函数的变量,函数声明和参数等,因此,外部函数即使被执行完了,变量也不会销毁,因为他们依旧被内部函数的作用域链引用。 举个例子:

1
2
3
4
5
6
7
8
var 
scope =
'global scope'
;
function 
foo() {
    
var 
scope =
'local scope'
;
    
return 
function 
bar() {
    
console.log(scope);
    
}
}
foo()();

执行结果是‘local scope’。因为在返回的bar函数被调用的时候,会先从自己的作用域链查找,没有的话会逐级再向上查找,直到找到scope对象,输出结果结束。

二.this

如果把上面的代码增加一句话,在返回的函数中输出this。

1
2
3
4
5
6
7
8
9
var 
scope =
'global scope'
;
function 
foo() {
    
var 
scope =
'local scope'
;
    
return 
function 
bar() {
    
console.log(scope);
        
console.log(
this
);
    
}
}
foo()();

结果是’local scope’,’window’。this指向的是global对象,在浏览器中就是window。 对this的理解是:

1)它是在解析函数的时候确定的,即执行上下文的一个属性,运行过程中并不会改变。

1
2
3
4
5
6
function 
foo() {
    
function 
bar () {
      
...
    
}
    
this 
= bar;
//会报错
}

2)this根据调用函数的对象或者表达式形式确定。

1
2
3
4
function 
foo() {
   
console.log(
this
);  
}
foo();

调用函数的对象是Global,即window

1
2
3
4
5
6
7
8
9
10
11
12
var 
foo = {
   
x:10,
   
bar:
function 
() {               
        
console.log(
this
.x);     
   
}  
}
var 
zoo = {
    
x:20
}
zoo.bar = foo.bar;
zoo.bar();
foo.bar();

输出20,10,调用函数的对象分别是zoo和foo

1
2
3
4
5
6
7
8
9
10
x =
'global x'
;
var 
foo = {
   
x:
'local x'
,
   
bar:
function 
() {       
        
console.log(
this
.x);  
   
}  
}
foo.bar();
(foo.bar)();
(foo.bar = foo.bar)();

()表达式并没有改变函数本身的调用值,因此返回‘local x’,赋值表达式改变了函数本身的调用值,因此返回‘global x’。

3)new操作符调用的函数this指向构造函数对象

当函数作为构造器被调用的时候:

1
2
3
4
5
6
7
function 
A() {
  
alert(
this
);
// newly created object, below - "a" object
  
this
.x = 10;
}
  
var 
a =
new 
A();
alert(a.x);
// 10

在这种情况下,new操作符会生成一个新的对象,即构造函数定义的对象。 在对象创建之后,然后所有“A”函数中this的值会设置为新创建的对象。

可以通过函数对this值进行人为干预:

4)call和apply函数

1
2
3
4
5
6
7
8
9
10
x =
'global x'
;
var 
foo = {
   
x:
'local x'
,
   
bar:
function 
(n) {       
        
console.log(
this
.x);
        
console.log(n); 
   
}  
}
foo.bar.call({x:
'call x'
},
'call'
);
foo.bar.apply({x:
'apply x'
}, [
'apply'
]);

通过call和apply的第一个参数改变this的值。

参考文章:

对于js中原型的理解,我仅处在初级阶段。我的理解是,js的原型是为了实现“类”的概念,可以使得对象的方法可以通用,实现类的继承。虽然js中并没有类的概念,但是多数情况下,人们还是偏向于使用面向对象的概念在编程。

Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。当我们用js来模拟类时就涉及到了原型链的概念。原型链和作用域链的作用很相似,都是用来定义查询变量的一种规则。当你在自身查找不到某个变量或者方法的时候,原型链会根据规则继续向上查找,直到顶端为止。

比如,在定义一个“类”的时候,通常会先定义一个构造函数,里面包含了实例属性。

function Person (name, age) {     this.name = name;     this.age = age;}

他可能包含了一些通用的方法(类方法),比如读取姓名和年龄,安排班级等

Person.prototype.getName = function () {    return this.name;}Person.prototype.getAge = function () {    return this.age;}

当我们需要给一个类定义通用的方法的时候,我们需要在它的原型上定义属性,这样,所有通过构造函数生成的实例都可以调用该方法。

继承的实现也是因为有原型的存在得以实现,通用的实现继承方法如下:

 
function Person (name, age) {     this.name = name;     this.age = age;}Person.prototype.getName = function () {    return this.name;}Person.prototype.getAge = function () {    return this.age;}Person.prototype.setAge = function (age) {    this.age = age;}function Teacher(name,age,no){    //实现子类属性的继承,每个实例都有属于自己的属性,同时需要注意参数的顺序,call函数只看重顺序,不在乎参数名称         Person.call(this, name, age);         this.classNo = no;}Teacher.prototype = new Person();  //将父类的对象赋值给子类,原型对象,这样子类就继承了父类的方法

// 在支持ES5的浏览器推荐下面的写法:(创建一个新的对象,内容是Person.prototype,将其赋值给Teacher.prototype,这样就将Person的原型和Teacher的原型相关联,并不会产生副作用)// Teacher.prototype = Object.new(Person.prototype);

Teacher.prototype.getInfo = function () {       console.log('name:' + this.name + 'age:' + this.age + 'classNo:' + this.classNo);}var teacherLi = new Teacher('Li', 30, 2);teacherLi.getInfo(); //name:Liage:30classNo:2teacherLi.setAge(28);teacherLi.getInfo(); //name:Liage:28classNo:2

一. new操作符的含义

当我们使用new操作符时,实际上就是创建一个对象。但在实际运行当中,new是创建了两个对象,并将其相互关联。例如上面的例子中var teacherLi = newTeacher('Li', 30, 2); 这句话,new操作符创建了一个对象并将它赋值给teacherLi,并将teacherLi和Teacher.prototype相联系,teacherLi.__proto__ === Teacher.prototype。

在ES5规范里,针对new的操作的定义如下:

简单理解就是:

1. 新建一个对象

2. 将对象的内部__proto__属性和构造函数的prototype相关联

3. 利用构造函数给实例对象属性赋值

4. 如果构造函数没有显示返回对象,则返回步骤一创建的对象

二.constructor

Foo.prototype.constructor === Foo

Foo.prototype的.constructor属性只是Foo函数在声明时的默认属性。如果prototype被重新赋值声明,那么constructor就不知道是指向谁了,它会根据原型链一直检索,直到检索到最上层Object对象。

function Foo() { /* .. */ }Foo.prototype = { /* .. */ }; // 创建一个新原型对象var a1 = new Foo();a1.constructor === Foo; // false!a1.constructor === Object; // true!

三.prototype&__proto__

对象的__proto__属性指向它关联的prototype对象。可以简单的理解为实例的__proto__属性指向它的原型对象。

function Foo(a) {    this.a = a;}var foo = new Foo('foo');console.log(foo.__proto__ === Foo.prototype);console.log(Foo.__proto__ === Function.prototype);console.log(Function.__proto__ === Function.prototype);console.log(Function.prototype.__proto__ === Object.prototype);console.log(Object.prototype.__proto__ === null);

以上的答案都是true,可以看到当你用new标识符来创建一个属性时它会默认应用建立原型链,一直关联到Object这个对象原型。

在js的内置类型当中:

Number.__proto__ === Function.prototype  // trueBoolean.__proto__ === Function.prototype // trueString.__proto__ === Function.prototype  // trueObject.__proto__ === Function.prototype  // trueFunction.__proto__ === Function.prototype // trueArray.__proto__ === Function.prototype   // trueRegExp.__proto__ === Function.prototype  // trueError.__proto__ === Function.prototype   // trueDate.__proto__ === Function.prototype    // trueMath.__proto__ === Object.prototype  // trueJSON.__proto__ === Object.prototype // true

因为Function.prototype.__proto__ === Object.prototype得值是true,所以,函数也是对象。

之前看到过一套测试题,放在这里以供思考:

function Foo() {    getName = function () { alert (1); };    return this;}Foo.getName = function () { alert (2);};Foo.prototype.getName = function () { alert (3);};var getName = function () { alert (4);};function getName() { alert (5);} //请写出以下输出结果:Foo.getName();getName();Foo().getName();getName();new Foo.getName();new Foo().getName();new new Foo().getName();

解释地址:

前两天在网上看到了一道面试题,问iframe高度自适应的问题。发现自己之前几乎没有关注过iframe的问题,所以在这里记录一下。

原题目是: 页面A的域名是:http://www.taobao.com,页面B的域名是http://www.tmall.com,如果A使用iframe引用页面B,如何做到iframe的高度自适应(即B内容有多高,iframe就有多高)

在这里首先分析一下如果不涉及跨域或者只是主域相同,子域不同的情况下的解决方案:

父页面代码:

1  2  3  4     
5 Document 6 7 8 9 26 27

 

看到张鑫旭的博客里说到另一种方法,是在iframe页面传递一个参数给父页面,告知其高度。父页面取到参数后再给iframe高度赋值。

大致原理在子页面iframe里定义

// 为了防止window.location.hash产生跨域问题,可以直接写死hostUrl地址:利用window.top.location = 父页面地址(写死) + 锚点 var hostUrl = window.location.hash.slice(1);hostUrl += "#height=" + 1294;window.top.location = hostUrl;

然后将子页面嵌入到父页面中,父页面提取location中的height数值,从而更改iframe高度。

var iframeHeight = function() {        var hash = window.location.hash.slice(1);    if (hash && /height=/.test(hash)) {        iframe.height = hash.replace("height=", "");    }    setTimeout(iframeHeight, 200);};iframeHeight();

可以参考:

这里思考了一下是不是可以不写死页面的地址:

假设面试题目中提到的页面A:www.taobao.com内部嵌入页面B:www.tmall.com页面,要让B页面高度自适应的解决方案

参考各种资料,可以利用中间代理页面agent.html来完成。

主要原理是agent页面和A页面同源,将agent页面嵌入到B页面获取到B页面宽高后,通过url传递宽高值。通过agent来操作A页面中嵌入的B页面宽高。

1. 在A(taobao)页面嵌入iframe

2. 在B(tmall)页面嵌入agent_iframe,获取B页面的宽高。(将获取到的宽高通过url传递)

3.  在agent.html插入代码(因为agent和A页面是相同域名,所以可以通过子元素来控制父元素的父元素[因为agent是嵌入在B页面的,B页面嵌入在A页面,因此agent可以控制A页面的元素,此处为多层嵌套,有点绕]的宽高)

总结

个人认为,如果父页面的地址是固定的,我觉得直接写死地址是比较方便直观的方法。当然还有很多其他方法可以实现高度自适应。

详见:

看到的笔试题,总结在这里吧!

1.运用JS设置cookie、读取cookie、删除cookie

function setCookie (name, value) {        let duringDay = 30;        let exp = new Date();        // setTime() 方法以毫秒设置 Date 对象。        exp.setTime(exp.getTime() + duringDay*24*60*60*1000);        // 防止Cookie中不允许需要保存的字符串中有“;”出现。有些操作系统,在解释中文的字符串时候常常会出现乱码的现象。避免储存数据中出现非英文字母、非数字的字符。运用escape编码        document.cookie = name + '=' + escape(value) + ';expires=' + exp.toGTMString();    }    // setCookie('ga', 'aaaaa');    function getCookie (searchName) {        let rsObj = {};        let rsArray = document.cookie.split(';');        rsArray.map((cv,index,array)=>{            let item = cv.split('=');            //去掉空格            let name = unescape(item[0].split(' ').join(''));            let value = unescape(item[1]);            rsObj[name] = value;        });        /* 或者利用正则        let arr;        let reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");        if(arr=document.cookie.match(reg)) {            return unescape(arr[2]);        }        else {            return null;        }        */        return rsObj[searchName];    }    // getCookie('ga');    function deleteCookie(delName) {        let exp = new Date();        exp.setTime(exp.getTime() - 1);        let val = getCookie(delName);        if (val) {            // toGMTString() 方法可根据格林威治时间 (GMT) 把 Date 对象转换为字符串,并返回结果。            // Thu, 29 Dec 2016 10:48:00 GMT            document.cookie = delName + '=' + val + ';expires=' + exp.toGTMString();        }    }    // deleteCookie('ga');

2. 请编写一个JavaScript函数 parseQueryString,它的用途是把URL参数解析为一个对象,如:var url = “http://witmax.cn/index.php?key0=0&key1=1&key2=2″;

function parseQueryString () {        let query = window.location.search.substring(1);        let arr = query.split('&');        let obj = {};        arr.map((cv,index,array)=>{            let item = cv.split('=');            let name = decodeURIComponent(item[0]);            let value = decodeURIComponent(item[1]);            obj[name] = value;        });        return obj;    }    // let foo = parseQueryString();     // console.log(foo);
你可能感兴趣的文章
可以买个好点的电烙铁
查看>>
ACfly调参记录(包括ACfly-F330和ACfly-T265)
查看>>
一定记得每飞几次或者隔一天要把螺丝和浆帽拧一次,确实会松的
查看>>
《多旋翼无人飞行器嵌入式飞控开发指南》里基于FreeRTOS的无人机软件框架
查看>>
思岚A1的SDK其实很好读懂,每个函数清晰明了,可以直接调用
查看>>
pixhawk(PX4)的一些论坛网站(包括中文版的PX4用户手册和PX4开发手册)
查看>>
串级 PID 为什么外环输出是内环的期望?(和我之前对串级PID的总结一样)
查看>>
我刚刚才完全清楚GPS模块的那根杆子是怎么固定安装好的
查看>>
去github里面找找也没有别人无人机+SLAM的工程
查看>>
PX4与ROS关系以及仿真控制(键盘控制无人机)
查看>>
我对无人机重心高度的理解
查看>>
现在明白为什么无名博客里好几篇文章在讲传感器的滞后
查看>>
实际我看Pixhawk定高模式其实也是飞得很稳,飘得也不厉害
查看>>
Pixhawk解锁常见错误
查看>>
C++的模板化等等的确实比C用起来方便多了
查看>>
ROS是不是可以理解成一个虚拟机,就是操作系统之上的操作系统
查看>>
用STL algorithm轻松解决几道算法面试题
查看>>
ACfly之所以不怕炸机因为它觉得某个传感器数据不安全就立马不用了
查看>>
我发觉,不管是弄ROS OPENCV T265二次开发 SDK开发 caffe PX4 都是用的C++
查看>>
ROS的安装(包含文字和视频教程,我的ROS安装教程以这篇为准)
查看>>