JavaScript高级

1.判断以下程序的输出结果:

var age=100;

function test(){ 

   this.age=50;

   return funtion(){   

              return this.age; 

     }

}

var  m = new test();

alert( m() );

var n=test();

alert( n() );

 

答案:100,50

构造函数一旦返回一个对象,就不再创建新对象

m获得的是function(){ return this.age;}

n=test(), this指向window. 先将全局变量age变为50,

又返回一个函数function(){ return this.age;} 保存变量

n中,调用n时,this指向window.

 

2.判断以下程序的输出结果:

var name ="The Window";

var obj ={   

     name:"My obj",

      getName:function(){   

            return function(){   

                 return this.name;

         }

      }

};

console.log(obj.getName()());

 

答案:The window 

obj.getName()返回的是一个函数对象function(){ return this.name;}

(function(){return this.name;}()) 相当于匿名函数自调,this指向window

 

3.判断以下程序的输出结果:

var length =10;

function fn(){   

    console.log(this.length);

 }

var obj ={ 

   length:5;

   method:function(fn){   

         fn();

         arguments[0]();

    }

}

obj.method(fn,1)

 

答案:10  2

fn()  this指向window,所以输出10

arguments[0]()属于特殊情况,this->arguments,相当于arguments.0(),所以,

this指向arguments。fn也属于arguments的成员,所以length输出的是obj.method()的参数个数,2

 

4.统计一个字符串中出现次数最多的字符是?共出现多少次?

答案:

var  dict={};

var  c="",max=1;

for(var i=0;i<str.length;i++){

    var char =str[i];

    if(dict[chart]===undefined)

           dict[char]=1;

        else {   

           dict[char]+=1;

           if(dict[char]>max){

                max=dict[char];

                c=char;

        }

     }

}

console.log(c,max);

提前创建一个空对象,用于保存每个字母出现的次数。

提前创建变量,准备保存出现次数最多的字符和出现的次数.

然后,遍历字符串中的每个字母,每遍历一个字母就判断结果

对象中是否包含以当前字母为属性名的属性。如果不包含以

当前字母为属性名的属性,说明是首次遇见该字母,就向结

果对象中强行添加以该字母为属性名的属性,值暂时为1。如

果结果对象中已经包含以当前字母为属性名的属性,说明不是

第一次碰见该字母。则取出该字母名属性对应的次数+1。只要

当前字母出现的次数>之前变量中记录的最大次数,就用当前字

母和出现次数,取而代之。

 

5.判断以下程序的输出结果:

for(var i=0;i<5;i++){   

    setTimeout(function(){   

        console.log(i);

     },0)

}

console.log(i);

 

答案:5 5 5 5 5

函数定义时,函数内容是不执行的,所以i还是i,不会变成0,1,2,3,4

定时器中的回调函数只能在主程序执行完才能开始执行

当主程序执行完,循环变量i,已经被改为5了.

 

6.判断以下程序的输出结果:

window.color ="red";

let  color="green";

let   obj={   

    color:"blue"

};

let  sayColor=()=>{

   return this.color;

}

console.log(sayColor.apply(obj));

let  a=10;

console.log(window.a);

答案:  red  undefined

let 相当于匿名函数自调,所以,let 声明的变量,不会自动加入到window.

箭头函数内外this通用,所以apply也无法替换sayColor函数内的this,

所以this指向window,所以输出red.

 

7.判断以下程序的输出结果:

var c=1;

function c(c){

   console.log(c);

   var c=3;

}

c(2);

答案:报错:TypeError:c 不是一个函数

function c(c){} 整体被声明提前,后又被c=1代替.所以,

c最后不是一个函数,而是数字1

 

8.判断以下程序的输出结果:

function change(){   

   alert(typeof  fn)

   function  fn(){ alert('hello') }

    var fn;

}

change();

 

答案:function

function fn(){ ...  }被整体声明提前了

var  fn发现已经有fn变量了,就不再重复创建,所以,

var  fn 没作用.

 

9.判断以下程序的输出结果:

a=3;

a.prop=4;

alert(a+a.prop);

