第一题
function fun(){
for(var i=0,arr=[];i<3;i++){
arr[i]=function(){
console.log(i)
}
}
return arr;
}
var funs=fun();
funs[0]();//3
funs[1]();//3
funs[2]();//3
第二题
去掉数组中非数字字符,并给每个数字加+1
var arr=[1,2,3,“a”,4,“b”]
for(var i=arr.length-1;i>=0;i--){
if(typeof arr[i]==="number"){
arr[i]++ ;
}else{
arr.splice(i,1);
}
}
第三题
在两个排好序的数组中,高效率的找出相同的元素,放入新数组
var arr1=[1,3,7,9,12,37,45]
var arr2=[2,4,9,13,45,88,92]
for(var i=0,j=0,arr=[];i<arr1.length&&j<arr2.length;){
if(arr1[i]>arr2[j]){
j++;
}else if(arr1[i]<arr2[j]){
i++;
}else{
arr.push(arr1[i]);
i++;
j++;
}
}
第四题
找出一个排好序的数组中,两个元素相加和为19的元素组合,考虑程序的执行效率
var arr=[1,2,4,6,7,11,12,15,17]
for(var i=0,j=arr.length-1;i<j;){
if(arr[i]+arr[j]<19){
i++;
}else if(arr[i]+arr[j]>19){
j--;
}else{
console.log(`${arr[i]}+${arr[j]}`);
i++;
j--;
}
}
第五题
统计一个字符串中每种字符出现的次数?出现次数最多的是哪个字?共出现几次
for(var i=0,arr=[];i<str.length;i++){
var char=str[i];
if(arr[char]===undefined){
arr[char]=1
}else{
arr[char]++;
}
}
/* 这种方法也可以
var res=str.split("").reduce(function(prev,elem){
if(prev[elem]!==undefined){
prev[elem]++
}else{
prev[elem]=1;
}
return prev;
},{})
console.log(res);
*/
var maxChar,count=0;
for(var key in arr){
if(arr[key]>count){
maxChar=key;
count=arr[key];
}
}
第六题
[]-[], []+[] 分别输出多少
- 法计算永远试图将左右两边的值都转为数字,因为只有数字可以做减法。所以,自动调用Number()
Number([]) = 0 记住。
[]-[]等于0, []-1等于-1
+ 法则完全不同。两个对象相加,会自动调用两个对象的toString方法,将两个对象转为字符串,然后执行字符串拼接。
[].toStirng() = “”,因为数组没有值,所以转为空字符串
[]+[],等于""+"",返回""
[1,2,3]+[4,5,6], 等于"1,2,3"+“4,5,6” 结果:
“1,2,34,5,6”
第七题
function fun(o){
o.name="西西";
o={};
o.name="小丽";
}
var obj={name:"小红",age:11};
fun(obj);
console.log(obj);
> {name: "西西", age: 11}
第八题
深克隆
function clone(obj){
var newObj={};
if(obj==null){
return null;
}else if({}.toString.call(obj)==="[object Array]"){
var newArr=[];
newArr=obj.slice();
return newArr;
}
for(var key in obj){
if(typeof obj[key]!=="object")//typeof null 也是object
{
newObj[key]=obj[key];
}else{
newObj[key]=clone(obj[key]);
}
}
return newObj;
}
第九题
function fun(){//妈妈
var n=999;//红包
//共生了几个孩子?
nAdd=function(){n++};//剖腹产
//js中一个特征: 任何情况下给一个从未声明过的变量赋值,不会报错!而是自动在全局创建该变量!
return function(){//顺产
console.log(n)
}
}
var getN=fun();//妈妈生了一次孩子,包了一个红包
//getN:function(){console.log(n)}
getN();//999
nAdd();
getN();//1000
第十题
// var a=10;
// function fun(){
// var a=100;
// a+=1;
// console.log(a)
// }
// fun();//101
// console.log(a);//10
// var a=10;
// function fun(){
// a=100;
// a+=1;
// console.log(a)
// }
// fun();//101
// console.log(a);//101
var a=10;
function fun(a){//局部变量
/**只要函数自己有a,则内部一切操作与全局无关***/
a=100;
a+=1;
console.log(a)
/******************************************/
}
fun(a);//101
console.log(a);//10
第十一题
function ltrim(str){
return str.replace(/^\s+/,"")
}
function rtrim(str){
return str.replace(/\s+$/,"")
}
function trim(str){
return str.replace(/^\s+|\s+$/g,"")
}
第十二题
function fun(){console.log(1)};
fun();//2
function fun(){console.log(2)};
fun();//2
var fun=100;
fun();//报错
> 2
> 2
>Uncaught TypeError: fun is not a function
at <anonymous>:6:1
第十三题
内置对象11种
String Boolean Number
Math Date RegExp Array
Function Error Object
Global
第十四题
如何知道现在的浏览器中该类型下都有哪些可用的函数?
所有类型的函数列表都保存在原型对象中:
比如: Array.prototype下包含着目前数组对象可用的所有函数
String.prototype 下包含着目前字符串对象可用的所有函数
第十五题
如果经常使用的一个函数,在原形对象中没有,而我们又想让所有的孩子都能用上这个函数:
自己定义该函数,并强行放入原型对象中!
比如: 经常对数组求和,但是数组暂时没有求和的函数sum
Array.prototype.sum=function(){
… …
}
将来: arr1.sum() arr2.sum() … …
强调: 运行对象方法中应该用this指向将来调用该函数的.前的当前类型的子对象。
比如:
Array.prototype.sum=function(){
console.log(“调用了一次自己的sum函数”);
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i]
}
return sum;
}
var arr1=[1,2,3];
var arr2=[1,2,3,4,5];
var arr3=[1,2,3,4,5,6,7];
console.log(
arr1.sum(),
arr2.sum(),
arr3.sum()
)
第十六题
自有属性和共有属性:
(1). 自有属性: 直接保存在当前对象内部,仅归当前对象自己所有的属性
(2). 共有属性: 保存在原型对象中,所有子对象共有的属性
(3). 获取属性值: 二者没有差别,都可用子对象打.访问
子对象.属性名
程序会优先在当前对象内部先找自有属性。如果没有想要的自有属性,才去父对象中查找
(4). 修改属性值:
a. 自有属性可用用子对象直接修改:
lilei.sage=26
b. 共有属性不能用子对象修改,必须用原型对象本身来修改
构造函数.prototype.共有属性=值
比如: Student.prototype.className=“初二2班”
如果强行用子对象修改共有属性,不会报错,而是给这个子对象悄悄添加一个自有同名属性。从此,这个子对象,在这个属性的使用上和其它子对象分道扬镳
第十七题
总结: this 目前4种用法:
- obj.fun() this->obj
- fun() this->window
- new Fun() this->new(正在创建的新对象)
- Array.prototype.sum=function(){ this }
arr1.sum() this->arr1
arr2.sum() this->arr2
第十八题
function Foo(){
Foo.a=function(){
console.log(1);
}
this.a=function(){
console.log(2);
}
}
Foo.prototype.a=function(){
console.log(3);
}
Foo.a=function(){
console.log(4)
}
Foo.a();
let obj=new Foo();
obj.a();
Foo.a();
> 4
> 2
> 1
第十九题
var x=0;
var foo={
x:1,
bar:function(){
console.log(this.x);
var that=this;
return function(){
console.log(this.x);
console.log(that.x);
}
}
}
foo.bar();
foo.bar()();
> 1
> 1
> 0
> 1
第二十题
function fun(n,o){
console.log(o);
return {
fun:function(m){
return fun(m,n)
}
}
}
var a=fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
> undefined
> 0
> 0
> 0
var b=fun(0)
.fun(1)
.fun(2)
.fun(3);
> undefined
> 0
> 1
> 2
var c=fun(0).fun(1);
c.fun(2);
c.fun(3);
> undefined
> 0
> 1
> 1
第二十一题
function A(){
}
function B(){
return new A();
}
A.prototype=new A();
B.prototype=new B();
var a=new A();
var b=new B();
console.log(a.__proto__==b.__proto__);

