一、问答题(50分)
1、let和var的区别(6分)
let、const:
- 不存在变量提升。
- 只能声明一次,不能重复声明
- 变量声明出来存在VO(变量对象)或AO(活动对象)中,不会给window增加属性
- 遇到大括号有块级作用域
var:
- 有变量提升
- 在全局中声明的变量,会给window增加一个属性。
2、call、bind、apply的区别(6分)
call改变this并执行函数;bind改变this,但不会执行函数,会把改变this后的函数体返回;
apply与call的传参方式不同,需要把传给F函数的参数放到一个数组(或者类数组)中传递进去
3、构造函数与普通函数执行的区别(4分)
构造函数执行之前,首先创建一个对象(创建一个堆内存,暂时不存储任何东西),并且让函数中的执行主体(this)指向这个新的堆内存(this===创建的对象)。
执行完以后把this这个堆内存返回。
4、构造函数执行,如果有return会怎么样(4分)
return的是一个基本值,返回的结果依然是类的实例,没有受到影响
return引用值,则会把默认返回值覆盖
5、实现一个方法,检测该属性是否是该对象的公有属性。(10分)
Object.prototype.hasPubProperty = function (attr) {
let proto = Object.getPrototypeOf(this);
while(proto){
if(proto.hasOwnProperty(attr))return true;
proto = Object.getPrototypeOf(proto);
}
return false;
};
6、类数组转数组的三种方式(3分)
Array.from(arguments)
[…arguments]
[].slice.call(arguments)
7、如何能够让类数组使用forEach方法(2分)
[].forEach.call(arguments,()=>{})
8、描述原型链的机制(4分)
原型链:属性的查找机制
他是一种基于__proto__
向上查找的机制。当我们操作实例的某个属性或者方法的时候,首先找自己空间中私有的属性或者方法
找到了则结束查找,使用自己私有的即可
没有找到,则基于__proto __
找所属类的prototype,如果找到就用这个共有的,没有找到,基于原型上的__proto __
继续向上查找,一直找到object.prototype 的原型为止,如果再没有,操作的属性或者方法不存在
9、函数的三种角色(3分)
普通函数、构造函数、普通对象
10、Object的proto指向哪(2分)
Function的原型
11、手写map方法的实现原理(6分)
Array.prototype.myMap = function (fn) {
let res = [];
for (let i = 0; i < this.length; i++) {
res.push(fn(this[i], i));
}
return res;
};
二、基础编程(33分)
1、下面代码的输出结果(3分)
10 ‘zf’ 22
let obj = {
name:'zf',
age:12,
b:2
};
let {age=10,name='zhufeng',bb=22} = obj;
console.log(age,name,bb)
2、下面代码的输出结果(8分) 2 1 3 3
var obj1 = {
a: 1
}
var obj2 = {
a: 2,
foo1: function () {
console.log(this.a)
},
foo2: function () {
setTimeout(function () {
console.log(this.a)
}, 0)
}
}
var a = 3
obj2.foo1();//把foo1对应的函数执行,此时的this=>obj2 console.log(this.a)=>console.log(obj2.a)=>2
obj2.foo1.call(obj1)//把foo1对应的函数执行 .call方法更改了方法中的this执行 this=>obj2=>更改为obj1 相当于console.log(obj.a)=>1
obj2.foo2();//f002执行但是执行的是匿名函数,匿名函数中的this是全局下的window 相当于 console.log(this.a)=>console.log(window.a)=>3
obj2.foo2.call(obj1)//虽然更改了foo2执行的this的执行,但是因为是匿名函数,匿名函数中的this是window同上
3、下面代码输出的结果(6分)2 1 2 1
function foo () {
console.log(this.a);
return function () {
console.log(this.a);
}
}
var obj = { a: 1 };
var a = 2;
foo();//=>this=>2 window window.a=>2
foo.call(obj);//=>foo 1 执行 this更改为obj=>obj.a=>1
foo().call(obj);//2 1 //=>foo执行的实例.call foo执行的时候this为window window.a=2 retrun的堆 0x001.call(obj)=>此时this更改为obj=>1
4、下面代码输出的结果(6分)’zhufeng’ 5000 ‘zhufeng’ 9 9 5000
function Person() {
this.name = 'zhufeng';
}
Person.prototype.getName = function () {
console.log(this.name);
console.log(this.age);
};
Person.prototype.age = 5000;
var per1 = new Person();
per1.getName();
per1.age = 9;
per1.getName();//9
console.log(per1.age);//9
var per2 = new Person();
console.log(per2.age);//5000
4、下面代码输出的结果(4分)0 30
function fun() {
this.a = 0;
this.b = function () {
alert(this.a);
};
}
fun.prototype = {
b: function () {
this.a = 20;
alert(this.a);
},
c: function () {
this.a = 30;
alert(this.a);
},
};
var my_fun = new fun();
my_fun.b();
my_fun.c();
5、下面代码的输出结果(6分)2 4 1 1 2 3
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
};
Foo.prototype.getName = function () {
console.log(3);
};
var getName = function () {
console.log(4);
};
function getName() {
console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
三、编程实战(17分)
1、编写一个数组去重的函数,并且可实现数组调用(7分)
数组去重的n种办法
let ary = [12,23,12,13,13,12,23,14,8];
ary.unique();//=>[12,23,13,14,8]去重后的新数组
Array.prototype.unique = function() {
let ary = [];
this.forEach(item => {
if(ary.indexOf(item)===-1) {
ary.push(item)
}
})
return ary
}
2、实现数字可调用方法,plus加法与minus减法(10分)
let n = 10;
let m = n.plus(10).minus(5);
console.log(m);//=>15(10+10-5)
Number.prototype.plus = function (num = 0) {
return this + num;
};
Number.prototype.minus = function (num = 0) {
return this - num;
};