答案:NaN

a.prop=4;等效于new Number(a).prop =4,但是new Number(a),

使用后自动释放,4也不存在了.

再次使用a.prop,又等效于新的new Number(a),所以没有prop属性,

值为undefined.

数字+undefined,undefined隐式转换为数字NaN,导致计算结果为NaN

 

10.判断以下程序的输出结果:

var  o={   

    a=10,

    b:{   

       a:12,

       fn:function(){   

             var a=13;

             console.log(this.a);

        }

     }

}

o.b.fn();

答案:12 this指.前的o.b对象,所以a为12

 

11.判断以下程序的输出结果:

var  obj1={   

    name:'obj1',

     fn:function(){   

          document.write(this.name);

     }

 };

var     obj2 ={ name:'obj2' };

var     obj3 ={ name:'obj3' };

obj1.fn();

var  newFn =obj1.fn;

newFn();

newFn.call(obj2);

obj3.fn=newFn;

obj3.fn();

 

答案: obj1 空字符串 obj2 obj3

this指.前的obj1

因为newFn调用时,前没有. ,所以this->window,

call是强行替换newFn中的this为obj2

this指 .前的obj3

 

12.一个数组par中存放有多个人员的信息,

每个人员的信息由年龄age和姓名name组成,如{age:2,name:'xx'}.

请写一段JS程序,对这个数组按年龄从小到大进行排序.

答案:function parSort(arr,propName){   

        arr.sort(function(a,b){

               return a[propName]-b[propName];

   });

}

parSort(arr,"age");

 

1)数组的sort函数的参数,是一个比较器函数。比较器函数

的形参a和b,指当前要排序的数组中的任意两个作比较的元素。

如果要作比较的a和b两个元素时简单的数字类型,则a直接和b相减,

就可比较两数大小。但是,如果a和b都是对象类型的元素。要比较

两个对象中某个属性的值的大小,就必须用a.属性-b.属性。如果属性

名是灵活的,来自于变量,则必须用a[属性名变量]-b[属性名变量],

就可比出两个对象的某个属性值的大小.

2)最后,数组是引用类型的对象,在函数内修改数组,等效于修改原数组。

所以不用返回值。

 

13.有字符串var =' abc345efgabcab';请写出3条JS语句分别实现如下

3个功能:

1)去掉字符串中的a 、b、c字符,形成结果:'345efg'

2)将字符串中的数字用中括号括起来,形成结果:'abc[345]efgabcab'

3)将字符串中的每个数字的值分别乘以2,形成结果:'abc6810efgabcab'

 

答案:

1)str.replace(/([a-c])/g,'');

2)str.replace(/(\d+)/g,'[$1]');

3)str.replace(/(\d)/g,function(num){ return num*2 });

 

1)将字符串中的a,b,c三个字符都替换为空字符串

2)找到字符串中多个连续的数字,分为一组,然后将这一组的内容,替换为用[ ]包裹。$1,

可获得关键词第一个()包裹的内容.

3)找到字符串中的每个数字,*2后,再放回原位置.

 

14.判断以下程序的输出结果:

var  a=10;

var  obj={   

    a:20,

    intr:function(){   

          var a=30;

          console.log(this.a);

    }

 }

 

obj.intr();

var intr=obj.intr;

intr();

答案:20 10 

obj.intr(),this指.前的obj,所以输出20

intr(),this指window,所以输出10

 

15.判断以下程序的输出结果:

function fun(){   

   for(var i=0;arr=[];i<3;i++){   

       arr[i]=function(){   

             console.log(i);

         }

   }

       return arr;

}  

var funs=fun();

funs[0]();

funs[1]();

funs[2]();

答案:3 3 3

 

16.介绍JavaScript的原型,原型链?有什么特点?

答案:

原型:

-   JavaScript的所有对象中都包含了一个[proto]内部属性,这个属性所对应的就是该

对象的原型.

-  JavaScript的函数对象,除了原型[proto]之外,还预置了prototype属性

-  当函数对象作为构造函数创建实例时,该prototype属性值将被作为实例对象的原型[proto].

 