第二十二题
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
new new Foo().getName();//3

第二十三题
判断一个对象是不是数组类型,一共有几种方法:
//不正确的方法:typeof
var n=10,str='hello',b=true,nu=null,un;
var f=function(){};
var obj1={},obj2=[1,2,3],obj3=new Date();
console.log(
typeof(n),//number
typeof(str),//string
typeof(b),//boolean
typeof(nu),//object
typeof(un),//undefined
typeof(f),//function
typeof(obj1),//object
typeof(obj2),//object
typeof(obj3)//object
)
//判断爹:3种
//1.用__proto__获得对象的爹,然后再和数组的爹做比较
console.log(
obj1.__proto__==Array.prototype,//false
obj2.__proto__==Array.prototype,//true
obj3.__proto__==Array.prototype //false
)
//2.因为__proto__可能被浏览器禁用,所以有等效的函数来完成__proto__的任务:Object.getPrototypeOf(child)
console.log(
Object.getPrototypeOf(obj1)==Array.prototype,//false
Object.getPrototypeOf(obj2)==Array.prototype,//true
Object.getPrototypeOf(obj3)==Array.prototype//false
)
//3.还有一个更直接的函数:father.isPrototypeOf(child)
console.log(
Array.prototype.isPrototypeOf(obj1),//false
Array.prototype.isPrototypeOf(obj2),//true
Array.prototype.isPrototypeOf(obj3)//false
)
//判断妈妈
//4.用父级原型对象中的constructor属性
console.log(
obj1.constructor==Array,//false
obj2.constructor==Array,//true
obj3.constructor==Array//false
)
//用"child instanceof 妈妈"
console.log(
obj1 instanceof Array,//false
obj2 instanceof Array,//true
obj3 instanceof Array//false
)
//当obj1.__proto__=Array.prototype时,以上的判断方法均失效
//输出对象中的DNA:内部隐藏属性class
//.call()可让任意一个对象,抢到原本不属于它的任何一个函数
console.log(Object.prototype.toString.call(obj1)==="[object Array]");//false
console.log(Object.prototype.toString.call(obj2)==="[object Array]");//true
console.log(Object.prototype.toString.call(obj3)==="[object Array]");//false
//ES5中新增了一个专门判断一个对象是不是数组的函数:Array.isArray(obj)>bool
console.log(
Array.isArray(obj1),//false
Array.isArray(obj2),//true
Array.isArray(obj3)//false
)
第二十四题
var number=2;
var obj={
number:4,
fn1:(function(){
this.number*=2;
number*=2;
var number=3;
return function(){
this.number*=2;
number*=3;
console.log(number)
}
})()
}
var fn1=obj.fn1;
console.log(number);//4
fn1();//9
obj.fn1();//9
console.log(number);//8
console.log(obj.number);//16

