试题与解析-JavaScript(一)

1.JavaScript的全局函数? 全局对象/函数
在这里插入图片描述
坑:setTimeout是window的一个方法。
补充:
在这里插入图片描述
2.下列代码存在几个变量没有被回收?( )

var i = 1;
var i = 2;
var add = function() {
    var i = 0;
    return function()
		{
        	i++;
       	 	console.log(i);
   		}
}();
add();

代码回收规则如下:

  1. 全局变量不会被回收。
  2. 局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。
  3. 只要被另外一个作用域所引用就不会被回收

首先全局变量的i和add不会被回收,函数内部的闭包引用的i也不会被回收。

3.运算符优先级 运算符优先级

4.如何判断一个js对象是否是Array,arr为要判断的对象,其中最准确的方法是?
A.typeof(arr)
B.arr instanceof Array
C.arr.toString=== ‘[object Array]’;
D.Object.prototype.toString.call(arr) === ‘[object Array]’;

一个经典的 ECMAScript 问题是判断一个对象是不是数组。在只有一个网页(因而只有一个全局作用域)的情况下,使用 instanceof 操作符就足矣:

if (value instanceof Array){
 	// 操作数组
}

使用 instanceof 的问题是假定只有一个全局执行上下文。

为解决这个问题,ECMAScript 提供了 Array.isArray()方法。这个方法的目的就是确定一个值是否为数组,而 不用管它是在哪个全局执行上下文中创建的。 来看下面的例子:

if (Array.isArray(value)){
 // 操作数组
} 

在这里插入图片描述
解析:
typeof 操作符:

var arr=new Array("1","2","3","4","5");
alert(typeof(arr)); //object

instanceof 操作符:
JavaScript中instanceof运算符会返回一个 Boolean 值,指出对象是否是特定类的一个实例。 使用方法:result = object instanceof class,还是刚刚的数组,再来一次,嗯,成功的返回 true。

var arrayStr=new Array("1","2","3","4","5");
alert(arrayStr instanceof Array); //true

但事实上在多个frame中穿梭就会产生大问题了。

var iframe = document.createElement('iframe');   
document.body.appendChild(iframe);   
xArray = window.frames[window.frames.length-1].Array;      
var arr = new xArray("1","2","3","4","5");//这个写法IE大哥下是不支持的,FF下才有
alert(arr instanceof Array); // false
alert(arr.constructor === Array); // false

返回结果为两个False,让人大失所望。

Object.prototype.toString:
首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于"[object Array]"的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。

function isArray(obj) {  
  return Object.prototype.toString.call(obj) === '[object Array]';   
}

call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是’[object Array]’,以判断其是否是Array的实例。也许你要问了,为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有toString方法,但是这个方法有可能会被改写而达不到我们的要求,而Object.prototype则是老虎的屁股,很少有人敢去碰它的,所以能一定程度保证其“纯洁性”:)

与前面几个方案不同,这个方法很好的解决了跨frame对象构建的问题,经过测试,各大浏览器兼容性也很好,可以放心使用。一个好消息是,很多框架,比如jQuery、Base2等等,都计划借鉴此方法以实现某些特殊的,比如数组、正则表达式等对象的类型判定,不用我们自己写了。

isArray : function(v){
            return toString.apply(v) === '[object Array]'
}

5.在很多时候,我们需要给网页中的一些元素不停的切换样式,那么要怎样实现给元素删除一个样式的同时,添加另外一个样式( )
在这里插入图片描述
本题考察JQuery中选择器的知识
常用有三种:
①元素选择器:$(“TagName”)

②ID 选择器: $("#ID")

③类选择器:$(".className")

B:错误。选项使用元素选择器,但是 HTML 中没有 us 标签(不考虑自定义标签这种特殊情况)
C:错误。选项使用类选择器,看起来是正确的。但, 若删除类选择器 className 就是 .us,就无法再通过$(’.us’).addClass(‘ClassName’) 给该元素添加样式了
D:错误。add() 方法:把元素添加到已存在的元素组合中。 remove() 方法:移除被选元素,包括所有的文本和子节点。