原型链:

-  当一个对象调用的属性/方法自身不存在时,就会去自己[proto]关联的前辈prototype对象上去找

-  如果没找到,就会去该prototype原型[proto]关联的前辈prototype去找。依次类推,直到找到属性/

方法或undefined为止。从而形成了所谓的"原型链"

 

原型特点:

-JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变。

 

17.谈谈JavaScript垃圾回收方法

答案:标记清除(mark and sweep),

- 这是JavaSript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,

垃圾回收器将其标记为"进入环境",当变量离开环境的时候(函数执行结束)将其标记为"离开环境"

- 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境

变量中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了.

 

 

引用计数(reference counting)

 

-   在低版本 IE 中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加 1,如果该变量的值变成了另外一个,则这个值得引用次数减 1,当这个值的引用次数变为 0 的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运

行的时候清理掉引用次数为 0 的值占用的空间

 

 

18.说说严格模式的限制?

答案:严格模式主要有以下限制:

-  变量必须声明后再使用

-  函数的参数不能有同名的属性,否则报错

-  不能使用width语句

-  不能对只读属性赋值,否则报错

-  不能使用前缀0 表示八进制数,否则报错

-  不能删除变量 delete prop,会报错,只能删除属性delete global[prop]

-  eval 不会再它的外层作用域引入变量

-  eval 和arguments不能被重新赋值

-  arguments不会自动反映函数参数的变化

-  不能使用arguments.callee

-  不能使用arguments.caller

-   禁止this指向全局对象

-   不能使用fn.caller 和 fn.arguments获取函数调用的堆栈

-   增加了保留字(比如protected、static 和interface)

 

19。使用正则表达式验证邮箱格式

答案:

var  reg =/^(\w)+(\.\w+)*@(\w)+(\.\w{2,3}){1,3}$/;

var email="example@qq.com";

console.log(email);//true

 

20.使用typeof  bar ==="object" 来确定bar是否是一个对象时有什么潜在的缺陷?

这个陷阱如何避免?

答案:尽管typeof  bar ==="object"是检查bar是否是对象的可靠方法,

但JavaScript中令人惊讶的问题null也被认为是一个对象!

因此,对于大多数开发人员来说,下面的代码会将true(而不是false)打印到控制台:

 

var  bar  = null;

console.log(typeof bar === "object");  ///  logs true

 

只要知道这一点,就可以通过检查bar是否为空来轻松避免该问题:

 

console.log((bar !== null) && (typeof bar === "object")); // logs false

为了让我们的答案更加的完整,还有两件事值得注意: 首先,如果bar是一个函数,上面的解决方案将返回false。在大多数情况下,这是所期望的行为,但是在您希望函数返回true的情况下,您可以将上述解决方案修改为:

 

console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function")));

其次,如果bar是数组,则上述解决方案将返回true(例如,如果var bar = [];)。在大多数情况下,这是所希望的行为,因为数组确实是对象,但是在您想要对数组也是false的情况下,可以将上述解决方案修改为:

 

console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));

但是,还有一个替代方法对空值,数组和函数返回false,但对于对象则为true:

console.log((bar !== null) && (bar.constructor === Object));

或者,如果您使用jQuery:

console.log((bar !== null) && (typeof bar === "object") && (! $.isArray(bar)));

ES5使得数组的情况非常简单,包括它自己的空检查:

console.log(Array.isArray(bar));

 

20.以下代码的输出是什么?解释你的答案

var  a={  },

       b={key:'b'},

       c={key:'c'};

a[b] =123;

a[c]  =456;

 

console.log(a[b]);

答案:  456

原因如下:设置对象属性时,JavaScript会隐式地将参数串联起来。

在这种情况下,由于b和c都是对象,他们都将转换为"[objet  Object]"。

因此,a[b]和a[c]都等价于["[objet Object]"],并且可以互换使用。因此,

设置或引用[c]与设置或引用[b]完全相同。

 

posted @ 2020-03-08 22:02  平凡人的普通修仙之路  阅读(350)  评论(0编辑  收藏  举报