第二十五题
console.log(window.a)输出undefined,而console.log(a),就报错,难道window.a是全局,a就不是全局?
答:所有全局变量一定是保存在window中的
保存在window中的变量其实有两种访问方式:
可以以变量语法方式: 变量名
可以以window对象的成员形式使用: window.变量
比如: var a=10;
console.log(a) //10
因为所有没有前缀的,js都会自动加上window.前缀——仅限于全局作用域中执行的程序
比如: alert() -> 执行时被补全为window.alert()
再比如: parseInt() -> 执行时被补全为window.parseInt()
console.log(window.a) //10
如果没有声明a,执行console.log(a)和console.log(window.a),一个报错,一个不报错?
语法规定:
如果直接访问一个不存在的变量,会报错!ReferenceError: a未定义
如果强行访问对象中一个不存在的属性,或访问数组中一个不存在的位置,不报错!而是返回undefined。
全局变量a,其实都有两个角色,一个是单纯的变量a,同时也是window对象中的成员。所以,以单独变量方式访问不存在的变量,则参考第一条规则,会报错。如果以window.a成员的方式访问变量a,永远不会报错!而是返回undefined。
补: var a和 window.a
1. 如果未声明变量a,则单独使用a会报错,而使用window.a不报错。
2. var a的变量不能用delete彻底删除
而用window.a强行添加的变量,才能被delete彻底删除
总结: 今后即使用全局变量,也要用window.变量。不要用var。因为如果不想用了,还可以用delete彻底删除。
第二十六题
pay=null后,为什么变量pay还在?
答: 给pay变量赋值为null,只是清空变量的内容,而变量在window中不会被删除。
如果希望彻底删除变量: delete window.变量
但是: 删除不掉!
原因: pay是var pay创建的。如果想用delete彻底删除变量,创建变量时,必须用window.pay
第二十七题
console.log(a) //报错,为什么不是undefine?
a=10;
console.log(a)
//因为a=10前,没有var。没有var,就不是声明语法,就不会会被声明提前。不会被声明提前,第一次使用时就没有a可用,就报错。a=10,只是一个赋值语句。赋值语句会强行创建变量a,但是,也只能在语句所在位置才创建a。因为声明提前规定,“”赋值留在原地“
第二十八题
为什么加入overflow:hidden或添加元素设置为display:table,可防止高度坍塌?BFC?
答: Block Formatting Context
以块的形式,格式化显示元素的子内容
为什么: 启用BFC模式都是为了避免子元素被隐藏或遮挡。
如何启用BFC:
浮动元素:float 除 none 以外的值。
绝对定位元素:position (absolute、fixed)。
display 为 inline-block、table-cells、flex。
overflow 除了 visible 以外的值 (hidden、auto、scroll)
后果:
1. 父元素启用BFC,则范围必须包含所有子元素的范围。
2. 平级子元素启用BFC,则其他兄弟子元素不能覆盖在它之上。
第二十九题
var tom='tom';
tom.money=100;
//new String(tom).money=100;
//调用后自动释放
console.log(tom.money);//undefined
//new String(tom).money
var tom=new String("tom");
tom.monry=10;
console.log(tom.money);//10
第三十题
闭包的外层函数向外抛出内层函数共有几种方式?
答: 3种:
1. return function(){ … }
2. 全局变量=function(){ … }
3. return [ function, …]
return { 方法: function(){ … } }
第三十一题
一共讲了几种this的情况?
答: 4种:
1. obj.fun() -> this->obj
2. fun() 或(function(){ … })() this->window
3. new fun() -> this->新对象
4. Student.prototype.intr=function(){ … this.sname …}
this-> 将来调用intr()的.前的子对象
第三十二题