6.以下哪些代码执行后i的值为10:
在这里插入图片描述
A中,数字类型+对象,会先看对象有没有valueOf()方法,如果有,调用valueOf()方法;如果没有,则看它有没有toString()方法,有就调用。如果没有,则将他们都转换为字符串相加。
在这里插入图片描述
B中,forEach方法按升序为数组中含有效值的每一项执行一次 callback函数,那些未初始化的项将被跳过
new Array(10)创建的数组默认值都是undefined,所以回调函数都会被跳过。
C中,parseInt()专注于将字符串转化为整数。字符串最前面的空格会被 忽略,从第一个非空格字符开始转换。**如果第一个字符不是数值字符、加号或减号,parseInt()立即 返回 NaN。**这意味着空字符串也会返回 NaN(这一点跟 Number()不一样,它返回 0)。假设字符串中的第一个字符是数值字符,parseInt()函数也能识别不同的整数格式(十进制、八 进制、十六进制)。 也接收 第二个参数
D中,形参属于局部变量。

7.下列代码,页面打开后能够弹出1的是?
在这里插入图片描述
D选项,首先,div盒子没有宽高大小,无法点击。
加了宽高之后的效果:

<div onclick="alert(1)" style="width:100px;height: 100px;background-color: pink;"></div>

在这里插入图片描述
再就是,题目说的是页面打开就弹出1,D选项需要先点击。

8.以下哪些语句触发了隐式的类型转换?
在这里插入图片描述
A中,parseInt针对的是字符串值,传递非字符串参数首先会被强制类型转换为字符串。 parseInt(string, radix);

9.如下代码输出的结果是什么:

console.log(1+ "2"+"2");
console.log(1+ +"2"+"2");
console.log("A"- "B"+"2");
console.log("A"- "B"+2);

第一个,就是简单的字符串拼接。“122”
第二个,+"2"前面的一元加操作符+,如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换:布尔值 false 和 true 转换为 0 和 1,字符串根据特殊规则进行解析,对象会调用它们的 valueOf()和/或 toString() 方法以得到可以转换的值。“32”
第三个,“A”- "B"的结果是NaN。对于操作数中有一个操作数为字符串的情况,则将另外一个操作数转化为字符串,再进行字符串拼接。 “NaN2”
第四个,对于两个操作数都是数值的情况,若其中有一个为NaN,则结果返回NaN.“NaN”

10.下面哪些执行结果为true()
在这里插入图片描述
A,B选项:使用new运算符调用函数时,会返回一个对象
如果构造函数没有return语句时,则默认返回原型为Human.prototype的、设置了属性name的对象。
然而就像Class的constructor一样,return语句返回一个对象时,该对象将被作为new操作符的结果返回。
A中,String()作为普通函数使用时,将值转为字符串,不是对象,默认返回是一个空对象原型为匿名函数的prototype
在这里插入图片描述
在这里插入图片描述

空对象转化为字符串类型,就是"[object Object]"
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

B中,String()作为构造函数来用时,返回了一个字符串包装对象。原型为String对象.
在这里插入图片描述
在执行相等操作符时,若其中一个操作符是对象,另一个不是,则调用对象的valueOf()方法取得原始值,再进行相应的比较。

C中,在做相等操作符时,若其中一个为对象,另一个不是,则调用对象的valueOf()方法取得原始值,再进行相应的比较。
在这里插入图片描述
11.关于这段代码正确的结论是:()
在这里插入图片描述

var F=function(){};
Object.prototype.a=function(){};
Function.prototype .b=function(){};
var f=new F();

new操作符创建的f只是对象,所以只能继承于Object.prototype.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
F的原型链上既有Function,又有Object,因此a b属性都能取到。而f对象实例的原型链上只有F和object,取不到Funtion原型上的属性a。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这个过程中,new 构造函数究竟做了什么

  1. 创建一个空对象
  2. 将空对象的原型设置为构造函数的原型
  3. 改变空对象的this指向为构造函数,并执行构造函数,将其中的成员变量更新到空对象中
  4. 返回这个空对象
	var obj  = {};

	obj.__proto__ = F.prototype;

	F.call(obj);

	return obj