第三十三题

第三十四题
判断是否为升序数组?
var arr1=[1,2,3,4,5];
var arr2=[2,4,6,4,2];
var result1=arr1.every(function(elem,i,arr){
return i<arr.length-1?elem<arr[i+1]:true;
});
var result2=arr2.every(function(elem,i,arr){
return i<arr.length-1?elem<arr[i+1]:true;
})
console.log(result1,result2);//true false
第三十五题

var arr=[1,2,3,4,5];
arr.forEach(function(elem,i,arr){
// elem*=2//按值传递改不了
arr[i]*=2;
})
console.log(arr);
arr=[{x:1},{x:2},{x:3},{x:4},{x:5}];
arr.forEach(function(elem){
elem.x*=2//引用类型,改变的了
})
console.log(arr);
第三十六题
页面上五个完全相同的按钮,点哪个按钮,让按钮弹出自己是第几个?





第三十七题


第三十八题
打散数组

第三十九题

第四十题
数组去重复,有几种方法,哪种方法最好(考虑数组中包含上万个元素的情况)
var arr=[];
for(var i=0;i<100000;i++){
arr.push(parseInt(Math.random()*10000));
}
//第一种:传统,利用对象的属性名不能重复的特点
function unique1(arr){
var obj={};
for(var n of arr){
obj[n]=1;
}
/*var newArr=[];
for(var key in obj){
newArr.push(parseInt(key));
}*/
//如果字符串内容的数组去重
var newArr=Object.keys(obj);
return newArr;
}
console.time("unique1")
unique1(arr);
console.timeEnd("unique1");
//第二种:利用新ES标准中的新类型Set---最优
//Set类型的对象:是值不允许重复的集合
//向Set类型对象中添加新值,如果Set中没有这个新值,才能添加进去,如果Set中已经有这个新值了,则不再添加
function unique2(arr){
//将原数组arr放入一个new Set()对象中,利用new Set()不允许重复值的特点,自动去重复
//var set=new Set();
//将set打散后,放入新数组
//var newArr=[...set];
//return newArr
return [...new Set(arr)]
}
console.time("unique2")
unique1(arr);
console.timeEnd("unique2");
第四十一题