在这里插入图片描述

function Person(){}
var friend = new Person();

Person.prototype = {
    constructor : Person,
    name : "kayorl",
    sayName : function () {console.log(this.name);}
}

friend.sayName(); //ERROR

原型修改后, 切断了原来原形与 更改后原形的关系.
在这里插入图片描述
链接:https://www.nowcoder.com/questionTerminal/958d0ae11c9b46e09d7b919467dce9a4
来源:牛客网

f 与其原型
1.1 __proto__是浏览器实现的实例对象访问原型的方式;propertype是构造函数自身的原型属性,也就是构造函数访问原型的方式,所以有

f.__proto__  === F.prototype

1.2 基本上所有的对象最终都是继承于Object(null和undefined没有原型对象),检查一下f的类型:

f instanceof Object  // true ;
f instanceof Function //false ;

由此可见用new操作符创建的f只是对象,所以只能继承于Object.prototype.故而

F.prototype.__proto__==Object.prototype

所以有关于f 的原型链上并没有Function什么事情,所以就不能访问到b
1.3 关于constructor的问题,constructor 属性返回对创建此原型对象的构造函数的引用。

f.__proto__.constructor===F.prototype.constructor   //都是function类型的匿名函数 (){}
F.prototype.constructor  === F;  //在prototype中的constructor的定义
f.constructor === F   //这里的f.constructor应该是原型中的

2.F与其原型
2.1 F不是由构造函数创建的,F是一个函数Function类型的数据,所以F是从Function对象继承而来的

F.__proto__ === Function.prototype

2.2同时一切引用类型都是对象,对象是若干属性的集合,这里可以使用isPrototypeOf方法检验一下,表明Object和Function都是F的原型

Function.prototype.isPrototypeOf(F)    //true
Object.prototype.isPrototypeOf(F)       //true

所以F最终也是继承于Object

F.__proto__===Object.prototype   //false
F.__proto__ === Function.prototype   //true
F.__proto__.__proto__===Object.prototype   //true

故此题答案选A

在讨论区看到的另外一个例子:

Function.prototype.a = 'a';
Object.prototype.b = 'b';
function Person(){};
var p = new Person();
console.log('p.a: '+ p.a); // p.a: undefined
console.log('p.b: '+ p.b); // p.b: b  问为什么?

Person函数才是Function对象的一个实例,所以通过Person.a可以访问到Function原型里面的属性,但是new Person()返回来的是一个对象,它是Object的一个实例,是没有继承Function的,所以无法访问Function原型里面的属性。但是,由于在js里面所有对象都是Object的实例,所以,Person函数可以访问到Object原型里面的属性。

12.以下代码执行后,array的结果是?

var array=[-1,1,3,4,6,10]; 
array.sort((a,b)=>Math.abs(a-3)-Math.abs(b-3));

将Math.abs(item-3)当作一个整体,组成的数组为[4,2,0,1,3,7],此数组按照升序排序,为[0,1,2,3,4,7],下标对应原数组的输出顺序则为[3,4,1,6,-1,10].

13.符合es6规范的语法有()
在这里插入图片描述
C中,Symbol类型属于ES6中新增的基本数据类型之一,内部没有construtor构造器,不能使用new关键字创建。
最重要的是,Symbol()函数不能与 new 关键字一起作为构造函数使用。这样做是为了避免创建符号包装对象

let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor

如果你确实想使用符号包装对象,可以借用 Object()函数

let mySymbol = Symbol();
let myWrappedSymbol = Object(mySymbol);
console.log(typeof myWrappedSymbol); // "object"

D中,Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象

Object.assign(target, source1, source2,...);