第四十二题

第四十三题
将一个类数组对象转化为数组的几种方法
1.slice
语法:slice(begin,end)方法选择一个从开始到结束(不包括结束)的数组的一部分浅拷贝到一个新的数组对象,方法不会改变原数组。如果是对象则拷贝对象的引用到新数组,如果是基本类型则会拷贝这些值到新数组。
如果省略begin则会从0开始。如果end被省略则会抽取到最后一个元素,如果end数值大于数组长度则会抽取到最后一个元素。
使用Array.prototype.slice.call(arguments)可以将类数组转化为数组对象,[].slice.call(arguments)亦可
function list(){
return Array.prototype.slice.call(arguments);
}
var list=list(1,2,3);//[1,2,3]
2.splice
语法:splice(start)
splice(start,deleteCount)
splice(start,deleteCount,item1,item2…)
返回一个包含被删除元素的数组,start是必须值,其他是可选值,item表示要添加的元素,splice方法会直接对数组进行修改
Array.prototype.splice.call(arguments,0)
3.ES6 Array.from
语法:Array.from(arguments)
4.Array.prototype.concat.apply([],arguments)
第四十四题
arr1.every(function(elem,i,arr){ })内,如果想使用.前的arr1,为什么不能用this直接找到.前的对象,而只能用形参中的arr呢?
答:所有回调函数的执行,都是自动执行的,且没有.前缀。所以,绝大多数回调函数中的this,都指window。
再比如:
var lilei={
sname:“Li Lei”,
intr:function(){ console.log(I'm ${this.sname})}
};
lilei.intr(); //this->.前的lilei,所以可以正常输出lilei.sname
但是:
setTimeout(lilei.intr,3000); //3秒后输出的却是undefined
1. 为什么lilei.intr不加()?因为定时器不是立刻调用。而仅仅是给定时器拿走,等3秒后,由定时器自动调用。
2. 为什么输出undefined,而不是lilei.sname?
答: 因为定时器中的函数,也是回调函数。定时器在拿走函数时,只是单纯的拿走了函数的地址,而没有同时拿走.前的对象lilei。3秒后执行函数时,是直接用函数的地址加()调用的函数。早就不知道函数的所有者是谁了。仅相当于匿名函数自调。匿名函数自调中的this->window,而window.sname当然返回undefined。

第四十五题
匿名函数和回调函数有什么差别和关系?
答: 回调函数不一定是匿名函数,匿名函数也不一定是回调函数。
只有当回调函数只使用一次时,才会定义为匿名函数。如果回调函数可能反复使用,也要定义为有名称的函数。
比如: setTimeout(function(){ … }, 3000)
如果这句话需要反复使用:
不好的做法: 将setTimeout(连同里边的function(){}定义,反复复制多次!
就应该: 只定义一次函数,然后再定时器中用函数名反复引用函数:
function task(){ … }
setTimeout(task,3000)
setTimeout(task,2000)
setTimeout(task,1000)
总结: 是否使用匿名函数,取决于将来这个函数被几处使用。如果只被一处使用,则就用匿名函数。如果多处都需要使用这个函数,则必须起名!
另一方面: 匿名函数也有主动自调的情况,就不属于回调。
总结: 之所以大多数回调函数都是匿名函数,只是因为多数回调函数只在一个位置使用一次!所以,没必要起名。
第四十六题
fromi=fromi||0,按理说,逻辑运算应该返回bool值才对呀?为什么会返回fromi的值或者数字0呢?
答: 逻辑运算有一个特殊的情况,就是,如果逻辑运算前后,都是值时,就不再返回bool值,而是先尝试转bool类型做判断,然后,决定具体返回左边还是右边的值
比如: 1||0, 返回1,而不是true
1&&0 返回0, 而不是false
第四十六题
total>=500&&(total*=0.8),可不可以换成三目?
答: 按语义分支结构分为三种情况:
1. 一件事,满足条件就执行,不满足条件就不执行
if实现: if(条件){ 操作 }
比如: if(total>=500){ total*=0.8 }
可简写为: total>=500&&(total*=0.8)
2. 两件事,根据条件二选一执行
if实现: if(条件){操作1}else{操作2}
比如: if(score>=60){ 输出及格 }else{ 输出不及格 }
可用三目简写: score>=60?输出及格:输出不及格
3. 多件事,根据条件多选一执行
if实现: if(条件1){操作1}
else if(条件2){ 操作2 }
…
else { 默认操作 }
比如: if(score>=90){ 输出A }
else if(score>=80){ 输出B }
else if(score>=60){ 输出C }
else { 输出D }
可用三目简写:
score>=90?输出A:
score>=80?输出B:
score>=60?输出C:
输出D
所以,选择何种简写,需要根据其语义来选择。如果只有一件事,选择做与不做,最好使用短路,而不是三目。三目至少要有两件事,二选一执行时,才适用。
第四十七题
//1. concat可以将单个元素和数组,都打散后拼接到一个新的数组中
var arr1=[].concat(1,[2,3],4);
//arr1:[1,2,3,4]
console.log(arr1);
//2. 二维数组降维,应该先将数组打散一次后,再将数字和数组混合的参数交给concat,再打散一次拼接。
var arr=[1,[2,3],4,[5,6]]
//错误: arr=[].concat(arr); //只能打散一次!
//console.log(arr);
//正确: 先让apply打散arr,在将打散后的混合数字和数组的多个值交给concat
//arr=Array.prototype.concat.apply(?,arr);
//问题: apply()第一个参数写谁?
//原理: apply()第一个参数替换concat里的this,等效于替换concat.前的对象。
//因为concat函数的主语只能是数组,所以替换concat.前主语的对象只能是一个数组
//arr=Array.prototype.concat.apply([],arr);
//运行时,等效于: [].concat(1,[2,3],4,[5,6])
//3. 简写: 从孩子抢方法比从爹抢方法简单
//第一个[]为了找到concat方法,而随便创建的空数组
// |
// __|
// ↓
//arr=[].concat.apply([],arr);
// |
// ______________|
// ↓
//第二个[]是创建一个空数组,代替concat.前的主语,作为盛放拼接后的结果数组
//4. 用es6代替apply()
arr=[].concat(...arr);
console.log(arr);//[1,2,3,4,5,6]
这是一篇关于JavaScript面试题的汇总,涵盖了数组处理、数据查找、对象属性、函数定义等多个方面的问题,旨在帮助开发者准备面试和提升技能。题目包括数组去非数字字符并加1、查找两个有序数组的共同元素、寻找数组中和为19的元素组合、统计字符串字符频率、数组操作的规则、深克隆、内置对象的函数列表、自定义函数添加到原型链、自有属性和共有属性的区别、this的四种用法、全局变量的访问、BFC布局、闭包的外层函数抛出内层函数的方式、类数组对象转数组、数组去重等编程挑战。

9727

被折叠的 条评论
为什么被折叠?