14.以下哪个是错误的
在这里插入图片描述

  1. 创建比一般的 DOM 元素慢了 1-2 个数量级
    iframe 的创建比其它包括 scripts 和 css 的 DOM 元素的创建慢了 1-2 个数量级,使用 iframe 的页面一般不会包含太多 iframe,所以创建 DOM 节点所花费的时间不会占很大的比重。但带来一些其它的问题:onload 事件以及连接池(connection pool)

  2. 阻塞页面加载
    及时触发 window 的 onload 事件是非常重要的。onload 事件触发使浏览器的 “忙” 指示器停止,告诉用户当前网页已经加载完毕。当 onload 事件加载延迟后,它给用户的感觉就是这个网页非常慢。
    window 的 onload 事件需要在所有 iframe 加载完毕后(包含里面的元素)才会触发。在 Safari 和 Chrome 里,通过 JavaScript 动态设置 iframe 的 SRC 可以避免这种阻塞情况

  3. 唯一的连接池
    浏览器只能开少量的连接到 web 服务器。比较老的浏览器,包含 Internet Explorer 6 & 7 和 Firefox 2,只能对一个域名(hostname)同时打开两个连接。这个数量的限制在新版本的浏览器中有所提高。Safari 3+ 和 Opera 9+ 可同时对一个域名打开 4 个连接,Chrome 1+, IE 8 以及 Firefox 3 可以同时打开 6 个
    绝大部分浏览器,主页面和其中的 iframe 是共享这些连接的。这意味着 iframe 在加载资源时可能用光了所有的可用连接,从而阻塞了主页面资源的加载。如果 iframe 中的内容比主页面的内容更重要,这当然是很好的。但通常情况下,iframe 里的内容是没有主页面的内容重要的。这时 iframe 中用光了可用的连接就是不值得的了。一种解决办法是,在主页面上重要的元素加载完毕后,再动态设置 iframe 的 SRC。

  4. 不利于 SEO
    搜索引擎的检索程序无法解读 iframe。另外,iframe 本身不是动态语言,样式和脚本都需要额外导入。综上,iframe 应谨慎使用。

15.下面哪些方法可以用作javascript异步模式的编程?
在这里插入图片描述

  • 回调函数,这是异步编程最基本的方法
  • 事件监听,另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
  • 发布/订阅,上一节的 “事件”,完全可以理解成"信号"。
  • Promise对象,Promise 对象是CommonJS 工作组提出的一种规范,目的是为异步编程提供统一接口。

“同步模式”和“异步模式”:
(1)同步模式:就是后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的

(2)异步模式:完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的

JavaScript中实现异步编程模式的4种方法,回调函数、事件监听、发布/订阅、Promise对象:
(1)回调函数:这是异步编程最基本的方法,优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
例:假定有两个函数f1和f2,后者等待前者的执行结果,如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。

f1();//这是一个耗时的任务
f2();
function f1(callback){
	setTimeout(function () {
		// f1的任务代码
		callback();
	}, 1000);
}
f1(f2);//先执行回调f2

(2)事件监听:任务的执行不取决于代码的顺序,而取决于某个事件是否发生。优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以”去耦合”(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
例:为f1绑定一个事件,当f1发生done事件,就执行f2。

f1.on('done', f2);
function f1(){
	setTimeout(function () {
		// f1的任务代码
		f1.trigger('done');
	}, 1000);
}

(3)发布/订阅:我们假定,存在一个 ”信号中心”,某个任务执行完成,就向信号中心 ”发布”(publish)一个信号,其他任务可以向信号中心 ”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式”(publish-subscribe pattern),又称 ”观察者模式”(observer pattern)
这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

jQuery.subscribe("done", f2);
function f1(){
	setTimeout(function () {
		// f1的任务代码
		jQuery.publish("done");
	}, 1000);
}
jQuery.unsubscribe("done", f2);

(4)Promise对象:是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法允许指定回调函数。回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
例:f1的回调函数f2,f1().then(f2);

f1().then(f2);
function f1(){
	var dfd = $.Deferred();
	setTimeout(function () {
		// f1的任务代码
		dfd.resolve();
	}, 500);
	return dfd.promise; //返回一个promise对象
}
//指定多个回调函数:
f1().then(f2).then(f3);
//指定发生错误时的回调函数:
f1().then(f2).fail(f3);

第一期试题整理完毕,每期15题。下期见~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值