获取页面元素位置与宽高?
element.clientWidth = content + padding
element.clientHeight = content + padding
element.getBoundingClientRect()返回值情况
left:包围盒左边 border 以外的边缘距页面左边的距离
right:包围盒右边 border 以外的边缘距页面左边的距离
top:包围盒上边 border 以外的边缘距页面顶部的距离
bottom:包围盒下边 border 以外的便于距页面顶部的距离
width: content + padding + border
height: content + padding + border
注意,设置外边距时外边距合并的情况
requestAnimationFrame原理?是同步还是异步?
异步,传入的函数在重绘之前调用
开始之前要介绍两个概念:
· 页面可见
当页面被最小化或者被切换成后台标签页时,页面为不可见,浏览器会触发一个 visibilitychange事件,并设置document.hidden属性为true;切换到显示状态时,页面为可见,也同样触发一个 visibilitychange事件,设置document.hidden属性为false。
· 动画帧请求回调函数列表
每个Document都有一个动画帧请求回调函数列表,该列表可以看成是由< handle, callback>元组组成的集合。其中handle是一个整数,唯一地标识了元组在列表中的位置;callback回掉函数,形参为一个时间值的函数(该时间值为动画函数每次开始执行距离第一次执行的毫秒数)。
正餐开始:
写法:Handle=requestanimatonframerequest(函数名);
1).传入一个函数名,自然就是要一直跑啊跑的动画函数了;
2).这个handle返回值可是很重要的,他接着的可是动画函数的灵魂!
该值为浏览器定义的、大于0的整数,唯一标识了该回调函数在列表中位置。
简单点的浏览器执行过程:
看过不少网上写的原理,完整点的要看很久才看明白,今天就给看官们更新个新手简化版本(买手抓饼版本): requestAnimationFrame方法,总结起来,每次调用这个方法时会简单的发生两件事(浏览器处理过程)如下:
1.首先要判断document.hidden属性是否为true,就是浏览器开着才会执行。就像是手抓饼店开着才能去抓。
2.浏览器会清空上一轮的动画函数,这个怎么理解呢?就是说Handle=requestanimatonframerequest(函数名);这一句话调用一次后就被浏览器吃掉了。恩,挺对的,手抓饼吃一次就没了,再想吃要再去买。
3.这个方法返回的handle值会和动画函数,以这样的方式:< handle, callback> 进入到——动画帧请求回调函数列;
4.浏览器会遍历动画帧请求回调函数列表,根据handel的值大小,依次去执行相应的动画函数;(这里还有个小前提,马上将到).这个过程就像是排队买手抓饼(我们学校的手抓饼阿姨会先给排队的人每人一个袋子,先拿到袋子的先拿饼)
所以,正确的requestanimatonframerequest其实应该是不断的递归。
如下:
function animate(time) {
//这里写的语句会不断重复
console.log(“买手抓饼”);
id = window.requestAnimationFrame(animate);
}
animate();
补充删掉动画函数的操作:
每天都控制不住去买手抓饼怎么办,答案是:钱用完了就不去了。
同样的,来看上文提到的小前提:
每个回调函数都有一个布尔标识cancelled,该标识初始值为false
浏览器在执行“采样所有动画”的任务时会遍历动画帧请求回调函数列表,判断每个元组的callback的cancelled,如果为false,则执行callback,此时才能看到动画效果啦~
(canaelled=你Y的是不是没钱,false=不是的不是的)—》诺,饼给你!
(非常吐槽,为什么要这么虐心,非要cancel+false, 歪果仁很喜欢负负得正啊)
用法:cancelAnimationFrame(要删除的handle);
最后一个小问题,既然传入的参数并不是控制时间间隔的,那么怎么做到像setInterval一样的效果呢? 用时间去判断吧
vartimeOne=Date.now(); //起始时间1
function animate(time) {
console.log(time); //这个time 是每次进入执行动画经过的毫秒数
var timeTwo = Date.now(); //起始时间1
if (timeTwo - timeOne >=1000) { //差值就是中间暂停的时间啦(消化手抓饼)
me.innerHTML = ‘我是’ + number + ‘只小青龙’;
number++;
timeOne = timeTwo;
}
id = requestAnimationFrame(animate);
}
animate();
js事件机制?点击屏幕上一个按钮,事件是如何传播的?
捕获 冒泡
下面代码输出结果?为什么?
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
复制代码
下面代码输出结果?为什么?
const person = {
namea: ‘menglinghua’,
say: function (){
return function (){
console.log(this.namea);
};
}
};
person.say()(); // undefined
复制代码
const person = {
namea: ‘menglinghua’,
say: function (){
return () => {
console.log(this.namea);
};
}
};
person.say()(); // menglinghua
复制代码
下面代码输出结果?为什么?
setTimeout(() => console.log(‘a’), 0);
var p = new Promise((resolve) => {
console.log(‘b’);
resolve();
});
p.then(() => console.log(‘c’));
p.then(() => console.log(‘d’));
console.log(‘e’);
// 结果:b e c d a
// 任务队列优先级:promise.Trick()>promise的回调>setTimeout>setImmediate
复制代码
async function async1() {
console.log(“a”);
await async2(); //执行这一句后,await会让出当前线程,将后面的代码加到任务队列中,然后继续执行函数后面的同步代码
console.log(“b”);
}
async function async2() {
console.log( ‘c’);
}
console.log(“d”);
setTimeout(function () {
console.log(“e”);
},0);
async1();
new Promise(function (resolve) {
console.log(“f”);
resolve();
}).then(function () {
console.log(“g”);
});
console.log(‘h’);
// 谁知道为啥结果不一样?????????????
// 直接在控制台中运行结果: d a c f h g b e
// 在页面的script标签中运行结果:d a c f h b g e
复制代码
js bind 实现机制?手写一个 bind 方法?
// 代码来自书籍 《javaScript模式》
if (typeof Function.prototype.bind === “undefined”){
Function.prototype.bind = function (thisArgs){
var fn = this,
slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function (){
return fn.apply(thisArgs, args.concat(slice.call(arguments)));
}
}
}
复制代码
实现 vue 中的on,emit,off,once,手写代码。
// 参照 vue 源码实现
var EventEmiter = function (){
this._events = {};
};
EventEmiter.prototype.on = function (event, cb){
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.on(event[i], cb);
}
} else {
(this._events[event] || (this._events[event] = [])).push(cb);
}
return this;
};
EventEmiter.prototype.once = function (event, cb){
function on () {
this.off(event, cb);
cb.apply(this, arguments);
}
on.fn = cb;
this.on(event, on);
return this;
};
EventEmiter.prototype.off = function (event, cb){
if (!arguments.length){
this._events = Object.create(null);
return this;
}
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.off(event[i],cb);
}
return this;
}
if (!cb){
this._events[event] = null;
return this;
}
if (cb){
let cbs = this._events[event];
let i = cbs.length;
while(i—){
if (cb === cbs[i] || cb === cbs[i].fn){
cbs.splice(i, 1);
break;
}
}
return this;
}
};
EventEmiter.prototype.emit = function (event){
let cbs = this._events[event];
let args = Array.prototype.slice.call(arguments, 1);
if (cbs){
for (let i = 0, l = cbs.length; i < l; i++){
cbs[i].apply(this,args);
}
}
};
用 js 实现双链表,手写代码?
vue 的双向绑定机制?详细介绍。
哪些操作会引起浏览器重绘和重排?
postion:absolute; left:100px;会不会引起?
translateX:100px;会不会引起?
getBoundingClientRect会不会引起?
getClientWidth、getClientHeight会不会引起?
页面性能监测?
从基础到进阶,200道JavaScript题目
我在我的 Instagram 上每天都会发布 JavaScript 的多选问题,并且同时也会在这个仓库中发布。
1. 输出是什么?
function sayHi() {`console.log(name)<br /> console.log(age)<br /> var name = 'Lydia'``<br /> let age = 21``<br />}<br /> <br />sayHi()<br />复制代码<br />A:Lydia和undefined<br />B:Lydia和ReferenceError<br />C:ReferenceError和21<br />D:undefined和ReferenceError<br />答案: D<br />在函数内部,我们首先通过var关键字声明了name变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是undefined。因为当我们打印name变量时还没有执行到定义变量的位置,因此变量的值保持为undefined。<br />通过let和const关键字声明的变量也会提升,但是和var不同,它们不会被初始化。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个ReferenceError错误。<br />2. 输出是什么?<br />for (var i = 0; i < 3; i++) {<br /> setTimeout(() => console.log(i), 1)<br />}<br /> <br />for (let i = 0; i < 3; i++) {<br /> setTimeout(() => console.log(i), 1)<br />}<br />复制代码<br />A:0 1 2和0 1 2<br />B:0 1 2和3 3 3<br />C:3 3 3和0 1 2<br />答案 <br />答案: C<br />由于 JavaScript 的事件循环,setTimeout回调会在_遍历结束后_才执行。因为在第一个遍历中遍历i是通过var关键字声明的,所以这个值是全局作用域下的。在遍历过程中,我们通过一元操作符++来每次递增i的值。当setTimeout回调执行的时候,i的值等于 3。<br />在第二个遍历中,遍历i是通过let关键字声明的:通过let和const关键字声明的变量是拥有块级作用域(指的是任何在 {} 中的内容)。在每次的遍历过程中,i都有一个新值,并且每个值都在循环内的作用域中。<br />3. 输出是什么?<br />const shape = {<br /> radius: 10,<br /> diameter() {<br /> return this.radius 2``<br /> },<br /> perimeter: () => 2 Math.PI * this.radius<br />}<br /> <br />shape.diameter()<br />shape.perimeter()<br />复制代码<br />A:20and62.83185307179586<br />B:20andNaN<br />C:20and63<br />D:NaNand63<br />答案 <br />答案: B<br />注意diameter的值是一个常规函数,但是perimeter的值是一个箭头函数。<br />对于箭头函数,this关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用perimeter时,this不是指向shape对象,而是它的周围作用域(在例子中是window)。<br />在window中没有radius这个属性,因此返回undefined。<br />4. 输出是什么?<br />+true;<br />!"Lydia";<br />复制代码<br />A:1andfalse<br />B:falseandNaN<br />C:falseandfalse<br />答案 <br />答案: A<br />一元操作符加号尝试将 bool 转为 number。true转换为 number 的话为1,false为0。<br />字符串‘Lydia’是一个真值,真值取反那么就返回false。<br />5. 哪一个是无效的?<br />const bird = {<br /> size: 'small'``<br />}<br /> <br />const mouse = {<br /> name: 'Mickey',<br /> small: true``<br />}<br />复制代码<br />A:mouse.bird.size<br />B:mouse[bird.size]<br />C:mouse[bird[“size”]]<br />D: All of them are valid<br />答案 <br />答案: A<br />在 JavaScript 中,所有对象的 keys 都是字符串(除非对象是 Symbol)。尽管我们可能不会定义它们为字符串,但它们在底层总会被转换为字符串。<br />当我们使用括号语法时([]),JavaScript会解释(或者 unboxes)语句。它首先看到第一个开始括号[并继续前进直到找到结束括号]。只有这样,它才会计算语句的值。<br />mouse[bird.size]:首先计算bird.size,这会得到small。mouse[“small”]返回true。<br />然后使用点语法的话,上面这一切都不会发生。mouse没有bird这个 key,这也就意味着mouse.bird是undefined。然后当我们使用点语法mouse.bird.size时,因为mouse.bird是undefined,这也就变成了undefined.size。这个行为是无效的,并且会抛出一个错误类似Cannot read property “size” of undefined。<br />6. 输出是什么?<br />let c = { greeting: 'Hey!' }<br />let d<br /> <br />d = c<br />c.greeting = 'Hello'``<br />console.log(d.greeting)<br />复制代码<br />A:Hello<br />B:undefined<br />C:ReferenceError<br />D:TypeError<br />答案 <br />答案: A<br />在 JavaScript 中,当设置两个对象彼此相等时,它们会通过_引用_进行交互。<br />首先,变量c的值是一个对象。接下来,我们给d分配了一个和c` 对象相同的引用。
因此当我们改变其中一个对象时,其实是改变了所有的对象。
7. 输出是什么?
leta =3<br />let` b = `new` `Number`(`3`)`<br />let` c = `3`<br />console.log(a == b)<br />console.log(a === b)<br />console.log(b === c)<br />复制代码<br />A:truefalse` `true`<br />B: `falsefalse`true
C: true``false false
D: false``true true
答案
答案: Cnew Number() 是一个内建的函数构造器。虽然它看着像是一个 number,但它实际上并不是一个真实的 number:它有一堆额外的功能并且它是一个对象。
当我们使用 == 操作符时,它只会检查两者是否拥有相同的值。因为它们的值都是 3,因此返回 true。
然后,当我们使用 === 操作符时,两者的值以及类型都应该是相同的。new Number() 是一个对象而不是 number,因此返回 false。
8. 输出是什么?
class Chameleon {`staticcolorChange(newColor) {<br /> this.newColor = newColor<br /> return this.newColor<br /> }<br /> <br /> constructor({ newColor = 'green' } = {}) {<br /> this.newColor = newColor<br /> }<br />}<br /> <br />const freddie = new Chameleon({ newColor: 'purple' })<br />freddie.colorChange('orange')<br />复制代码<br />A:orange<br />B:purple<br />C:green<br />D:TypeError<br />答案 <br />答案: D<br />colorChange是一个静态方法。静态方法被设计为只能被创建它们的构造器使用(也就是Chameleon),并且不能传递给实例。因为freddie是一个实例,静态方法不能被实例使用,因此抛出了TypeError错误。<br />9. 输出是什么?<br />let greeting<br />greetign = {} // Typo!``<br />console.log(greetign)<br />复制代码<br />A:{}<br />B:ReferenceError: greetign is not defined<br />C:undefined<br />答案 <br />答案: A<br />代码打印出了一个对象,这是因为我们在全局对象上创建了一个空对象!当我们将greeting写错成greetign时,JS 解释器实际在上浏览器中将它视为global.greetign = {}(或者window.greetign = {})。<br />为了避免这个为题,我们可以使用“use strict”。这能确保当你声明变量时必须赋值。
10. 当我们这么做时,会发生什么?
function bark() {`console.log('Woof!')<br />}<br /> <br />bark.animal = 'dog'``<br />复制代码<br />A: 正常运行!<br />B:SyntaxError.你不能通过这种方式给函数增加属性。<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: A<br />这在 JavaScript 中是可以的,因为函数是对象!(除了基本类型之外其他都是对象)<br />函数是一个特殊的对象。你写的这个代码其实不是一个实际的函数。函数是一个拥有属性的对象,并且属性也可被调用。<br />11. 输出是什么?<br />function Person(firstName, lastName){<br /> this.firstName = firstName;<br /> this.lastName = lastName;<br />}<br /> <br />const member = new Person("Lydia", "Hallie");<br />Person.getFullName = function (){<br /> return ${this.firstName} ${this.lastName};<br />}<br /> <br />console.log(member.getFullName());<br />复制代码<br />A:TypeError<br />B:SyntaxError<br />C:Lydia Hallie<br />D:undefinedundefined`<br />答案 <br />答案: A<br />你不能像常规对象那样,给构造函数添加属性。如果你想一次性给所有实例添加特性,你应该使用原型。因此本例中,使用如下方式:<br />`Person.prototype.getFullName = `function () `{`<br />` `return` ${this.firstName} ${this.lastName}`;}
复制代码
这才会使 member.getFullName() 起作用。为什么这么做有益的?假设我们将这个方法添加到构造函数本身里。也许不是每个 Person 实例都需要这个方法。这将浪费大量内存空间,因为它们仍然具有该属性,这将占用每个实例的内存空间。相反,如果我们只将它添加到原型中,那么它只存在于内存中的一个位置,但是所有实例都可以访问它!
12. 输出是什么?
function Person(firstName, lastName) {`this.firstName = firstName<br /> this.lastName = lastName<br />}<br /> <br />const lydia = new Person('Lydia', 'Hallie')<br />const sarah = Person('Sarah', 'Smith')<br /> <br />console.log(lydia)<br />console.log(sarah)<br />复制代码<br />A:Person {firstName: “Lydia”, lastName: “Hallie”}andundefined<br />B:Person {firstName: “Lydia”, lastName: “Hallie”}andPerson {firstName: “Sarah”, lastName: “Smith”}<br />C:Person {firstName: “Lydia”, lastName: “Hallie”}and{}<br />D:Person {firstName: “Lydia”, lastName: “Hallie”}andReferenceError<br />答案 <br />答案: A<br />对于sarah,我们没有使用new关键字。当使用new时,this引用我们创建的空对象。当未使用new时,this引用的是**全局对象**(global object)。<br />我们说this.firstName等于“Sarah”,并且this.lastName等于“Smith”。实际上我们做的是,定义了global.firstName = ‘Sarah’和global.lastName = ‘Smith’。而sarah本身是undefined`。
13. 事件传播的三个阶段是什么?
A: Target > Capturing > Bubbling
B: Bubbling > Target > Capturing
C: Target > Bubbling > Capturing
D: Capturing > Target > Bubbling
答案
答案: D
在捕获(capturing)阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标(target)元素后,冒泡(bubbling)才开始。
- 所有对象都有原型。
A: true
B: false
答案
答案: B
除了基本对象(base object),所有对象都有原型。基本对象可以访问一些方法和属性,比如.toString。这就是为什么你可以使用内置的 JavaScript 方法!所有这些方法在原型上都是可用的。虽然 JavaScript不能直接在对象上找到这些方法,但 JavaScript 会沿着原型链找到它们,以便于你使用。
15. 输出是什么?
function sum(a, b){`returna + b<br />}<br /><br />sum(1,'2')<br />复制代码<br />A:NaN<br />B:TypeError<br />C:“12”<br />D:3<br />答案 <br />答案: C<br />JavaScript 是一种**动态类型语言**:我们不指定某些变量的类型。值可以在你不知道的情况下自动转换成另一种类型,这种类型称为**隐式类型转换**(implicit type coercion)。**Coercion** 是指将一种类型转换为另一种类型。<br />在本例中,JavaScript 将数字1转换为字符串,以便函数有意义并返回一个值。在数字类型(1)和字符串类型(‘2’)相加时,该数字被视为字符串。我们可以连接字符串,比如“Hello” + “World”,这里发生的是“1” + “2”,它返回“12”。<br />16. 输出是什么?<br />letnumber =0``<br />console.log(number++)<br />console.log(++number)<br />console.log(number)<br />复制代码<br />A:11` `2`<br />B: `12`2
C:0``22
D:0``12
答案
答案: C
一元后自增运算符++:
返回值(返回0)
值自增(number 现在是1)
一元前自增运算符++:
值自增(number 现在是2)
返回值(返回2)
结果是0 2 2.
17. 输出是什么?
function getPersonInfo(one, two, three){`console.log(one)<br />console.log(two)<br />console.log(three)<br />}<br /><br />constperson ='Lydia'``<br />constage =21``<br /><br />getPersonInfo${person} is ${age} years old```<br />复制代码<br />A: `"Lydia"21`["", " is ", " years old"]
B:["", " is ", " years old"]"Lydia"21
C:"Lydia"``["", " is ", " years old"]21
答案
答案: B
如果使用标记模板字面量,第一个参数的值总是包含字符串的数组。其余的参数获取的是传递的表达式的值!
18. 输出是什么?
function checkAge(data){`if(data === {age:18}) {<br />console.log('You are an adult!')<br />}elseif(data == {age:18}) {<br />console.log('You are still an adult.')<br />}else{<br />console.log(Hmm.. You don't have an age I guess)<br />}<br />}<br /><br />checkAge({age:18})<br />复制代码<br />A:You are an adult!<br />B:You are still an adult.<br />C:Hmm.. You don’t have an age I guess<br />答案 <br />答案: C<br />在测试相等性时,基本类型通过它们的值(value)进行比较,而对象通过它们的引用(reference)进行比较。JavaScript 检查对象是否具有对内存中相同位置的引用。<br />题目中我们正在比较的两个对象不是同一个引用:作为参数传递的对象引用的内存位置,与用于判断相等的对象所引用的内存位置并不同。<br />这也是{ age: 18 } === { age: 18 }和{ age: 18 } == { age: 18 }都返回false的原因。<br />19. 输出是什么?<br />function getAge(...args){<br />console.log(typeofargs)<br />}<br /><br />getAge(21)<br />复制代码<br />A:“number”<br />B:“array”<br />C:“object”<br />D:“NaN”<br />答案 <br />答案: C<br />扩展运算符(…args)会返回实参组成的数组。而数组是对象,因此typeof args返回“object”。<br />20. 输出是什么?<br />function getAge(){<br /> 'use strict'``<br />age =21``<br />console.log(age)<br />}<br /><br />getAge()<br />复制代码<br />A:21<br />B:undefined<br />C:ReferenceError<br />D:TypeError<br />答案 <br />答案: C<br />使用“use strict”,你可以确保不会意外地声明全局变量。我们从来没有声明变量age,因为我们使用“use strict”,它将抛出一个引用错误。如果我们不使用“use strict”,它就会工作,因为属性age会被添加到全局对象中了。<br />21. 输出是什么?<br />constsum =eval('10*10+5')<br />复制代码<br />A:105<br />B:“105”<br />C:TypeError<br />D:“1010+5”<br />答案 <br />答案: A<br />代码以字符串形式传递进来,eval对其求值。如果它是一个表达式,就像本例中那样,它对表达式求值。表达式是10 10 + 5。这将返回数字105。<br />22. cool_secret 可访问多长时间?<br />sessionStorage.setItem('cool_secret',123)<br />复制代码<br />A: 永远,数据不会丢失。<br />B: 当用户关掉标签页时。<br />C: 当用户关掉整个浏览器,而不只是关掉标签页。<br />D: 当用户关闭电脑时。<br />答案 <br />答案: B<br />关闭 **tab 标签页** 后,sessionStorage存储的数据才会删除。<br />如果使用localStorage,那么数据将永远在那里,除非调用了localStorage.clear()。<br />23. 输出是什么?<br />varnum =8``<br />varnum =10``<br /><br />console.log(num)<br />复制代码<br />A:8<br />B:10<br />C:SyntaxError<br />D:ReferenceError<br />答案 <br />答案: B<br />使用var关键字,你可以用相同的名称声明多个变量。然后变量将保存最新的值。<br />你不能使用let或const来实现这一点,因为它们是块作用域的。<br />24. 输出是什么?<br />constobj = {1:'a',2:'b',3:'c'}<br />constset =newSet([1,2,3,4,5])<br /><br />obj.hasOwnProperty('1')<br />obj.hasOwnProperty(1)<br />set.has('1')<br />set.has(1)<br />复制代码<br />A:falsetrue` `false` `true`<br />B: `falsetrue`truetrue
C:true``truefalsetrue
D:true``truetruetrue
答案
答案: C
所有对象的键(不包括 Symbol)在底层都是字符串,即使你自己没有将其作为字符串输入。这就是为什么obj.hasOwnProperty('1')也返回true。
对于集合,它不是这样工作的。在我们的集合中没有'1':set.has('1')返回false。它有数字类型为1,set.has(1)返回true。
25. 输出是什么?
constobj = {a:‘one’,b:‘two’,a:‘three’}
console.log(obj)
复制代码
A:{ a: "one", b: "two" }
B:{ b: "two", a: "three" }
C:{ a: "three", b: "two" }
D:SyntaxError
答案
答案: C
如果你有两个名称相同的键,则键会被替换掉。它仍然位于第一个键出现的位置,但是值是最后出现那个键的值。
26. JavaScript 全局执行上下文为你做了两件事:全局对象和 this 关键字。
A: true
B: false
C: it depends
答案
答案: A
基本执行上下文是全局执行上下文:它是代码中随处可访问的内容。
27. 输出是什么?
for(leti =1; i <5; i++) {`if(i ===3)continue``<br />console.log(i)<br />}<br />复制代码<br />A:12`<br />B: `12`3
C:1``24
D:1``34
答案
答案: C
如果某个条件返回true,则continue语句跳过本次迭代。
28. 输出是什么?
String.prototype.giveLydiaPizza =() =>{`return'Just give Lydia pizza already!'``<br />}<br /><br />constname ='Lydia'``<br /><br />name.giveLydiaPizza()<br />复制代码<br />A:“Just give Lydia pizza already!”<br />B:TypeError: not a function<br />C:SyntaxError<br />D:undefined<br />答案 <br />答案: A<br />String是内置的构造函数,我们可以向它添加属性。我只是在它的原型中添加了一个方法。基本类型字符串被自动转换为字符串对象,由字符串原型函数生成。因此,所有 string(string 对象)都可以访问该方法!<br />29. 输出是什么?<br />consta = {}<br />constb = {key:'b'}<br />constc = {key:'c'}<br /><br />a[b] =123``<br />a[c] =456``<br /><br />console.log(a[b])<br />复制代码<br />A:123<br />B:456<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: B<br />对象的键被自动转换为字符串。我们试图将一个对象b设置为对象a的键,且相应的值为123。<br />然而,当字符串化一个对象时,它会变成“[object Object]”。因此这里说的是,a[“[object Object]”] = 123。然后,我们再一次做了同样的事情,c是另外一个对象,这里也有隐式字符串化,于是,a[“[object Object]”] = 456。<br />然后,我们打印a[b],也就是a[“[object Object]”]。之前刚设置为456,因此返回的是456。<br />30. 输出是什么?<br />constfoo =() =>console.log('First')<br />constbar =() =>setTimeout(() =>console.log('Second'))<br />constbaz =() =>console.log('Third')<br /><br />bar()<br />foo()<br />baz()<br />复制代码<br />A:FirstSecond` `Third`<br />B: `FirstThird`Second
C:Second``FirstThird
D:Second``ThirdFirst
答案
答案: B
我们有一个setTimeout函数,并首先调用它。然而,它是最后打印日志的。
这是因为在浏览器中,我们不仅有运行时引擎,还有一个叫做WebAPI的东西。WebAPI提供了setTimeout函数,也包含其他的,例如 DOM。
将 callback 推送到 WebAPI 后,setTimeout函数本身(但不是回调!)将从栈中弹出。
现在,foo 被调用,打印"First"。
foo 从栈中弹出,baz 被调用. 打印 "Third"。
WebAPI 不能随时向栈内添加内容。相反,它将回调函数推到名为 queue 的地方。
这就是事件循环开始工作的地方。一个事件循环查看栈和任务队列。如果栈是空的,它接受队列上的第一个元素并将其推入栈。
bar 被调用,打印 "Second",然后它被栈弹出。
31. 当点击按钮时,event.target是什么?
<br />` `<div onclick="console.log('second div')">`<button onclick="console.log('button')">``<br /> Click!<br /> </button>``<br /> </div>``<br /></div>``<br />复制代码<br />A: Outerdiv<br />B: Innerdiv<br />C:button<br />D: 一个包含所有嵌套元素的数组。<br />答案 <br />答案: C<br />导致事件的最深嵌套的元素是事件的 target。你可以通过event.stopPropagation来停止冒泡。<br />32. 当您单击该段落时,日志输出是什么?<br /><div onclick="console.log('div')">``<br /> <p onclick="console.log('p')">``<br /> Click here!<br /> </p>``<br /></div>``<br />复制代码<br />A:pdiv`<br />B: `divp<br />C:p<br />D:div<br />答案 <br />答案: A<br />如果我们点击p,我们会看到两个日志:p和div。在事件传播期间,有三个阶段:捕获、目标和冒泡。默认情况下,事件处理程序在冒泡阶段执行(除非将useCapture设置为true)。它从嵌套最深的元素向外传播。<br />33. 输出是什么?<br />const person = { name: 'Lydia' }<br /> <br />function sayHi(age){<br /> console.log(${this.name} is ${age})<br />}<br /> <br />sayHi.call(person,21)<br />sayHi.bind(person,21)<br />复制代码<br />A:undefined is 21`Lydia is 21B:
function``functionC:
Lydia is 21 Lydia is 21D:
Lydia is 21 function答案
答案: D
使用这两种方法,我们都可以传递我们希望
this 关键字引用的对象。但是,.call 是立即执行的。.bind 返回函数的副本,但带有绑定上下文!它不是立即执行的。34. 输出是什么?
function sayHi()
{`return (() => 0)()<br />}<br /> <br />typeof sayHi()<br />复制代码<br />A:“object”<br />B:“number”<br />C:“function”<br />D:“undefined”<br />答案 <br />答案: B<br />sayHi方法返回的是立即执行函数(IIFE)的返回值.此立即执行函数的返回值是0, 类型是number<br />参考:只有7种内置类型:null,undefined,boolean,number,string,object和symbol。function不是一种类型,函数是对象,它的类型是object。<br />35. 下面哪些值是falsy?<br />0``<br />new Number(0)<br />('')<br />(' ')<br />new Boolean(false)<br />undefined``<br />复制代码<br />A:0,‘’,undefined<br />B:0,new Number(0),‘’,new Boolean(false),undefined<br />C:0,‘’,new Boolean(false),undefined<br />D: All of them are falsy<br />答案 <br />答案: A<br />只有 6 种 [falsy](https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy)值:<br />undefined<br />null<br />NaN<br />0<br />‘’(empty string)<br />false<br />Function构造函数, 比如new Number和new Boolean,是 [truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy)。<br />36. 输出是什么?<br />console.log(typeof typeof 1)<br />复制代码<br />A:“number”<br />B:“string”<br />C:“object”<br />D:“undefined”<br />答案 <br />答案: B<br />typeof 1返回“number”。typeof “number”返回“string”。<br />37. 输出是什么?<br />const numbers = [1, 2, 3]<br />numbers[10] = 11``<br />console.log(numbers)<br />复制代码<br />A:[1, 2, 3, 7 x null, 11]<br />B:[1, 2, 3, 11]<br />C:[1, 2, 3, 7 x empty, 11]<br />D:SyntaxError<br />答案 <br />答案: C<br />当你为数组设置超过数组长度的值的时候, JavaScript 会创建名为 "empty slots" 的东西。它们的值实际上是undefined。你会看到以下场景:<br />[1, 2, 3, 7 x empty, 11]<br />这取决于你的运行环境(每个浏览器,以及 node 环境,都有可能不同)<br />38. 输出是什么?<br />(() => {<br /> let x, y<br /> try {<br /> throw new Error()<br /> } catch (x) {<br /> (x = 1), (y = 2)<br /> console.log(x)<br /> }<br /> console.log(x)<br /> console.log(y)<br />})()<br />复制代码<br />A:1undefined` `2`<br />B: `undefinedundefined`undefinedC:
1``1 2D:
1``undefined undefined答案
答案: A
catch 代码块接收参数 x。当我们传递参数时,这与之前定义的变量x 不同 。这个 x 是属于 catch 块级作用域的。然后,我们将块级作用域中的变量赋值为
1,同时也设置了变量 y 的值。现在,我们打印块级作用域中的变量x,值为 1。catch 块之外的变量 x 的值仍为 undefined,y 的值为 2。当我们在 catch 块之外执行console.log(x) 时,返回undefined,y 返回 2。39. JavaScript 中的一切都是?
A: 基本类型与对象
B: 函数与对象
C: 只有对象
D: 数字与对象
答案
答案: A
JavaScript 只有基本类型和对象。
基本类型包括
boolean, null, undefined, bigint, number, string, symbol。40. 输出是什么?
[[0,1], [2,3]].reduce(`(acc, cur) => {<br /> returnacc.concat(cur)<br /> },<br /> [1, 2]<br />)<br />复制代码<br />A:[0, 1, 2, 3, 1, 2]<br />B:[6, 1, 2]<br />C:[1, 2, 0, 1, 2, 3]<br />D:[1, 2, 6]<br />答案 <br />答案: C<br />[1, 2]是初始值。初始值将会作为首次调用时第一个参数acc的值。在第一次执行时,acc的值是[1, 2],cur的值是[0, 1]。合并它们,结果为[1, 2, 0, 1]。 第二次执行,acc的值是[1, 2, 0, 1],cur的值是[2, 3]。合并它们,最终结果为[1, 2, 0, 1, 2, 3]<br />41. 输出是什么?<br />!!null``<br />!!''``<br />!!1``<br />复制代码<br />A:falsetrue` `false`<br />B: `falsefalse`trueC:
false``true trueD:
true``true false答案
答案: B
null 是 falsy。!null 的值是true。 !true 的值是false。"" 是 falsy。!"" 的值是true。 !true 的值是false。1 是 truthy。!1 的值是 false。 !false 的值是true。42.
setInterval方法的返回值是什么?setInterval(() =>`console.log('Hi'), 1000)<br />复制代码<br />A: 一个唯一的id<br />B: 该方法指定的毫秒数<br />C: 传递的函数<br />D:undefined<br />答案 <br />答案: A<br />setInterval返回一个唯一的 id。此 id 可被用于clearInterval函数来取消定时。<br />43. 输出是什么?<br />[…'Lydia']<br />复制代码<br />A:[“L”, “y”, “d”, “i”, “a”]<br />B:[“Lydia”]<br />C:[[], “Lydia”]<br />D:[[“L”, “y”, “d”, “i”, “a”]]<br />答案 <br />答案: A<br />string 类型是可迭代的。扩展运算符将迭代的每个字符映射成一个元素。<br />44. 输出是什么?<br />function* generator(i){<br /> yield i;<br /> yield i 2;<br />}<br /> <br />const gen = generator(10);<br /> <br />console.log(gen.next().value);<br />console.log(gen.next().value);<br />复制代码<br />A:[0, 10], [10, 20]<br />B:20, 20<br />C:10, 20<br />D:0, 10 and 10, 20<br />答案 <br />答案: C<br />一般的函数在执行之后是不能中途停下的。但是,生成器函数却可以中途“停下”,之后可以再从停下的地方继续。当生成器遇到yield关键字的时候,会生成yield后面的值。注意,生成器在这种情况下不 _返回_ (_return_ )值,而是 _生成_ (_yield_)值。<br />首先,我们用10作为参数i来初始化生成器函数。然后使用next()方法一步步执行生成器。第一次执行生成器的时候,i的值为10,遇到第一个yield关键字,它要生成i的值。此时,生成器“暂停”,生成了10。<br />然后,我们再执行next()方法。生成器会从刚才暂停的地方继续,这个时候i还是10。于是我们走到了第二个yield关键字处,这时候需要生成的值是i2,i为10,那么此时生成的值便是20。所以这道题的最终结果是10,20。<br />45. 返回值是什么?<br />const firstPromise = new Promise((res, rej) => {<br /> setTimeout(res, 500, "one");<br />});<br /> <br />const secondPromise = new Promise((res, rej) => {<br /> setTimeout(res, 100, "two");<br />});<br /> <br />Promise.race([firstPromise, secondPromise]).then(res => console.log(res));<br />复制代码<br />A:“one”<br />B:“two”<br />C:“two” “one”<br />D:“one” “two”<br />答案 <br />答案: B<br />当我们向Promise.race方法中传入多个Promise时,会进行 _优先_ 解析。在这个例子中,我们用setTimeout给firstPromise和secondPromise分别设定了500ms和100ms的定时器。这意味着secondPromise会首先解析出字符串two。那么此时res参数即为two,是为输出结果。<br />46. 输出是什么?<br />let person = { name: "Lydia" };<br />const members = [person];<br />person =null;<br /> <br />console.log(members);<br />复制代码<br />A:null<br />B:[null]<br />C:[{}]<br />D:[{ name: “Lydia” }]<br />答案 <br />答案: D<br />首先我们声明了一个拥有name属性的对象person。<br />然后我们又声明了一个变量members. 将首个元素赋值为变量person。 当设置两个对象彼此相等时,它们会通过 _引用_进行交互。但是当你将引用从一个变量分配至另一个变量时,其实只是执行了一个 _复制_ 操作。(注意一点,他们的引用 _并不相同_!)<br />接下来我们让person等于null。<br />我们没有修改数组第一个元素的值,而只是修改了变量person的值,因为元素(复制而来)的引用与person不同。members的第一个元素仍然保持着对原始对象的引用。当我们输出members数组时,第一个元素会将引用的对象打印出来。<br />47. 输出是什么?<br />const person = {<br /> name: "Lydia",<br /> age: 21``<br />};<br /> <br />for (const item in person) {<br /> console.log(item);<br />}<br />复制代码<br />A:{ name: “Lydia” }, { age: 21 }<br />B:“name”, “age”<br />C:“Lydia”, 21<br />D:[“name”, “Lydia”], [“age”, 21]<br />答案 <br />答案: B<br />在for-in循环中,我们可以通过对象的key来进行迭代,也就是这里的name和age。在底层,对象的key都是字符串(如果他们不是Symbol的话)。在每次循环中,我们将item设定为当前遍历到的key.所以一开始,item是name,之后item输出的则是age。<br />48. 输出是什么?<br />console.log(3 + 4 + "5");<br />复制代码<br />A:“345”<br />B:“75”<br />C:12<br />D:“12”<br />答案 <br />答案: B<br />当所有运算符的 _优先级_相同时,计算表达式需要确定运算符的结合顺序,即从右到左还是从左往右。在这个例子中,我们只有一类运算符+,对于加法来说,结合顺序就是从左到右。<br />3 + 4首先计算,得到数字7.<br />由于类型的强制转换,7 + ‘5’的结果是“75”. JavaScript将7转换成了字符串,可以参考问题15.我们可以用+号把两个字符串连接起来。“7” + “5”就得到了“75”.<br />49.num的值是什么?<br />const num = parseInt("7*6", 10);<br />复制代码<br />A:42<br />B:“42”<br />C:7<br />D:NaN<br />答案 <br />答案: C<br />只返回了字符串中第一个字母. 设定了 _进制_ 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……),parseInt检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。<br />就是不合法的数字字符。所以只解析到“7”,并将其解析为十进制的7.num的值即为7.<br />50. 输出是什么?<br />[1, 2, 3].map(num => {<br /> if (typeof num === "number") return;<br /> return num 2;<br />});<br />复制代码<br />A:[]<br />B:[null, null, null]<br />C:[undefined, undefined, undefined]<br />D:[ 3 x empty ]<br />答案 <br />答案: C<br />对数组进行映射的时候,num就是当前循环到的元素. 在这个例子中,所有的映射都是number类型,所以if中的判断typeof num === “number”结果都是true.map函数创建了新数组并且将函数的返回值插入数组。<br />但是,没有任何值返回。当函数没有返回任何值时,即默认返回undefined.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是undefined.<br />51. 输出的是什么?<br />function getInfo(member, year){<br /> member.name = "Lydia";<br /> year = "1998";<br />}<br /> <br />const person = { name: "Sarah" };<br />const birthYear = "1997";<br /> <br />getInfo(person, birthYear);<br /> <br />console.log(person, birthYear);<br />复制代码<br />A:{ name: “Lydia” }, “1997”<br />B:{ name: “Sarah” }, “1998”<br />C:{ name: “Lydia” }, “1998”<br />D:{ name: “Sarah” }, “1997”<br />答案 <br />答案: A<br />普通参数都是 _值_传递的,而对象则不同,是 _引用_传递。所以说,birthYear是值传递,因为他是个字符串而不是对象。当我们对参数进行值传递时,会创建一份该值的_复制_ 。(可以参考问题46)<br />变量birthYear有一个对“1997”的引用,而传入的参数也有一个对“1997”的引用,但二者的引用并不相同。当我们通过给year赋值“1998”来更新year的值的时候我们只是更新了year(的引用)。此时birthYear仍然是“1997”.<br />而person是个对象。参数member引用与之 _相同的_ 对象。当我们修改member所引用对象的属性时,person的相应属性也被修改了,因为他们引用了相同的对象.person的name属性也变成了“Lydia”.<br />52. 输出是什么?<br />function greeting(){<br /> throw "Hello world!";<br />}<br /> <br />function sayHi(){<br /> try {<br /> const data = greeting();<br /> console.log("It worked!", data);<br /> } catch (e) {<br /> console.log("Oh no an error!", e);<br /> }<br />}<br /> <br />sayHi();<br />复制代码<br />A:“It worked! Hello world!”<br />B:“Oh no an error: undefined<br />C:SyntaxError: can only throw Error objects<br />D:“Oh no an error: Hello world!<br />答案 <br />答案: D<br />通过throw语句,我么可以创建自定义错误。 而通过它,我们可以抛出异常。异常可以是一个字符串, 一个 数字, 一个 布尔类型 或者是一个 对象。在本例中,我们的异常是字符串‘Hello world’.<br />通过catch语句,我们可以设定当try语句块中抛出异常后应该做什么处理。在本例中抛出的异常是字符串‘Hello world’.e就是这个字符串,因此被输出。最终结果就是‘Oh an error: Hello world’.<br />53. 输出是什么?<br />function Car(){<br /> this.make = "Lamborghini";<br /> return { make: "Maserati" };<br />}<br /> <br />const myCar = new Car();<br />console.log(myCar.make);<br />复制代码<br />A:“Lamborghini”<br />B:“Maserati”<br />C:ReferenceError<br />D:TypeError<br />答案 <br />答案: B<br />返回属性的时候,属性的值等于 _返回的_ 值,而不是构造函数中设定的值。我们返回了字符串“Maserati”,所以myCar.make等于“Maserati”.<br />54. 输出是什么?<br />(() => {<br /> let x = (y = 10);<br />})();<br /> <br />console.log(typeof x);<br />console.log(typeof y);<br />复制代码<br />A:“undefined”, “number”<br />B:“number”, “number”<br />C:“object”, “number”<br />D:“number”, “undefined”<br />答案 <br />答案: A<br />let x = y = 10;是下面这个表达式的缩写:<br />y = 10;<br />let x = y;<br />复制代码<br />我们设定y等于10时,我们实际上增加了一个属性y给全局对象(浏览器里的window, Nodejs里的global)。在浏览器中,window.y等于10.<br />然后我们声明了变量x等于y,也是10.但变量是使用let声明的,它只作用于 _块级作用域_, 仅在声明它的块中有效;就是案例中的立即调用表达式(IIFE)。使用typeof操作符时, 操作值x没有被定义:因为我们在x声明块的外部,无法调用它。这就意味着x未定义。未分配或是未声明的变量类型为“undefined”.console.log(typeof x)返回“undefined”.<br />而我们创建了全局变量y,并且设定y等于10.这个值在我们的代码各处都访问的到。y已经被定义了,而且有一个“number”类型的值。console.log(typeof y)返回“number”.<br />55. 输出是什么?<br />class Dog{<br /> constructor(name) {<br /> this.name = name;<br /> }<br />}<br /> <br />Dog.prototype.bark = function(){<br /> console.log(Woof I am ${this.name});<br />};<br /> <br />const pet = new Dog("Mara");<br /> <br />pet.bark();<br /> <br />delete Dog.prototype.bark;<br /> <br />pet.bark();<br />复制代码<br />A:“Woof I am Mara”,TypeError<br />B:“Woof I am Mara”,“Woof I am Mara”<br />C:“Woof I am Mara”,undefined<br />D:TypeError,TypeError<br />答案 <br />答案: A<br />我们可以用delete关键字删除对象的属性,对原型也是适用的。删除了原型的属性后,该属性在原型链上就不可用了。在本例中,函数bark在执行了delete Dog.prototype.bark后不可用, 然而后面的代码还在调用它。<br />当我们尝试调用一个不存在的函数时TypeError异常会被抛出。在本例中就是TypeError: pet.bark is not a function,因为pet.bark是undefined.<br />56. 输出是什么?<br />const set = new Set([1, 1, 2, 3, 4]);<br /> <br />console.log(set);<br />复制代码<br />A:[1, 1, 2, 3, 4]<br />B:[1, 2, 3, 4]<br />C:{1, 1, 2, 3, 4}<br />D:{1, 2, 3, 4}<br />答案 <br />答案: D<br />Set对象是独一无二的值的集合:也就是说同一个值在其中仅出现一次。<br />我们传入了数组[1, 1, 2, 3, 4],他有一个重复值1.以为一个集合里不能有两个重复的值,其中一个就被移除了。所以结果是{1, 2, 3, 4}.<br />57. 输出是什么?<br />// counter.js``<br />let counter = 10;<br />export defaultcounter;<br />复制代码<br />// index.js``<br />import myCounter from "./counter";<br /> <br />myCounter += 1;<br /> <br />console.log(myCounter);<br />复制代码<br />A:10<br />B:11<br />C:Error<br />D:NaN<br />答案 <br />答案: C<br />引入的模块是 _只读_的: 你不能修改引入的模块。只有导出他们的模块才能修改其值。<br />当我们给myCounter增加一个值的时候会抛出一个异常:myCounter是只读的,不能被修改。<br />58. 输出是什么?<br />const name = "Lydia";<br />age = 21;<br /> <br />console.log(delete name);<br />console.log(delete age);<br />复制代码<br />A:false,true<br />B:“Lydia”,21<br />C:true,true<br />D:undefined,undefined<br />答案 <br />答案: A<br />delete操作符返回一个布尔值:true指删除成功,否则返回false. 但是通过var,const或let关键字声明的变量无法用delete操作符来删除。<br />name变量由const关键字声明,所以删除不成功:返回false. 而我们设定age等于21时,我们实际上添加了一个名为age的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以delete age返回true.<br />59. 输出是什么?<br />const numbers = [1, 2, 3, 4, 5];<br />const [y] = numbers;<br /> <br />console.log(y);<br />复制代码<br />A:[[1, 2, 3, 4, 5]]<br />B:[1, 2, 3, 4, 5]<br />C:1<br />D:[1]<br />答案 <br />答案: C<br />我们可以通过解构赋值来解析来自对象的数组或属性的值,比如说:<br />[a, b] = [1, 2];<br />a的值现在是1,b的值现在是2.而在题目中,我们是这么做的:<br />[y] = [1, 2, 3, 4, 5];<br />也就是说,y等于数组的第一个值就是数字1.我们输出y, 返回1.<br />60. 输出是什么?<br />const user = { name: "Lydia", age: 21 };<br />const admin = { admin: true, …user };<br /> <br />console.log(admin);<br />复制代码<br />A:{ admin: true, user: { name: “Lydia”, age: 21 } }<br />B:{ admin: true, name: “Lydia”, age: 21 }<br />C:{ admin: true, user: [“Lydia”, 21] }<br />D:{ admin: true }<br />答案 <br />答案: B<br />扩展运算符…为对象的组合提供了可能。你可以复制对象中的键值对,然后把它们加到另一个对象里去。在本例中,我们复制了user对象键值对,然后把它们加入到admin对象中。admin对象就拥有了这些键值对,所以结果为{ admin: true, name: “Lydia”, age: 21 }.<br />61. 输出是什么?<br />const person = { name: "Lydia" };<br /> <br />Object.defineProperty(person, "age", { value: 21 });<br /> <br />console.log(person);<br />console.log(Object.keys(person));<br />复制代码<br />A:{ name: “Lydia”, age: 21 },[“name”, “age”]<br />B:{ name: “Lydia”, age: 21 },[“name”]<br />C:{ name: “Lydia”},[“name”, “age”]<br />D:{ name: “Lydia”},[“age”]<br />答案 <br />答案: B<br />通过defineProperty方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty方法给对象添加了一个属性之后,属性默认为_不可枚举(not enumerable)_.Object.keys方法仅返回对象中 _可枚举(enumerable)_ 的属性,因此只剩下了“name”.<br />用defineProperty方法添加的属性默认不可变。你可以通过writable,configurable和enumerable属性来改变这一行为。这样的话, 相比于自己添加的属性,defineProperty方法添加的属性有了更多的控制权。<br />62. 输出是什么?<br />const settings = {<br /> username: "lydiahallie",<br /> level: 19,<br /> health: 90``<br />};<br /> <br />const data = JSON.stringify(settings, ["level", "health"]);<br />console.log(data);<br />复制代码<br />A:“{“level”:19, “health”:90}”<br />B:“{“username”: “lydiahallie”}”<br />C:“[“level”, “health”]”<br />D:“{“username”: “lydiahallie”, “level”:19, “health”:90}”<br />答案 <br />答案: A<br />JSON.stringify的第二个参数是_替代者(replacer)_. 替代者(replacer)可以是个函数或数组,用以控制哪些值如何被转换为字符串。<br />如果替代者(replacer)是个 _数组_ ,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为“level”和“health”的属性被包括进来,“username”则被排除在外。data就等于“{“level”:19, “health”:90}”.<br />而如果替代者(replacer)是个 _函数_,这个函数将被对象的每个属性都调用一遍。 函数返回的值会成为这个属性的值,最终体现在转化后的JSON字符串中(译者注:Chrome下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出JSON字符串),而如果返回值为undefined,则该属性会被排除在外。<br />63. 输出是什么?<br />let num = 10;<br /> <br />const increaseNumber = () => num++;<br />const increasePassedNumber = number => number++;<br /> <br />const num1 = increaseNumber();<br />const num2 = increasePassedNumber(num1);<br /> <br />console.log(num1);<br />console.log(num2);<br />复制代码<br />A:10,10<br />B:10,11<br />C:11,11<br />D:11,12<br />答案 <br />答案: A<br />一元操作符++_先返回_操作值, _再累加_操作值。num1的值是10, 因为increaseNumber函数首先返回num的值,也就是10,随后再进行num的累加。<br />num2是10因为我们将num1传入increasePassedNumber.number等于10(num1的值。同样道理,++_先返回_ 操作值, _再累加_ 操作值。)number是10,所以num2也是10.<br />64. 输出什么?<br />const value = { number: 10 };<br /> <br />const multiply = (x = { ...value }) => {<br /> console.log(x.number = 2);<br />};<br /> <br />multiply();<br />multiply();<br />multiply(value);<br />multiply(value);<br />复制代码<br />A:20,40,80,160<br />B:20,40,20,40<br />C:20,20,20,40<br />D:NaN,NaN,20,40<br />答案 <br />答案: C<br />在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为“undefined”,那么参数的值将是默认值。上述例子中,我们将value对象进行了解构并传到一个新对象中,因此x的默认值为{number:10}` 。<br />默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用 `multiply` 函数且不传递值,那么每一次`x` 的默认值都为 `{number:10},因此打印出该数字的乘积值为20。<br />第三次调用multiply时,我们传递了一个参数,即对象value。=运算符实际上是x.number = x.number 2的简写,我们修改了x.number的值,并打印出值20。<br />第四次,我们再次传递value对象。x.number之前被修改为20,所以x.number = 2打印为40。<br />65. 输出什么?<br />[1, 2, 3, 4].reduce((x, y) => console.log(x, y));<br />复制代码<br />A:12` and `3` `3`and `6` `4`<br />B: `12and2`3and 3 4C:
1``undefined and 2 undefinedand 3 undefinedand 4 undefinedD:
1``2 and undefined 3 and undefined 4答案
答案: D
reducer 函数接收4个参数:Accumulator (acc) (累计器)
Current Value (cur) (当前值)
Current Index (idx) (当前索引)
Source Array (src) (源数组)
reducer 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。reducer 函数还有一个可选参数initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供initialValue,则将使用数组中的第一个元素。在上述例子,
reduce方法接收的第一个参数(Accumulator)是x, 第二个参数(Current Value)是y。在第一次调用时,累加器
x为1,当前值“y”为2,打印出累加器和当前值:1和2。例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回
undefined。 在下一次调用时,累加器为undefined,当前值为“3”,因此undefined和3被打印出。在第四次调用时,回调函数依然没有返回值。 累加器再次为
undefined ,当前值为“4”。 undefined和4被打印出。66. 使用哪个构造函数可以成功继承
Dog类?class Dog
{`constructor(name) {<br /> this.name = name;<br /> }<br />};<br /> <br />class Labrador extends Dog{<br /> // 1 ``<br /> constructor(name, size) {<br /> this.size = size;<br /> }<br /> // 2``<br /> constructor(name, size) {<br /> super(name);<br /> this.size = size;<br /> }<br /> // 3``<br /> constructor(size) {<br /> super(name);<br /> this.size = size;<br /> }<br /> // 4 ``<br /> constructor(name, size) {<br /> this.name = name;<br /> this.size = size;<br /> }<br /> <br />};<br />复制代码<br />A: 1<br />B: 2<br />C: 3<br />D: 4<br />答案 <br />答案: B<br />在子类中,在调用super之前不能访问到this关键字。 如果这样做,它将抛出一个ReferenceError:1和4将引发一个引用错误。<br />使用super关键字,需要用给定的参数来调用父类的构造函数。 父类的构造函数接收name参数,因此我们需要将name传递给super。<br />Labrador类接收两个参数,name参数是由于它继承了Dog,size作为Labrador类的额外属性,它们都需要传递给Labrador的构造函数,因此使用构造函数2正确完成。<br />67. 输出什么?<br />// index.js``<br />console.log('running index.js');<br />import { sum } from './sum.js';<br />console.log(sum(1, 2));<br /> <br />// sum.js``<br />console.log('running sum.js');<br />export const sum = (a, b) => a + b;<br />复制代码<br />A:running index.js,running sum.js,3<br />B:running sum.js,running index.js,3<br />C:running sum.js,3,running index.js<br />D:running index.js,undefined,running sum.js<br />答案 <br />答案: B<br />import命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。<br />这是CommonJS中require()`和`import`之间的区别。使用`require()`,您可以在运行代码时根据需要加载依赖项。 如果我们使用`require`而不是`import`,`running index.js`,`running sum.js`,`3`会被依次打印。<br />68. 输出什么?<br />console`.log(`Number`(`2`) === `Number`(`2`))`<br />console`.log(`Boolean`(`false`) === `Boolean`(`false`))`<br />console`.log(`Symbol`(`'foo'`) === `Symbol`(`'foo'`))`<br />复制代码<br />A: `true`,`true`, `false`<br />B: `false`,`true`, `false`<br />C: `true`,`false`, `true`<br />D: `true`,`true`, `true`<br />答案 <br />答案: A<br />每个`Symbol`都是完全唯一的。传递给`Symbol`的参数只是给`Symbol`的一个描述。 `Symbol`的值不依赖于传递的参数。 当我们测试相等时,我们创建了两个全新的符号:第一个`Symbol(’foo’),第二个Symbol('foo')`, 这两个值是唯一的,彼此不相等,因此返回`false`。<br />69. 输出什么?<br />const` name = `"Lydia Hallie"console
.log(name.padStart(13))console
.log(name.padStart(2))复制代码
A:
"Lydia Hallie", "Lydia Hallie"B:
" Lydia Hallie", " Lydia Hallie" ("[13x whitespace]Lydia Hallie", "[2x whitespace]Lydia Hallie")C:
" Lydia Hallie", "Lydia Hallie" ("[1x whitespace]Lydia Hallie", "Lydia Hallie")D:
"Lydia Hallie", "Lyd"答案
答案: C
使用
padStart方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串Lydia Hallie的长度为12, 因此name.padStart``(13)在字符串的开头只会插入1(13 - 12 = 1)个空格。如果传递给
padStart方法的参数小于字符串的长度,则不会添加填充。70. 输出什么?
console
.log(“🥑”+“💻”);复制代码
A:
"``🥑💻``"B:
257548C: A string containing their code points
D: Error
答案
答案: A
使用
+运算符,您可以连接字符串。 上述情况,我们将字符串“``🥑``”与字符串”``💻``“连接起来,产生”``🥑💻``“。71. 如何能打印出
console.log语句后注释掉的值?function startGame()
{`const answer = yield "Do you love JavaScript?";<br /> if (answer !== "Yes") {<br /> return "Oh wow... Guess we're gone here";<br /> }<br /> return "JavaScript loves you back ❤️";<br />}<br /> <br />const game = startGame();<br />console.log(`/ 1 /);// Do you love JavaScript?`<br />console.log(`/ 2 /);// JavaScript loves you back ❤️<br />复制代码<br />A: `game.next("Yes").value`and `game.next().value`<br />B: `game.next.value("Yes")`and `game.next.value()`<br />C: `game.next().value`and `game.next("Yes").value`<br />D: `game.next.value()`and `game.next.value("Yes")`<br />答案 <br />答案: C<br />`generator`函数在遇到`yield`关键字时会“暂停”其执行。 首先,我们需要让函数产生字符串`Do you love JavaScript?`,这可以通过调用`game.next().value`来完成。上述函数的第一行就有一个`yield`关键字,那么运行立即停止了,`yield`表达式本身没有返回值,或者说总是返回`undefined`, 这意味着此时变量`answer` 为`undefined`<br />`next`方法可以带一个参数,该参数会被当作上一个`yield` 表达式的返回值。当我们调用`game.next("Yes").value`时,先前的`yield` 的返回值将被替换为传递给`next()`函数的参数`"Yes"`。此时变量 `answer` 被赋值为`"Yes"`,`if`语句返回`false`,所以`JavaScript loves you back❤️`被打印。<br />72. 输出什么?<br />console`.log(`String`.rawHello\nworld);`<br />复制代码<br />A: `Hello world!`<br />B: `Hello`<br /> `world`<br />C: `Hello\nworld`<br />D: `Hello\n`<br /> `world`<br />答案 <br />答案: C<br />`String.raw`函数是用来获取一个模板字符串的原始字符串的,它返回一个字符串,其中忽略了转义符(`\n`,`\v`,`\t`等)。但反斜杠可能造成问题,因为你可能会遇到下面这种类似情况:<br />const` path =C:\Documents\Projects\table.html<br />String`.raw``${path}复制代码
这将导致:
"C:DocumentsProjects able.html"直接使用
String.rawString
.raw``C:\Documents\Projects\table.html```<br />复制代码<br />它会忽略转义字符并打印:C:\Documents\Projects\table.html<br />上述情况,字符串是Hello\nworld被打印出。<br />73. 输出什么?<br />async function getData(){<br /> return await Promise.resolve("I made it!");<br />}<br /> <br />const data = getData();<br />console.log(data);<br />复制代码<br />A:“I made it!”<br />B:Promise {<br />C:Promise {<br />D:undefined<br />答案 <br />答案: C<br />异步函数始终返回一个promise。await仍然需要等待promise的解决:当我们调用getData()并将其赋值给data,此时data为getData方法返回的一个挂起的promise,该promise并没有解决。<br />如果我们想要访问已解决的值“I made it!”,可以在data上使用.then()方法:<br />data.then(res => console.log(res))<br />这样将打印“I made it!”<br />74. 输出什么?<br />function addToList(item, list){<br /> returnlist.push(item);<br />}<br /> <br />const result = addToList("apple", ["banana"]);<br />console.log(result);<br />复制代码<br />A:[‘apple’, ‘banana’]<br />B:2<br />C:true<br />D:undefined<br />答案 <br />答案: B<br />push()方法返回新数组的长度。一开始,数组包含一个元素(字符串“banana”),长度为1。 在数组中添加字符串“apple”后,长度变为2,并将从addToList函数返回。<br />push方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在pushitem之后返回list。<br />75. 输出什么?<br />const box = { x: 10, y: 20 };<br /> <br />Object.freeze(box);<br /> <br />const shape = box;<br />shape.x = 100;<br />console.log(shape)<br />复制代码<br />A:{ x: 100, y: 20 }<br />B:{ x: 10, y: 20 }<br />C:{ x: 100 }<br />D:ReferenceError<br />答案 <br />答案: B<br />Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。<br />当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)`将返回`true`。<br />由于`shape`被冻结,并且`x`的值不是对象,所以我们不能修改属性`x`。 `x`仍然等于`10`,`{x:10,y:20}被打印。<br />注意,上述例子我们对属性x进行修改,可能会导致抛出TypeError异常(最常见但不仅限于严格模式下时)。<br />76. 输出什么?<br />const { name: myName } = { name: "Lydia" };<br /> <br />console.log(name);<br />复制代码<br />A:“Lydia”<br />B:“myName”<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: D<br />当我们从右侧的对象解构属性name时,我们将其值Lydia分配给名为myName的变量。<br />使用{name:myName}`,我们是在告诉JavaScript我们要创建一个名为`myName`的新变量,并且其值是右侧对象的`name`属性的值。<br />当我们尝试打印`name`,一个未定义的变量时,就会引发`ReferenceError`。<br />77. 以下是个纯函数么?<br />function sum(a, b) `{`<br />` `return` a + b;`<br />`}`<br />复制代码<br />A: Yes<br />B: No<br />答案 <br />答案: A<br />纯函数一种若输入参数相同,则永远会得到相同输出的函数。<br />`sum`函数总是返回相同的结果。 如果我们传递`1`和`2`,它将总是返回`3`而没有副作用。 如果我们传递`5`和`10`,它将总是返回`15`,依此类推,这是纯函数的定义。<br />78. 输出什么?<br />const` add = `() =>` {`<br />` `const` cache = {};`<br />` `return` `num =>` {`<br />` `if` (num `in` cache) {`<br />` `return` From cache! ${cache[num]};`<br />` } `else` {`<br />` `const` result = num + `10`;`<br />` cache[num] = result;`<br />` `return` Calculated! ${result}`;}};};`<br />const addFunction = add();<br />console.log(addFunction(10));<br />console.log(addFunction(10));<br />console.log(addFunction(5 2));<br />复制代码<br />A:Calculated! 20`Calculated! 20 Calculated! 20B:
Calculated! 20 From cache! 20 Calculated! 20C:
Calculated! 20 From cache! 20 From cache! 20D:
Calculated! 20 From cache! 20 Error答案
答案: C
add函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度。上述情况,我们创建一个cache对象,用于存储先前返回过的值。如果我们使用相同的参数多次调用
addFunction函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。我们用相同的值三次调用了
addFunction函数:在第一次调用,
num等于10时函数的值尚未缓存,if语句num in cache返回false,else块的代码被执行:Calculated! 20,并且其结果被添加到缓存对象,cache现在看起来像{10``:20}。第二次,
cache对象包含10的返回值。 if语句num in cache 返回true,From cache! 20被打印。第三次,我们将
5 * 2(值为10)传递给函数。 cache对象包含10的返回值。 if语句num in cache 返回true,From cache! 20被打印。79. 输出什么?
const
myLifeSummedUp = [“☕”,“💻”,“🍷”,“🍫”]`<br />for (let item in myLifeSummedUp) {<br /> console.log(item)<br />}<br /> <br />for (let item of myLifeSummedUp) {<br /> console.log(item)<br />}<br />复制代码<br />A:01` `23and“☕“`"``💻``" "``🍷``" "``🍫``"B:
"``☕``" "``💻``" "``🍷``" "``🍫``" and "``☕``" "``💻``" "``🍷``" "``🍫``"C:
"``☕``" "``💻``" "``🍷``" "``🍫``" and 0 1``2 3D:
0``1 2``3 and {0: "``☕``", 1: "``💻``", 2: "``🍷``", 3: "``🍫``"}答案
答案: A
通过
for-in循环,我们可以遍历一个对象自有的、继承的、可枚举的、非Symbol的属性。 在数组中,可枚举属性是数组元素的“键”, 即它们的索引。 类似于下面这个对象:{0: "``☕``", 1: "``💻``", 2: "``🍷``", 3: "``🍫``"}其中键则是可枚举属性,因此
0,1,2,3被记录。通过
for-of循环,我们可以迭代可迭代对象(包括 Array,Map,Set,String,arguments等)。当我们迭代数组时,在每次迭代中,不同属性的值将被分配给变量item, 因此“``☕``”,“``💻``”,“``🍷``”,“``🍫``”被打印。80. 输出什么?
const
list = [1+2,1*2,1/2]console
.log(list)复制代码
A:
["1 + 2", "1 * 2", "1 / 2"]B:
["12", 2, 0.5]C:
[3, 2, 0.5]D:
[1, 1, 1]答案
答案: C
数组元素可以包含任何值。 数字,字符串,布尔值,对象,数组,
null,undeifned, 以及其他表达式,如日期,函数和计算。元素将等于返回的值。
1 + 2返回3,1 * 2返回’2,'1 / 2返回0.5。81. 输出什么?
function sayHi(name)
{`return Hi there, ${name}```<br />`}`<br />` `<br />console`.log(sayHi())`<br />复制代码<br />A: `Hi there,`<br />B: `Hi there, undefined`<br />C: `Hi there, null`<br />D: `ReferenceError`<br />答案 <br />答案: B<br />默认情况下,如果不给函数传参,参数的值将为`undefined`。 上述情况,我们没有给参数`name`传值。 `name`等于`undefined`,并被打印。<br />在ES6中,我们可以使用默认参数覆盖此默认的`undefined`值。 例如:<br />`function sayHi(name =“Lydia”){…}<br />在这种情况下,如果我们没有传递值或者如果我们传递undefined,name总是等于字符串Lydia<br />82. 输出什么?<br />var status = "😎"``<br /> <br />setTimeout(() => {<br /> const status = "😍"``<br /> <br /> const data = {<br /> status: "🥑",<br /> getStatus() {<br /> return this.status<br /> }<br /> }<br /> <br /> console.log(data.getStatus())<br /> console.log(data.getStatus.call(this))<br />}, 0)<br />复制代码<br />A:“🥑“and“😍“<br />B:“🥑“and“😎“<br />C:“😍“and“😎“<br />D:“😎“and“😎“<br />答案 <br />答案: B<br />this关键字的指向取决于使用它的位置。 在**函数**中,比如getStatus,this指向的是调用它的对象,上述例子中data对象调用了getStatus,因此this指向的就是data对象。 当我们打印this.status时,data对象的status属性被打印,即“🥑“。<br />使用call方法,可以更改this指向的对象。data.getStatus.call(this)是将this的指向由data对象更改为全局对象。在全局对象上,有一个名为status的变量,其值为”😎“。 因此打印this.status时,会打印“😎”。<br />83. 输出什么?<br />const person = {<br /> name: "Lydia",<br /> age: 21``<br />}<br /> <br />let city = person.city<br />city = "Amsterdam"``<br /> <br />console.log(person)<br />复制代码<br />A:{ name: “Lydia”, age: 21 }<br />B:{ name: “Lydia”, age: 21, city: “Amsterdam” }<br />C:{ name: “Lydia”, age: 21, city: undefined }<br />D:“Amsterdam”<br />答案 <br />答案: A<br />我们将变量city设置为等于person对象上名为city的属性的值。 这个对象上没有名为city的属性,因此变量city的值为undefined。<br />请注意,我们没有引用person对象本身,只是将变量city设置为等于person对象上city属性的当前值。<br />然后,我们将city设置为等于字符串“Amsterdam”。 这不会更改person对象:没有对该对象的引用。<br />因此打印person对象时,会返回未修改的对象。<br />84. 输出什么?<br />function checkAge(age){<br /> if (age < 18) {<br /> const message = "Sorry, you're too young."``<br /> } else {<br /> const message = "Yay! You're old enough!"``<br /> }<br /> <br /> return message<br />}<br /> <br />console.log(checkAge(21))<br />复制代码<br />A:“Sorry, you’re too young.”<br />B:“Yay! You’re old enough!”<br />C:ReferenceError<br />D:undefined<br />答案 <br />答案: C<br />const和let声明的变量是具有**块级作用域**的,块是大括号({})之间的任何东西, 即上述情况if / else语句的花括号。 由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError。<br />85. 什么样的信息将被打印?<br />fetch('https://www.website.com/api/user/1')<br /> .then(res => res.json())<br /> .then(res => console.log(res))<br />复制代码<br />A:fetch方法的结果<br />B: 第二次调用fetch方法的结果<br />C: 前一个.then()中回调方法返回的结果<br />D: 总是undefined<br />答案 <br />答案: C<br />第二个.then中res的值等于前一个.then中的回调函数返回的值。 你可以像这样继续链接.then,将值传递给下一个处理程序。<br />86. 哪个选项是将hasName设置为true的方法,前提是不能将true作为参数传递?<br />function getName(name){<br /> const hasName = //``<br />}<br />复制代码<br />A:!!name<br />B:name<br />C:new Boolean(name)<br />D:name.length<br />答案 <br />答案: A<br />使用逻辑非运算符!,将返回一个布尔值,使用!! name,我们可以确定name的值是真的还是假的。 如果name是真实的,那么!name返回false。!false返回true。<br />通过将hasName设置为name,可以将hasName设置为等于传递给getName函数的值,而不是布尔值true。<br />new Boolean(true)`返回一个对象包装器,而不是布尔值本身。<br />`name.length`返回传递的参数的长度,而不是布尔值`true`。<br />87. 输出什么?<br />console`.log(`"I want pizza"`[`0`])`<br />复制代码<br />A: `"""`<br />B: `"I"`<br />C: `SyntaxError`<br />D: `undefined`<br />答案 <br />答案: B<br />可以使用方括号表示法获取字符串中特定索引的字符,字符串中的第一个字符具有索引0,依此类推。 在这种情况下,我们想要得到索引为0的元素,字符`'I'`被记录。<br />请注意,IE7及更低版本不支持此方法。 在这种情况下,应该使用`.charAt()<br />88. 输出什么?<br />function sum(num1, num2 = num1){<br /> console.log(num1 + num2)<br />}<br /> <br />sum(10)<br />复制代码<br />A:NaN<br />B:20<br />C:ReferenceError<br />D:undefined<br />答案 <br />答案: B<br />您可以将默认参数的值设置为函数的另一个参数,只要另一个参数定义在其之前即可。 我们将值10传递给sum函数。 如果sum函数只接收1个参数,则意味着没有传递num2的值,这种情况下,num1的值等于传递的值10。num2的默认值是num1的值,即10。num1 + num2返回20。<br />如果您尝试将默认参数的值设置为后面定义的参数,则可能导致参数的值尚未初始化,从而引发错误。比如:<br />function test(m = n, n = 2){<br /> console.log(m, n)<br />}<br />test() // Uncaught ReferenceError: Cannot access 'n' before initialization``<br />test(3) // 3 2``<br />test(3, 4) // 3 4``<br />复制代码<br />89. 输出什么?<br />// module.js ``<br />export default () => "Hello world"``<br />export const name = "Lydia"``<br /> <br />// index.js ``<br />import as data from "./module"``<br /> <br />console.log(data)<br />复制代码<br />A:{ default: function default(), name: “Lydia” }<br />B:{ default: function default() }<br />C:{ default: “Hello world”, name: “Lydia” }<br />D: Global object ofmodule.js<br />答案 <br />答案: A<br />使用import as name语法,我们将module.js文件中所有export导入到index.js文件中,并且创建了一个名为data的新对象。 在module.js文件中,有两个导出:默认导出和命名导出。 默认导出是一个返回字符串“Hello World”的函数,命名导出是一个名为name的变量,其值为字符串“Lydia”。<br />data对象具有默认导出的default属性,其他属性具有指定exports的名称及其对应的值。<br />90. 输出什么?<br />class Person{<br /> constructor(name) {<br /> this.name = name<br /> }<br />}<br /> <br />const member = new Person("John")<br />console.log(typeof member)<br />复制代码<br />A:“class”<br />B:“function”<br />C:“object”<br />D:“string”<br />答案 <br />答案: C<br />类是构造函数的语法糖,如果用构造函数的方式来重写Person类则将是:<br />function Person(){<br /> this.name = name<br />}<br />复制代码<br />通过new来调用构造函数,将会生成构造函数Person的实例,对实例执行typeof关键字将返回“object”,上述情况打印出“object”。<br />91. 输出什么?<br />let newList = [1, 2, 3].push(4)<br /> <br />console.log(newList.push(5))<br />复制代码<br />A:[1, 2, 3, 4, 5]<br />B:[1, 2, 3, 5]<br />C:[1, 2, 3, 4]<br />D:Error<br />答案 <br />答案: D<br />.push方法返回数组的长度,而不是数组本身! 通过将newList设置为[1,2,3].push(4),实际上newList等于数组的新长度:4。<br />然后,尝试在newList上使用.push方法。 由于newList是数值4,抛出TypeError。<br />92. 输出什么?<br />function giveLydiaPizza(){<br /> return "Here is pizza!"``<br />}<br /> <br />const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."``<br /> <br />console.log(giveLydiaPizza.prototype)<br />console.log(giveLydiaChocolate.prototype)<br />复制代码<br />A:{ constructor: …}`{ constructor: ...}B:
{}``{ constructor: ...}C:
{ constructor: ...} {}D:
{ constructor: ...} undefined答案
答案: D
常规函数,例如
giveLydiaPizza函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如giveLydiaChocolate函数,没有这个prototype属性。 尝试使用giveLydiaChocolate.prototype访问prototype属性时会返回undefined。93. 输出什么?
const
person = {`name: "Lydia",<br /> age: 21``<br />}<br /> <br />for (const [x, y] of Object.entries(person)) {<br /> console.log(x, y)<br />}<br />复制代码<br />A:nameLydia` and `age` `21`<br />B: `["name", "Lydia"]` and `["age", 21]`<br />C: `["name", "age"]` and `undefined`<br />D: `Error`<br />答案 <br />答案: A<br />`Object.entries()`方法返回一个给定对象自身可枚举属性的键值对数组,上述情况返回一个二维数组,数组每个元素是一个包含键和值的数组:<br />`[['name',’Lydia’],[‘age’,21]]<br />使用for-of循环,我们可以迭代数组中的每个元素,上述情况是子数组。 我们可以使用const [x,y]`在`for-of`循环中解构子数组。 `x`等于子数组中的第一个元素,`y`等于子数组中的第二个元素。<br />第一个子阵列是`[“name”,“Lydia”],其中x等于name,而y等于Lydia。 第二个子阵列是[“age”,21]`,其中`x`等于`age`,而`y`等于`21`。<br />94. 输出什么?<br />function getItems(fruitList, ...args, favoriteFruit) `{`<br />` `return`[...fruitList, ...args, favoriteFruit]`<br />`}`<br />` `<br />`getItems([`"banana"`, `"apple"`], `"pear"`, `"orange"`)`<br />复制代码<br />A: `["banana", "apple", "pear", "orange"]`<br />B: `[["banana", "apple"], "pear", "orange"]`<br />C: `["banana", "apple", ["pear"], "orange"]`<br />D: `SyntaxError`<br />答案 <br />答案: D<br />`... args`是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,**并且只能作为最后一个参数**。上述示例中,剩余参数是第二个参数,这是不可能的,并会抛出语法错误。<br />function getItems(fruitList, favoriteFruit, ...args) `{`<br />` `return`[...fruitList, ...args, favoriteFruit]`<br />`}`<br />` `<br />`getItems([`"banana"`, `"apple"`], `"pear"`, `"orange"`)`<br />复制代码<br />上述例子是有效的,将会返回数组:`[ 'banana', 'apple', 'orange', 'pear' ]`<br />95. 输出什么?<br />function nums(a, b) `{`<br />` `if(a > b)`console.log('a is bigger')<br /> else <br /> console.log('b is bigger')<br /> return <br /> a + b<br />}<br /> <br />console.log(nums(4, 2))<br />console.log(nums(1, 2))<br />复制代码<br />A:a is bigger,6andb is bigger,3<br />B:a is bigger,undefinedandb is bigger,undefined<br />C:undefinedandundefined<br />D:SyntaxError<br />答案 <br />答案: B<br />在JavaScript中,我们不必显式地编写分号(;),但是JavaScript引擎仍然在语句之后自动添加分号。这称为**自动分号插入**。例如,一个语句可以是变量,或者像throw、return、break这样的关键字。<br />在这里,我们在新的一行上写了一个return语句和另一个值a + b。然而,由于它是一个新行,引擎并不知道它实际上是我们想要返回的值。相反,它会在return后面自动添加分号。你可以这样看:<br /> return;<br /> a + b<br />复制代码<br />这意味着永远不会到达a + b,因为函数在return关键字之后停止运行。如果没有返回值,就像这里,函数返回undefined。注意,在if/else语句之后没有自动插入!<br />96. 输出什么?<br />class Person{<br /> constructor() {<br /> this.name = "Lydia"``<br /> }<br />}<br /> <br />Person =class AnotherPerson{<br /> constructor() {<br /> this.name = "Sarah"``<br /> }<br />}<br /> <br />const member = new Person()<br />console.log(member.name)<br />复制代码<br />A:“Lydia”<br />B:“Sarah”<br />C:Error: cannot redeclare Person<br />D:SyntaxError<br />答案 <br />答案: B<br />我们可以将类设置为等于其他类/函数构造函数。 在这种情况下,我们将Person设置为AnotherPerson。 这个构造函数的名字是Sarah,所以新的Person实例member上的name属性是Sarah。<br />97. 输出什么?<br />const info = {<br /> [Symbol('a')]: 'b'``<br />}<br /> <br />console.log(info)<br />console.log(Object.keys(info))<br />复制代码<br />A:{Symbol(‘a’): ‘b’}and[“{Symbol(‘a’)”]<br />B:{}and[]<br />C:{ a: “b” }and[“a”]<br />D:{Symbol(‘a’): ‘b’}and[]<br />答案 <br />答案: D<br />Symbol类型是不可枚举的。Object.keys方法返回对象上的所有可枚举的键属性。Symbol类型是不可见的,并返回一个空数组。 记录整个对象时,所有属性都是可见的,甚至是不可枚举的属性。<br />这是Symbol的众多特性之一:除了表示完全唯一的值(防止对象意外名称冲突,例如当使用2个想要向同一对象添加属性的库时),您还可以隐藏这种方式对象的属性(尽管不完全。你仍然可以使用Object.getOwnPropertySymbols()方法访问Symbol。<br />98. 输出什么?<br />const getList = ([x, ...y]) => [x, y]<br />const getUser = user => { name: user.name, age: user.age }<br /> <br />const list = [1, 2, 3, 4]<br />const user = { name: "Lydia", age: 21 }<br /> <br />console.log(getList(list))<br />console.log(getUser(user))<br />复制代码<br />A:[1, [2, 3, 4]]andundefined<br />B:[1, [2, 3, 4]]and{ name: “Lydia”, age: 21 }<br />C:[1, 2, 3, 4]and{ name: “Lydia”, age: 21 }<br />D:Errorand{ name: “Lydia”, age: 21 }<br />答案 <br />答案: A<br />getList函数接收一个数组作为其参数。 在getList函数的括号之间,我们立即解构这个数组。 您可以将其视为:<br />[x, …y] = [1, 2, 3, 4]<br />使用剩余的参数… y,我们将所有剩余参数放在一个数组中。 在这种情况下,其余的参数是2,3和4。y的值是一个数组,包含所有其余参数。 在这种情况下,x的值等于1,所以当我们打印[x,y]`时,会打印`[1,[2,3,4]]。<br />getUser函数接收一个对象。对于箭头函数,如果只返回一个值,我们不必编写花括号。但是,如果您想从一个箭头函数返回一个对象,您必须在圆括号之间编写它,否则不会返回任何值!下面的函数将返回一个对象:<br />const getUser = user => ({ name: user.name, age: user.age })<br />由于在这种情况下不返回任何值,因此该函数返回undefined。<br />99. 输出什么?<br />const name = "Lydia"``<br /> <br />console.log(name())<br />复制代码<br />A:SyntaxError<br />B:ReferenceError<br />C:TypeError<br />D:undefined<br />答案 <br />答案: C<br />变量name保存字符串的值,该字符串不是函数,因此无法调用。<br />当值不是预期类型时,会抛出TypeErrors。 JavaScript期望name是一个函数,因为我们试图调用它。 但它是一个字符串,因此抛出TypeError:name is not a function<br />当你编写了一些非有效的JavaScript时,会抛出语法错误,例如当你把return这个词写成retrun时。 当JavaScript无法找到您尝试访问的值的引用时,抛出ReferenceErrors。<br />100. 输出什么?<br />// 🎉✨ This is my 100th question! ✨🎉``<br /> <br />const output = ${[] && 'Im'}possible!<br />You should${'' && `n't`} see a therapist after so much JavaScript lol```<br />复制代码<br />A: `possible! You should see a therapist after so much JavaScript lol`<br />B: `Impossible! You should see a therapist after so much JavaScript lol`<br />C: `possible! You shouldn't see a therapist after so much JavaScript lol`<br />D: `Impossible! You shouldn't see a therapist after so much JavaScript lol`<br />答案 <br />答案: B<br />`[]`是一个真值。 使用`&&`运算符,如果左侧值是真值,则返回右侧值。 在这种情况下,左侧值`[]`是一个真值,所以返回`Im`。<br />`""`是一个假值。 如果左侧值是假的,则不返回任何内容。 `n't`不会被退回。<br />101.输出什么?<br />const` one = (`false` || {} || `null`)`<br />const` two = (`null` || `false` || `""`)`<br />const` three = ([] || `0` || `true`)`<br />` `<br />console`.log(one, two, three)`<br />复制代码<br />A: `falsenull`[]B:
null``"" trueC:
{}``"" []D:
null``null true答案
答案: C
使用
||运算符,我们可以返回第一个真值。 如果所有值都是假值,则返回最后一个值。(false || {} || null):空对象{}是一个真值。 这是第一个(也是唯一的)真值,它将被返回。one等于{}。(null || false ||“”):所有值都是假值。 这意味着返回传递的值""。 two等于""。([] || 0 ||“”):空数组[]是一个真值。 这是第一个返回的真值。 three等于[]。
- 依次输出什么?
constmyPromise =() =>`Promise.resolve('I have resolved!')<br /><br />function firstFunction(){<br />myPromise().then(res =>console.log(res))<br />console.log('second')<br />}<br /><br />asyncfunction secondFunction(){<br />console.log(awaitmyPromise())<br />console.log('second')<br />}<br /><br />firstFunction()<br />secondFunction()<br />复制代码<br />A:I have resolved!,secondandI have resolved!,second<br />B:second,I have resolved!andsecond,I have resolved!<br />C:I have resolved!,secondandsecond,I have resolved!<br />D:second,I have resolved!andI have resolved!,second<br />答案 <br />答案: D<br />有了promise,我们通常会说:当我想要调用某个方法,但是由于它可能需要一段时间,因此暂时将它放在一边。只有当某个值被resolved/rejected,并且执行栈为空时才使用这个值。<br />我们可以在async函数中通过.then和await关键字获得该值。 尽管我们可以通过.then和await获得promise的价值,但是它们的工作方式有所不同。<br />在firstFunction中,当运行到myPromise方法时我们将其放在一边,即promise进入微任务队列,其他后面的代码(console.log(‘second’))照常运行,因此second被打印出,firstFunction方法到此执行完毕,执行栈中宏任务队列被清空,此时开始执行微任务队列中的任务,I have resolved被打印出。<br />在secondFunction方法中,我们通过await关键字,暂停了后面代码的执行,直到异步函数的值被解析才开始后面代码的执行。这意味着,它会等着直到myPromise 以值I have resolved被解决之后,下一行second才开始执行。<br />103. 输出什么?<br />constset =newSet()<br /><br />set.add(1)<br />set.add("Lydia")<br />set.add({name:"Lydia"})<br /><br />for(letitemofset) {<br />console.log(item +2)<br />}<br />复制代码<br />A:3,NaN,NaN<br />B:3,7,NaN<br />C:3,Lydia2,[Object object]2<br />D:“12”,Lydia2,[Object object]2<br />答案 <br />答案: C<br />“+”运算符不仅用于数值相加,还可以使用它来连接字符串。 每当JavaScript引擎发现一个或多个值不是数字时,就会将数字强制转化为字符串。<br />第一个是数字1, 1 + 2返回数字3。<br />但是,第二个是字符串Lydia。Lydia是字符串,2是数字:2被强制转换为字符串。Lydia和2被连接起来,产生字符Lydia2。<br />{name:“Lydia”}`是一个对象。 数字和对象都不是字符串,因此将二者都字符串化。 每当我们对常规对象进行字符串化时,它就会变成`“[Object object]”`。<br />104. 结果是什么?<br />Promise`.resolve(`5`)`<br />复制代码<br />A: `5`<br />B: `Promise {<pending>: 5}`<br />C: `Promise {<resolved>: 5}`<br />D: `Error`<br />答案 <br />答案: C<br />我们可以将我们想要的任何类型的值传递`Promise.resolve`,无论是否`promise`。 该方法本身返回带有已解析值的`Promise`。 如果您传递常规函数,它将是具有常规值的已解决`promise`。 如果你通过了promise,它将是一个已经resolved的且带有传的值的promise。<br />上述情况,我们传了数字5,因此返回一个resolved状态的promise,resolve值为`5`<br />105. 输出什么?<br />function compareMembers(person1, person2 = person) `{`<br />` `if`(person1 !== person2) {`<br />` `console`.log(`"Not the same!"`)`<br />` } `else` {`<br />` `console`.log(`"They are the same!"`)`<br />` }`<br />`}`<br />` `<br />const` person = { `name`: `"Lydia"` }`<br />` `<br />`compareMembers(person)`<br />复制代码<br />A: `Not the same!`<br />B: `They are the same!`<br />C: `ReferenceError`<br />D: `SyntaxError`<br />答案 <br />答案: B<br />对象通过引用传递。 当我们检查对象的严格相等性(===)时,我们正在比较它们的引用。<br />我们将`person2`的默认值设置为`person`对象,并将`person`对象作为`person1`的值传递。<br />这意味着两个值都引用内存中的同一位置,因此它们是相等的。<br />运行“ else”语句中的代码块,并记录`They are the same!` 。<br />106. 输出什么?<br />const` colorConfig = {`<br />` `red`: `true`,`<br />` `blue`: `false`,`<br />` `green`: `true`,`<br />` `black`: `true`,`<br />` `yellow`: `false`,`<br />`}`<br />` `<br />const` colors = [`"pink"`, `"red"`, `"blue"`]`<br />` `<br />console`.log(colorConfig.colors[`1`])`<br />复制代码<br />A: `true`<br />B: `false`<br />C: `undefined`<br />D: `TypeError`<br />答案 <br />答案: D<br />在JavaScript中,我们有两种访问对象属性的方法:括号表示法或点表示法。 在此示例中,我们使用点表示法(`colorConfig.colors`)代替括号表示法(`colorConfig [“ colors”]`)。<br />使用点表示法,JavaScript会尝试使用该确切名称在对象上查找属性。 在此示例中,JavaScript尝试在colorconfig对象上找到名为colors的属性。 没有名为“colors”的属性,因此返回“undefined”。 然后,我们尝试使用`[1]`访问第一个元素的值。 我们无法对未定义的值执行此操作,因此会抛出`Cannot read property '1' of undefined`。<br />JavaScript解释(或取消装箱)语句。 当我们使用方括号表示法时,它会看到第一个左方括号`[`并一直进行下去,直到找到右方括号`]`。 只有这样,它才会评估该语句。 如果我们使用了colorConfig [colors [1]],它将返回colorConfig对象上red属性的值。<br />107. 输出什么?<br />console`.log(`'❤️'` === `'❤️'`)`<br />复制代码<br />A: `true`<br />B: `false`<br />答案 <br />答案: A<br />在内部,表情符号是unicode。 心表情符号的unicode是`U+2764 U+FE0F`。 对于相同的表情符号,它们总是相同的,因此我们正在将两个相等的字符串相互比较,这将返回true。<br />108. 哪些方法修改了原数组?<br />const` emojis = [`'✨'`, `'🥑'`, `'😍'`]`<br />` `<br />`emojis.map(`x =>` x + `'✨'`)`<br />`emojis.filter(`x =>` x !== `'🥑'`)`<br />`emojis.find(`x =>` x !== `'🥑'`)`<br />`emojis.reduce(`(acc, cur) =>` acc + `'✨'`)`<br />`emojis.slice(`1`, `2`, `'✨'`) `<br />`emojis.splice(`1`, `2`, `'✨'`)`<br />复制代码<br />A: `All of them`<br />B: `mapreduce`slicesplice
C:map``slicesplice
D:splice
答案
答案: D
使用splice方法,我们通过删除,替换或添加元素来修改原始数组。 上述情况,我们从索引1中删除了2个元素(删除了’🥑’和’😍’),并添加了✨emoji表情。map,filter和slice返回一个新数组,find返回一个元素,而reduce返回一个减小的值。
109. 输出什么?
constfood = [‘🍕’,‘🍫’,‘🥑’,‘🍔’]
constinfo = {favoriteFood: food[0] }`<br />info.favoriteFood ='🍝'``<br /><br />console.log(food)<br />复制代码<br />A:[‘🍕‘, ‘🍫‘, ‘🥑‘, ‘🍔‘]<br />B:[‘🍝‘, ‘🍫‘, ‘🥑‘, ‘🍔‘]<br />C:[‘🍝‘, ‘🍕‘, ‘🍫‘, ‘🥑‘, ‘🍔‘]<br />D:ReferenceError<br />答案 <br />答案: A<br />我们将info对象上的favoriteFood属性的值设置为披萨表情符号“🍕”的字符串。字符串是原始数据类型。在JavaScript中,原始数据类型通过值起作用<br />在这种情况下,我们将info对象上的favoriteFood属性的值设置为等于food数组中的第一个元素的值,字符串为披萨表情符号(‘🍕‘)。字符串是原始数据类型,并且通过值进行交互,我们更改info对象上favoriteFood属性的值。 food数组没有改变,因为favoriteFood的值只是该数组中第一个元素的值的复制,并且与该元素上的元素没有相同的内存引用食物[0]。当我们记录食物时,它仍然是原始数组[‘🍕‘,'🍫',’🥑‘,'🍔']`。<br />110. 这个函数干了什么?<br />JSON`.parse()`<br />复制代码<br />A: Parses JSON to a JavaScript value<br />B: Parses a JavaScript object to JSON<br />C: Parses any JavaScript value to JSON<br />D: Parses JSON to a JavaScript object only<br />答案 <br />答案: A<br />使用`JSON.parse()`方法,我们可以将JSON字符串解析为JavaScript值。<br />// 将数字字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:
constjsonNumber =JSON.stringify(4)// ‘4’<br />JSON`.parse(jsonNumber) `// 4`<br />// 将数组值字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:``<br />constjsonArray =JSON.stringify([1,2,3])// '[1, 2, 3]'``<br />JSON.parse(jsonArray)// [1, 2, 3]``<br /><br />// 将对象字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:``<br />constjsonArray =JSON.stringify({name:"Lydia"})// '{"name":"Lydia"}'``<br />JSON.parse(jsonArray)// { name: 'Lydia' }``<br />复制代码<br />111. 输出什么?<br />letname ='Lydia'``<br /><br />function getName(){<br />console.log(name)<br />letname ='Sarah'``<br />}<br /><br />getName()<br />复制代码<br />A: Lydia<br />B: Sarah<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: D<br />每个函数都有其自己的执行上下文。getName函数首先在其自身的上下文(范围)内查找,以查看其是否包含我们尝试访问的变量name。 上述情况,getName函数包含其自己的name变量:我们用let关键字和Sarah的值声明变量name。<br />带有let关键字(和const)的变量被提升,但是与var不同,它不会被***初始化***。 在我们声明(初始化)它们之前,无法访问它们。 这称为“暂时性死区”。 当我们尝试在声明变量之前访问变量时,JavaScript会抛出ReferenceError: Cannot access ‘name’ before initialization。<br />如果我们不在getName函数中声明name变量,则javascript引擎会查看原型练。会找到其外部作用域有一个名为name的变量,其值为Lydia。 在这种情况下,它将打印Lydia:<br />letname ='Lydia'``<br /><br />function getName(){<br />console.log(name)<br />}<br /><br />getName()// Lydia``<br />复制代码<br />112. 输出什么?<br />function* generatorOne(){<br />yield['a','b','c'];<br />}<br />function* generatorTwo(){<br />yield['a','b','c'];<br />}<br />constone = generatorOne()<br />consttwo = generatorTwo()<br />console.log(one.next().value)<br />console.log(two.next().value)<br />复制代码<br />A:aanda<br />B:aandundefined<br />C:[‘a’, ‘b’, ‘c’]anda<br />D:aand[‘a’, ‘b’, ‘c’]<br />答案 <br />答案: C<br />通过yield关键字, 我们在Generator函数里执行yield表达式. 通过yield关键字, 我们可以在一个Generator函数里面执行(yield表达式)另一个Generator函数, 或可遍历的对象 (如数组).<br />在函数generatorOne中, 我们通过yield关键字 yield 了一个完整的数组[‘a’, ‘b’, ‘c’]。函数one通过next方法返回的对象的value属性的值 (one.next().value) 等价于数组[‘a’, ‘b’, ‘c’].<br />console.log(one.next().value)// ['a', 'b', 'c']``<br />console.log(one.next().value)// undefined``<br />复制代码<br />在函数generatorTwo中, 我们使用yield关键字。就相当于函数two第一个yield的值, 等价于在迭代器中第一个yield的值。数组[‘a’, ‘b’, ‘c’]就是这个迭代器. 第一个yield的值就是a, 所以我们第一次调用two.next().value时, 就返回a。<br />console.log(two.next().value)// 'a'``<br />console.log(two.next().value)// 'b'``<br />console.log(two.next().value)// 'c'``<br />console.log(two.next().value)// undefined``<br />复制代码<br />113. 输出什么?<br />console.log(${(x => x)('I love')} to program)<br />复制代码<br />A:I love to program<br />B:undefined to program<br />C:${(x => x)(‘I love’) to program<br />D:TypeError<br />答案 <br />答案: A<br />带有模板字面量的表达式首先被执行。相当于字符串会包含表达式,这个立即执行函数(x => x)(‘I love’)返回的值. 我们向箭头函数x => x传递‘I love’作为参数。x等价于返回的‘I love’。这就是结果I love to program。<br />114. 将会发生什么?<br />letconfig = {<br />alert: setInterval(() =>{<br />console.log('Alert!')<br />},1000)<br />}<br />config =null``<br />复制代码<br />A:setInterval的回调不会被调用<br />B:setInterval的回调被调用一次<br />C:setInterval的回调仍然会被每秒钟调用<br />D: 我们从没调用过config.alert(), config 为null<br />答案 <br />答案: C<br />一般情况下当我们将对象赋值为null, 那些对象会被进行 _垃圾回收(garbage collected)_ 因为已经没有对这些对象的引用了。然而,setInterval的参数是一个箭头函数(所以上下文绑定到对象config了),回调函数仍然保留着对config的引用。只要存在引用,对象就不会被垃圾回收。因为没有被垃圾回收,setInterval的回调每1000ms (1s)会被调用一次。<br />115. 哪一个方法会返回‘Hello world!’?<br />constmyMap =newMap()<br />constmyFunc =() =>'greeting'``<br />myMap.set(myFunc,'Hello world!')<br />//1``<br />myMap.get('greeting')<br />//2``<br />myMap.get(myFunc)<br />//3``<br />myMap.get(() =>'greeting')<br />复制代码<br />A: 1<br />B: 2<br />C: 2 and 3<br />D: All of them<br />答案 <br />答案: B<br />当通过set方法添加一个键值对,一个传递给set方法的参数将会是键名,第二个参数将会是值。在这个case里,键名为 _函数_() => ‘greeting’,值为‘Hello world’。myMap现在就是{ () => ‘greeting’ => ‘Hello world!’ }。<br />1 是错的,因为键名不是‘greeting’而是() => ‘greeting’。 3 是错的,因为我们给get方法传递了一个新的函数。对象受 _引用_影响。函数也是对象,因此两个函数严格上并不等价,尽管他们相同:他们有两个不同的内存引用地址。<br />116. 输出什么?<br />constperson = {<br />name:"Lydia",<br />age:21``<br />}<br />constchangeAge =(x = { ...person }) =>x.age +=1``<br />constchangeAgeAndName =(x = { ...person }) =>{<br />x.age +=1``<br />x.name ="Sarah"``<br />}<br />changeAge(person)<br />changeAgeAndName()<br />console.log(person)<br />复制代码<br />A:{name: “Sarah”, age: 22}<br />B:{name: “Sarah”, age: 23}<br />C:{name: “Lydia”, age: 22}<br />D:{name: “Lydia”, age: 23}<br />答案 <br />答案: C<br />函数changeAge和函数changeAgeAndName有着不同的参数,定义一个 _新_生成的对象{ …person }。这个对象有着所有person对象 中 k/v 值的副本。<br />首项, 我们调用changeAge函数并传递person对象作为它的参数。这个函数对age属性进行加一操作。person现在是{ name: “Lydia”, age: 22 }。<br />然后,我们调用函数changeAgeAndName,然而我们没有传递参数。取而代之,x的值等价 _new_ 生成的对象:{ …person }。因为它是一个新生成的对象,它并不会对对象person造成任何副作用。person仍然等价于{ name: “Lydia”, age: 22 }。<br />117. 下面那个选项将会返回6?<br />function sumValues(x, y, z){<br />returnx + y + z;<br />}<br />复制代码<br />A:sumValues([…1, 2, 3])<br />B:sumValues([…[1, 2, 3]])<br />C:sumValues(…[1, 2, 3])<br />D:sumValues([1, 2, 3])<br />答案 <br />答案: C<br />通过展开操作符…,我们可以_暂开_ 单个可迭代的元素。函数sumValuesfunction 接收三个参数:x,y和z。…[1, 2, 3]的执行结果为1, 2, 3,将会传递给函数sumValues。<br />118. 输出什么?<br />letnum =1;<br />constlist = ["🥳","🤠","🥰","🤪"];<br />console.log(list[(num +=1)]);<br />复制代码<br />A:🤠<br />B:🥰<br />C:SyntaxError<br />D:ReferenceError<br />答案 <br />答案: B<br />通过+=操作符,我们对值num进行加1操作。num有初始值1,因此1 + 1的执行结果为2。数组list的第二项为🥰,console.log(list[2])输出 🥰.<br />119. 输出什么?<br />constperson = {<br />firstName:"Lydia",<br />lastName:"Hallie",<br />pet: {<br />name:"Mara",<br />breed:"Dutch Tulip Hound"``<br />},<br />getFullName() {<br />return${this.firstName} ${this.lastName};<br />}<br />};<br />console.log(person.pet?.name);<br />console.log(person.pet?.family?.name);<br />console.log(person.getFullName?.());<br />console.log(member.getLastName?.());<br />复制代码<br />A:undefinedundefined` `undefined` `undefined`<br />B: `Maraundefined`Lydia Hallieundefined
C:Mara``nullLydia Hallienull
D:null``ReferenceErrornullReferenceError
答案
答案: B
通过 ES10 或 TS3.7+可选链操作符?.,我们不再需要显式检测更深层的嵌套值是否有效。如果我们尝试获取undefined或null的值 (nullish),表达将会短路并返回undefined.person.pet?.name:person有一个名为pet的属性:person.pet不是 nullish。它有个名为name的属性,并返回字符串Mara。person.pet?.family?.name:person有一个名为pet的属性:person.pet不是 nullish.pet并没有 一个名为family的属性,person.pet.family是 nullish。表达式返回undefined。person.getFullName?.():person有一个名为getFullName的属性:person.getFullName()不是 nullish 并可以被调用,返回字符串Lydia Hallie。member.getLastName?.():memberis not defined:member.getLastName()is nullish. The expression returnsundefined.
120. 输出什么?
constgroceries = [“banana”,“apple”,“peanuts”];
if(groceries.indexOf(“banana”)) {`console.log("We have to buy bananas!");<br />}else{<br />console.log(We don't have to buy bananas!);<br />}<br />复制代码<br />A: We have to buy bananas!<br />B: We don't have to buy bananas<br />C:undefined<br />D:1<br />答案 <br />答案: B<br />我们传递了一个状态groceries.indexOf(“banana”)给if条件语句。groceries.indexOf(“banana”)返回0, 一个 falsy 的值。因为if条件语句的状态为 falsy,else块区内的代码执行,并且We don’t have to buy bananas!被输出.<br />121. 输出什么?<br />constconfig = {<br />languages: [],<br />set language(lang) {<br />returnthis.languages.push(lang);<br />}<br />};<br />console.log(config.language);<br />复制代码<br />A:function language(lang) { this.languages.push(lang }<br />B:0<br />C:[]<br />D:undefined<br />答案 <br />答案: D<br />方法language是一个setter。Setters 并不保存一个实际值,它们的使命在于 _修改_ 属性。当调用方法setter, 返回undefined。<br />122. 输出什么?<br />constname ="Lydia Hallie";<br />console.log(!typeofname ==="object");<br />console.log(!typeofname ==="string");<br />复制代码<br />A:falsetrue`<br />B: `truefalse<br />C:falsefalse`<br />D: `truetrue<br />答案 <br />答案: C<br />typeof name返回“string”。字符串“string”是一个 truthy 的值,因此!typeof name返回一个布尔值false。false === “object”和false === “string”都返回false。 (如果我们想检测一个值的类型,我们不应该用!==而不是!typeof)<br />123. 输出什么?<br />constadd =x =>y =>z =>{<br />console.log(x, y, z);<br />returnx + y + z;<br />};<br />add(4)(5)(6);<br />复制代码<br />A:45` `6`<br />B: `65`4
C:4``functionfunction
D:undefined``undefined6
答案
答案: A
函数add是一个返回 返回箭头函数的箭头函数 的箭头函数(still with me?)。第一个函数接收一个值为4的参数x。我们调用第二个函数,它接收一个值为5的参数y。然后我们调用第三个函数,它接收一个值为6的参数z。当我们尝试在最后一个箭头函数中获取x,y和z的值,JS 引擎根据作用域链去找x和y的值。得到456.
124. 输出什么?
asyncfunction range(start, end){`for(leti = start; i <= end; i++) {<br />yieldPromise.resolve(i);<br />}<br />}<br />(async() => {<br />constgen = range(1,3);<br />forawait(constitemofgen) {<br />console.log(item);<br />}<br />})();<br />复制代码<br />A:Promise {1}`Promise {2}Promise {3}
B:Promise {<pending>}Promise {<pending>}``Promise {<pending>}
C:1``23
D:undefined``undefinedundefined
答案
答案: C
我们给 函数range 传递:Promise{1},Promise{2},Promise{3},Generator 函数range返回一个全是 async object promise 数组。我们将 async object 赋值给变量gen,之后我们使用for await ... of进行循环遍历。我们将返回的 Promise 实例赋值给item: 第一个返回Promise{1}, 第二个返回Promise{2},之后是Promise{3}。因为我们正 awaitingitem的值,resolved状态的 promsie,promise数组的resolved 值以此为:1,2,3.
125. 输出什么?
constmyFunc =({ x, y, z }) =>{`console.log(x, y, z);<br />};<br />myFunc(1,2,3);<br />复制代码<br />A:12` `3`<br />B: `{1: 1}{2: 2}`{3: 3}
C:{ 1: undefined }undefined``undefined
D:undefined``undefinedundefined
答案
答案: DmyFunc期望接收一个包含x,y和z属性的对象作为它的参数。因为我们仅仅传递三个单独的数字值 (1, 2, 3) 而不是一个含有x,y和z属性的对象 ({x: 1, y: 2, z: 3}),x,y和z有着各自的默认值undefined.
126. 输出什么?
function getFine(speed, amount){`constformattedSpeed =newIntl.NumberFormat({<br />'en-US',<br />{style:'unit',unit:'mile-per-hour'}<br />}).format(speed)<br />constformattedAmount =newIntl.NumberFormat({<br />'en-US',<br />{style:'currency',currency:'USD'}<br />}).format(amount)<br />returnThe driver drove ${formattedSpeed} and has to pay ${formattedAmount}```<br />`}`<br />console`.log(getFine(`130`, `300`))`<br />复制代码<br />A: The driver drove 130 and has to pay 300<br />B: The driver drove 130 mph and has to pay $300.00<br />C: The driver drove undefined and has to pay undefined<br />D: The driver drove 130.00 and has to pay 300.00<br />答案 <br />答案: B<br />通过方法 `Intl.NumberFormat`,我们可以格式化任意区域的数字值。我们对数字值`130` 进行 `mile-per-hour` 作为`unit` 的 `en-US` 区域 格式化,结果为`130 mph`。对数字值 `300` 进行 `USD` 作为 `currentcy` 的`en-US` 区域格式化,结果为`$300.00`.<br />127. 输出什么?<br />const` spookyItems = [`"👻"`, `"🎃"`, `"🕸"`];`<br />`({ `item`: spookyItems[`3`] } = { `item`: `"💀"` });`<br />console`.log(spookyItems);`<br />复制代码<br />A: `["👻", "🎃", "🕸"]`<br />B: `["👻", "🎃", "🕸", "💀"]`<br />C: `["👻", "🎃", "🕸", { item: "💀" }]`<br />D: `["👻", "🎃", "🕸", "[object Object]"]`<br />答案 <br />答案: B<br />通过解构对象们,我们可以从右手边的对象中拆出值,并且将拆出的值分配给左手边对象同名的属性。在这种情况下,我们将值 "💀" 分配给`spookyItems[3]`。相当于我们正在篡改数组 `spookyItems`,我们给它添加了值 "💀"。当输出`spookyItems` 时,结果为`["👻", "🎃", "🕸", "💀"]`。<br />128. 输出什么?<br />const` name = `"Lydia Hallie"`;`<br />const` age = `21`;`<br />console`.log(`Number`.isNaN(name));`<br />console`.log(`Number`.isNaN(age));`<br />console`.log(`isNaN`(name));`<br />console`.log(`isNaN`(age));`<br />复制代码<br />A: `truefalse`truefalse
B:true``falsefalsefalse
C:false``falsetruefalse
D:false``truefalsetrue
答案
答案: C
通过方法Number.isNaN,你可以检测你传递的值是否为数字值 并且是否等价于NaN。name不是一个数字值,因此Number.isNaN(name)返回false。age是一个数字值,但它不等价于NaN,因此Number.isNaN(age)返回false. 通过方法isNaN, 你可以检测你传递的值是否一个 number。name不是一个number,因此isNaN(name)返回true.age是一个number因此isNaN(age)返回false.
129. 输出什么?
constrandomValue =21;
function getInfo(){`console.log(typeofrandomValue);<br />constrandomValue ="Lydia Hallie";<br />}<br />getInfo();<br />复制代码<br />A:“number”<br />B:“string”<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: D<br />通过const关键字声明的变量在被初始化之前不可被引用:这被称之为 _暂时性死去_。在函数getInfo中, 变量randomValue声明在getInfo的作用域的此法环境中。在想要对typeof randomValue进行log之前,变量randomValue仍未被初始化: 错误ReferenceError被抛出! JS引擎并不会根据作用域链网上寻找该变量,因为我们已经在getInfo函数中声明了randomValue变量。<br />130. 输出什么?<br />constmyPromise =Promise.resolve("Woah some cool data");<br />(async () =>{<br />try{<br />console.log(awaitmyPromise);<br />}catch{<br />thrownewError(Oops didn't work);<br />}finally{<br />console.log("Oh finally!");<br />}<br />})();<br />复制代码<br />A:Woah some cool data<br />B:Oh finally!<br />C:Woah some cool data`Oh finally!
D:Oops didn't workOh finally!
答案
答案: C
在try块区,我们打印myPromise变量的 awaited 值:"Woah some cool data"。因为try块区没有错误抛出,catch块区的代码并不执行。finally块区的代码总是 执行,"Oh finally!"被输出。
131. 输出什么?
constemojis = [“🥑”, [“✨”,“✨”, [“🍕”,“🍕”]]];
console.log(emojis.flat(1));
复制代码
A:['``🥑``', ['``✨``', '``✨``', ['``🍕``', '``🍕``']]]
B:['``🥑``', '``✨``', '``✨``', ['``🍕``', '``🍕``']]
C:['``🥑``', ['``✨``', '``✨``', '``🍕``', '``🍕``']]
D:['``🥑``', '``✨``', '``✨``', '``🍕``', '``🍕``']
答案
答案: B
通过方法flat, 我们可以创建一个新的, 已被扁平化的数组。被扁平化的深度取决于我们传递的值。在这个case里,我们传递了值1(并不必要,这是默认值),相当于只有第一层的数组才会被连接。即这个 case 里的['``🥑``']and['``✨``', '``✨``', ['``🍕``', '``🍕``']]。连接这两个数组得到结果['``🥑``', '``✨``', '``✨``', ['``🍕``', '``🍕``']].
132. 输出什么?
class Counter{`constructor() {<br />this.count =0;<br />}<br />increment() {<br />this.count++;<br />}<br />}<br />constcounterOne =newCounter();<br />counterOne.increment();<br />counterOne.increment();<br />constcounterTwo = counterOne;<br />counterTwo.increment();<br />console.log(counterOne.count);<br />复制代码<br />A:0<br />B:1<br />C:2<br />D:3<br />答案 <br />答案: D<br />counterOne是类Counter的一个实例。类 Counter 包含一个count属性在它的构造函数里, 和一个increment方法。首先,我们通过counterOne.increment()调用方法increment两次。现在counterOne.count 为 2.<br />然后,我们创建一个新的变量counterTwo并将counterOne的引用地址赋值给它。因为对象受引用地址的影响,我们刚刚创建了一个新的对象,其引用地址和counterOne的等价。因此它们指向同一块内存地址,任何对其的副作用都会影响counterTwo。现在counterTwo.count为2。我们调用counterTwo.increment()将count的值设为3。<br />然后,我们打印counterOne里的count为3.`<br />133. 输出什么?<br />const` myPromise = `Promise`.resolve(`Promise`.resolve(`"Promise!"`));`<br />function funcOne() `{`<br />` myPromise.then(`res =>`res).then(`res =>` `console`.log(res));`<br />` setTimeout(`() =>` `console`.log(`"Timeout!"`, `0`));`<br />` `console`.log(`"Last line!"`);`<br />`}`<br />async` `function funcTwo() `{`<br />` `const` res = `await` myPromise;`<br />` `console`.log(`await` res);`<br />` setTimeout(`() =>` `console`.log(`"Timeout!"`, `0`));`<br />` `console`.log(`"Last line!"`);`<br />`}`<br />`funcOne();`<br />`funcTwo();`<br />复制代码<br />A: `Promise! Last line! Promise! Last line! Last line! Promise!`<br />B: `Last line! Timeout! Promise! Last line! Timeout! Promise!`<br />C: `Promise! Last line! Last line! Promise! Timeout! Timeout!`<br />D: `Last line! Promise! Promise! Last line! Timeout! Timeout!`<br />答案 <br />答案: D<br />首先,我们调用 `funcOne`。在函数`funcOne` 的第一行,我们调用`myPromise`promise _异步操作_。当JS引擎在忙于执行 promise,它继续执行函数 `funcOne`。下一行 _异步操作_ `setTimeout`,其回调函数被 Web API 调用。 (详情请参考我关于event loop的文章.) promise 和 timeout 都是异步操作,函数继续执行当JS引擎忙于执行promise 和 处理 `setTimeout` 的回调。相当于 `Last line!` 首先被输出, 因为它不是异步操作。执行完 `funcOne` 的最后一行,promise 状态转变为 resolved,`Promise!` 被打印。然而,因为我们调用了`funcTwo()`, 调用栈不为空,`setTimeout` 的回调仍不能入栈。 我们现在处于 `funcTwo`,先 _awaiting_ myPromise。通过`await` 关键字, 我们暂停了函数的执行直到 promise 状态变为 resolved (或 rejected)。然后,我们输出 `res` 的 awaited 值(因为promise 本身返回一个 promise)。 接着输出 `Promise!`。 下一行就是 _异步操作_ `setTimeout`,其回调函数被 Web API 调用。 我们执行到函数 `funcTwo` 的最后一行,输出 `Last line!`。现在,因为`funcTwo` 出栈,调用栈为空。在事件队列中等待的回调函数(`() => console.log("Timeout!")` from `funcOne`, and `() => console.log("Timeout!")`from `funcTwo`)以此入栈。第一个回调输出 `Timeout!`,并出栈。然后,第二个回调输出 `Timeout!`,并出栈。得到结果 `Last line! Promise! Promise! Last line! Timeout! Timeout!`<br />134. 我们怎样才能在 `index.js` 中调用`sum.js?` 中的`sum`?<br />// sum.js
export`defaultfunction sum(x){<br />returnx + x;<br />}<br />// index.js``<br />importassumfrom"./sum";<br />复制代码<br />A:sum(4)<br />B:sum.sum(4)<br />C:sum.default(4)<br />D: 默认导出不用来导入,只能具名导出<br />答案 <br />答案: C<br />使用符号,我们引入文件中的所有值,包括默认和具名。如果我们有以下文件:<br />// info.js``<br />exportconstname ="Lydia";<br />exportconstage =21;<br />exportdefault"I love JavaScript";<br />// index.js``<br />importasinfofrom"./info";<br />console.log(info);<br />复制代码<br />将会输出以下内容:<br />{<br />default:"I love JavaScript",<br />name:"Lydia",<br />age:21``<br />}<br />复制代码<br />以sum为例,相当于以下形式引入值sum:<br />{default:function sum(x){returnx + x } }<br />复制代码<br />我们可以通过调用sum.default来调用该函数<br />135. 输出什么?<br />consthandler = {<br />set:() =>console.log("Added a new property!"),<br />get:() =>console.log("Accessed a property!")<br />};<br />constperson =newProxy({}, handler);<br />person.name ="Lydia";<br />person.name;<br />复制代码<br />A:Added a new property!<br />B:Accessed a property!<br />C:Added a new property!`Accessed a property!
D: 没有任何输出
答案
答案: C
使用 Proxy 对象,我们可以给一个对象添加自定义行为。在这个 case,我们传递一个包含以下属性的对象handler:setandget。每当我门 设置 属性值时set被调用,每当我们获取 时get被调用。 第一个参数是一个空对象{},作为person的值。对于这个对象,自定义行为被定义在对象handler。如果我们向对象person添加属性,set将被调用。如果我们获取person的属性,get将被调用。 首先,我们向 proxy 对象(person.name = "Lydia")添加一个属性name。set被调用并输出"Added a new property!"。 然后,我们获取 proxy 对象的一个属性,对象 handler 的属性get被调用。输出"Accessed a property!"。
136. 以下哪一项会对对象person有副作用?
constperson = {name:“Lydia Hallie”};
Object.seal(person);
复制代码
A:person.name = "Evan Bacon"
B:person.age = 21
C:delete person.name
D:Object.assign(person, { age: 21 })
答案
答案: A
使用Object.seal我们可以防止新属性 被添加,或者存在属性被移除. 然而,你仍然可以对存在属性进行更改。
137. 以下哪一项会对对象person有副作用?
constperson = {`name:"Lydia Hallie",<br />address: {<br />street:"100 Main St"``<br />}<br />};<br />Object.freeze(person);<br />复制代码<br />A:person.name = “Evan Bacon”<br />B:delete person.address<br />C:person.address.street = “101 Main St”<br />D:person.pet = { name: “Mara” }<br />答案 <br />答案: C<br />使用方法Object.freeze对一个对象进行 _冻结_。不能对属性进行添加,修改,删除。 然而,它仅 对对象进行 _浅_冻结,意味着只有 对象中的 _直接_属性被冻结。如果属性是另一个 object,像案例中的address,address中的属性没有被冻结,仍然可以被修改。<br />138. 以下哪一项会对对象person有副作用?<br />constperson = {<br />name:"Lydia Hallie",<br />address: {<br />street:"100 Main St"``<br />}<br />};<br />Object.freeze(person);<br />复制代码<br />A:person.name = “Evan Bacon”<br />B:delete person.address<br />C:person.address.street = “101 Main St”<br />D:person.pet = { name: “Mara” }<br />答案 <br />答案: C<br />使用方法Object.freeze对一个对象进行 _冻结_。不能对属性进行添加,修改,删除。 然而,它仅 对对象进行 _浅_冻结,意味着只有 对象中的 _直接_属性被冻结。如果属性是另一个 object,像案例中的address,address中的属性没有被冻结,仍然可以被修改。<br />139. 输出什么?<br />constadd =x =>x + x;<br />function myFunc(num = 2, value = add(num)){<br />console.log(num, value);<br />}<br />myFunc();<br />myFunc(3);<br />复制代码<br />A:24` and `3` `6`<br />B: `2NaNand3`NaN
C:2``Errorand36
D:2``4and3Error
答案
答案: A
首先我们不传递任何参数调用myFunc()。因为我们没有传递参数,num和value获取它们各自的默认值:num 为2, 而value为函数add的返回值。对于函数add,我们传递值为2的num作为参数。函数add返回4作为value的值。 然后,我们调用myFunc(3)并传递值3参数num的值。我们没有给value传递值。因为我们没有给参数value传递值,它获取默认值:函数add的返回值。对于函数add,我们传递值为3的num给它。函数add返回6作为value的值。
140. 输出什么?class Counter {#number = 10increment() {this.#number++}getNum() {return this.#number}}const counter = new Counter()counter.increment()console.log(counter.#number)
复制代码
A:10
B:11
C:undefined
D:SyntaxError
答案
答案: D
在 ES2020 中,通过#我们可以给 class 添加私有变量。在 class 的外部我们无法获取该值。当我们尝试输出counter.#number,语法错误被抛出:我们无法在 classCounter外部获取它!
141. 选择哪一个?
constteams = [{name:“Team 1”,members: [“Paul”,“Lisa”] },{name:“Team 2”,members: [“Laura”,“Tim”] }];
function getMembers(members){`for(leti =0; i < members.length; i++) {<br />yieldmembers[i];<br />}<br />}`
function getTeams(teams){`for(leti =0; i < teams.length; i++) {<br />// ✨ SOMETHING IS MISSING HERE ✨``<br />}<br />}<br />constobj = getTeams(teams);<br />obj.next();// { value: "Paul", done: false }``<br />obj.next();// { value: "Lisa", done: false }``<br />复制代码<br />A:yield getMembers(teams[i].members)<br />B:yield getMembers(teams[i].members)<br />C:return getMembers(teams[i].members)<br />D:return yield getMembers(teams[i].members)<br />答案 <br />答案: B<br />为了遍历teams数组中对象的属性members中的每一项,我们需要将teams[i].members传递给 Generator 函数getMembers。Generator函数返回一个 generator 对象。为了遍历这个generator 对象中的每一项,我们需要使用yield. 如果我们没有写yield,return yield或者return,整个Generator 函数不会第一时间 return 当我们调用next方法.<br />142. 输出什么?<br />constperson = {<br />name:"Lydia Hallie",<br />hobbies: ["coding"]<br />};<br />function addHobby(hobby, hobbies = person.hobbies){<br />hobbies.push(hobby);<br />returnhobbies;<br />}<br />addHobby("running", []);<br />addHobby("dancing");<br />addHobby("baking", person.hobbies);<br />console.log(person.hobbies);<br />复制代码<br />A:[“coding”]<br />B:[“coding”, “dancing”]<br />C:[“coding”, “dancing”, “baking”]<br />D:[“coding”, “running”, “dancing”, “baking”]<br />答案 <br />答案: C<br />函数addHobby接受两个参数,hobby和有着对象person中数组hobbies默认值的hobbies。 首相,我们调用函数addHobby,并给hobby传递“running”以及给hobbies传递一个空数组。因为我们给hobbies传递了空数组,“running”被添加到这个空数组。 然后,我们调用函数addHobby,并给hobby传递“dancing”。我们不向hobbies传递值,因此它获取其默认值 —— 对象person的 属性hobbies。我们向数组person.hobbiespushdancing。 最后,我们调用函数addHobby,并向hobby传递 值“bdaking”,并且向hobbies传递person.hobbies。我们向数组person.hobbiespushdancing。pushingdancing和baking之后,person.hobbies的值为[“coding”, “dancing”, “baking”]<br />143. 输出什么?<br />class Bird{<br />constructor() {<br />console.log("I'm a bird. 🦢");<br />}<br />}<br />class Flamingo extends Bird{<br />constructor() {<br />console.log("I'm pink. 🌸");<br />super();<br />}<br />}<br />constpet =newFlamingo();<br />复制代码<br />A:I’m pink.🌸`<br />B: `I'm pink.🌸`I'm a bird. ``🦢
C:I'm a bird. ``🦢I'm pink. ``🌸
D: Nothing, we didn’t call any method
答案
答案: B
我们创建了类Flamingo的实例pet。当我们实例化这个实例,Flamingo中的constructor被调用。首相,输出"I'm pink. ``🌸``", 之后我们调用super()。super()调用父类的构造函数,Bird。Bird的构造函数被调用,并输出"I'm a bird. ``🦢``"。
144. 哪一个选项会导致报错?
constemojis = [“🎄”,“🎅🏼”,“🎁”,“⭐”];
/ 1 /emojis.push(“🦌”);
/ 2 /emojis.splice(0,2);
/ 3 /emojis = [...emojis,“🥂”];
/ 4 /emojis.length =0;
复制代码
A: 1
B: 1 and 2
C: 3 and 4
D: 3
答案
答案: Dconst关键字意味着我们不能 重定义变量中的值,它 仅可读。而然,值本身不可修改。数组emojis中的值可被修改,如 push 新的值, 拼接,又或者将数组的长度设置为0。
145. 我们需要向对象person添加什么,以致执行[...person]时获得形如["Lydia Hallie", 21]的输出?
constperson = {`name:"Lydia Hallie",<br />age:21``<br />}<br />[…person]// ["Lydia Hallie", 21]``<br />复制代码<br />A: 不需要,对象默认就是可迭代的<br />B:Symbol.iterator { for (let x in this) yield this[x] }<br />C:Symbol.iterator { for (let x in this) yield Object.values(this) }<br />D:Symbol.iterator { for (let x in this) yield this }<br />答案 <br />答案: C<br />对象默认并不是可迭代的。如果迭代规则被定义,则一个对象是可迭代的(An iterable is an iterable if the iterator protocol is present)。我们可以通过添加迭代器symbol[Symbol.iterator]来定义迭代规则,其返回一个 generator 对象,比如说构建一个 generator 函数Symbol.iterator {}。如果我们想要返回数组[“Lydia Hallie”, 21]:yield Object.values(this),这个 generator 函数一定要 yield 对象person的Object.values。<br />146. 输出什么?<br />letcount =0;<br />constnums = [0,1,2,3];<br /><br />nums.forEach(num =>{<br />if(num) count +=1``<br />})<br /><br />console.log(count)<br />复制代码<br />A: 1<br />B: 2<br />C: 3<br />D: 4<br />答案 <br />答案: C<br />forEach循环中的if条件检查num的值是真还是假。 由于nums数组中的第一个数字为0,即:伪造的值,因此if语句的代码块将不会执行。 对于nums数组中的其他3个数字,count只会增加,分别为1、2和3。 由于count被增加了13倍,因此count的值是3。<br />147. 输出什么?<br />function getFruit(fruits){<br />console.log(fruits?.[1]?.[1])<br />fruits?(console.log(.[1]);)<br />}<br /><br />getFruit([['🍊','🍌'], ['🍍']])<br />getFruit()<br />getFruit([['🍍'], ['🍊','🍌']])<br />复制代码<br />A:null,undefined, 🍌<br />B:[],null, 🍌<br />C:[],[], 🍌<br />D:undefined,undefined, 🍌<br />答案 <br />答案: D<br />“?”允许我们选择访问对象内更深层的嵌套属性。我们正在尝试将子项记录在fruits数组的索引“ 1”上的子数组中的索引“ 1”上。如果fruits数组中的索引1上的子数组不存在,它将简单地返回undefined。如果存在“水果”数组中索引“ 1”上的子数组,但是此子数组在其“ 1”索引上没有任何项,则它还将返回undefined。<br />首先,我们试图将第二项记录在[[['🍊','🍌'],['🍍']]]的['🍍']子数组中。此子数组仅包含一个项目,这意味着索引“ 1”上没有任何项目,并返回“ undefined”。
然后,我们在调用getFruits函数时未传递值作为参数,这意味着默认情况下,fruits的值为undefined。由于我们有条件地链接“水果”的索引“ 1”上的项目,因此它返回“未定义”,因为索引“ 1”上的该项目不存在。
最后,我们尝试将第二项记录在['``🍍``']``,['``🍊``'``,'``🍌``']的['``🍊``'``,'``🍌``']子数组中。该子数组中索引“ 1”上的项是“🍌”,将其记录下来。
148. 输出什么?
class Calc{`constructor() {<br />this.count =0<br />}<br /><br />increase() {<br />this.count ++<br />}<br />}<br /><br />constcalc =newCalc()<br />newCalc().increase()<br /><br />console.log(calc.count)<br />复制代码<br />A:0<br />B:1<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: A<br />我们将变量calc设置为等于Calc类的新实例。 然后,我们实例化一个新的Calc实例,并对该实例调用increase方法。 由于count属性位于Calc类的构造函数中,因此count属性不会在Calc的原型上共享。 这意味着对于calc所指向的实例,count的值尚未更新,count仍为0。<br />149. 输出什么?<br />constuser = {<br />email:"e@mail.com",<br />password:"12345"``<br />}<br /><br />constupdateUser =({ email, password }) =>{<br />if(email) {<br />Object.assign(user, { email })<br />}<br /><br />if(password) {<br />user.password = password<br />}<br /><br />returnuser<br />}<br /><br />constupdatedUser = updateUser({email:"new@email.com"})<br /><br />console.log(updatedUser === user)<br />复制代码<br />A:false<br />B:true<br />C:TypeError<br />D:ReferenceError<br />答案 <br />答案: B<br />如果将用户的“ email”和“ password”属性的值传递给函数,则“ updateUser”函数将其值更新,此后该函数将返回“ user”对象。 函数“ updateUser”的返回值是“ user”对象,这意味着updatedUser的值是对“ user”指向的同一“ user”对象的引用。 “ updatedUser === user”等于“ true”。<br />150. 输出什么?<br />constfruit = ['🍌','🍊','🍎']<br /><br />fruit.slice(0,1)<br />fruit.splice(0,1)<br />fruit.unshift('🍇')<br />复制代码<br />A:[‘🍌‘, ‘🍊‘, ‘🍎‘]<br />B:[‘🍊‘, ‘🍎‘]<br />C:[‘🍇‘, ‘🍊‘, ‘🍎‘]<br />D:[‘🍇‘, ‘🍌‘, ‘🍊‘, ‘🍎‘]<br />答案 <br />答案: C<br />首先,我们在fruit数组上调用slice方法。 slice方法不会修改原始数组,但会返回从数组中切出的值:香蕉表情符号。 然后,我们在fruit数组上调用splice方法。 拼接方法确实修改了原始数组,这意味着fruit数组现在由[[🍊],'🍎']`组成。 最后,我们在“fruit”数组上调用“ unshift”方法,该方法通过添加提供的值“🍇”作为数组中的第一个元素来修改原始数组。 水果数组现在由“ `["🍇”,“🍊”,“🍎”]`组成。<br />151. 输出什么?<br />const` animals = {};`<br />let` dog = { `emoji`: `'🐶'` }`<br />let` cat = { `emoji`: `'🐈'` }`<br />` `<br />`animals[dog] = { ...dog, `name`: `"Mara"` }`<br />`animals[cat] = { ...cat, `name`: `"Sara"` }`<br />` `<br />console`.log(animals[dog])`<br />复制代码<br />A: `{ emoji: "🐶", name: "Mara" }`<br />B: `{ emoji: "🐈", name: "Sara" }`<br />C: `undefined`<br />D: `ReferenceError`<br />答案 <br />答案: B<br />对象键将转换为字符串。<br />由于“ dog”的值是一个对象,因此“ animals [dog]”实际上意味着我们正在创建一个名为““ Object Object””的新属性,该属性等于新对象。 “ animals [“ object Object”]]现在等于`{emoji:“🐶”`,名称:“ Mara”}。
“ cat”也是一个对象,这意味着“ animals [cat]”实际上意味着我们正在使用新的cat属性覆盖“ animals [“” object Object“”“]]的值。
因为将dog对象转换为字符串结果“ object Object”,所以记录animals [dog]或实际上是“ animals [” object Object“]都会返回{emoji:”🐈“,名称:” Sara”}。<br />152. 输出什么?<br />constuser = {<br />email:"my@email.com",<br />updateEmail:email =>{<br />this.email = email<br />}<br />}<br /><br />user.updateEmail("new@email.com")<br />console.log(user.email)<br />复制代码<br />A:my@email.com<br />B:new@email.com<br />C:undefined<br />D:ReferenceError<br />答案 <br />答案: A<br />updateEmail函数是一个箭头函数,未绑定到user对象。 这意味着关键字“ this”不是在引用“ user”对象,而是在这种情况下引用了全局范围。 用户对象内的电子邮件值不会被更新。 记录“ user.email”的值时,将返回“ my@email.com”的原始值。<br />153. 输出什么?<br />constpromise1 =Promise.resolve('First')<br />constpromise2 =Promise.resolve('Second')<br />constpromise3 =Promise.reject('Third')<br />constpromise4 =Promise.resolve('Fourth')<br /><br />construnPromises =async() => {<br />constres1 =awaitPromise.all([promise1, promise2])<br />constres2 =awaitPromise.all([promise3, promise4])<br />return[res1, res2]<br />}<br /><br />runPromises()<br />.then(res =>console.log(res))<br />.catch(err =>console.log(err))<br />复制代码<br />A:[[‘First’, ‘Second’], [‘Fourth’]]<br />B:[[‘First’, ‘Second’], [‘Third’, ‘Fourth’]]<br />C:[[‘First’, ‘Second’]]<br />D:‘Third’<br />答案 <br />答案: D<br />Promise.all方法并行运行传递的promise。 如果一个Promise失败,则Promise.all方法(_rejects)带有rejected的promise的值。 在这种情况下,“ promise3”reject返回了“Third”。 我们正在对runPromises调用进行链接的catch方法中捕获被拒绝的值,以捕获runPromises函数中的所有错误。 因为promise3拒绝了这个值,所以只有Third被记录。<br />154.当method是下列选项中的那项的时候,将会输出{ name: “Lydia”, age: 22 }?<br />constkeys = ["name","age"]<br />constvalues = ["Lydia",22]<br /><br />constmethod = `/ ?? /<br />Object`[method](keys.map(`(_, i) =>` {`<br />` `return`[keys[i], values[i]]`<br />`})) `// { name: "Lydia", age: 22 }
复制代码
A:entries
B:values
C:fromEntries
D:forEach
答案
答案: C
fromEntries方法将二维数组转换为对象。 每个子数组中的第一个元素将是键,每个子数组中的第二个元素将是值。 在这种情况下,我们将在“ keys”数组上进行映射,该数组将返回一个数组,其中第一个元素是当前索引上的键数组的项目,第二个元素是当前索引上的值数组的项目。
这将创建一个包含正确键和值的子数组数组,从而导致{name:“ Lydia”,age:22}<br />155. 输出什么?<br />constcreateMember =({ email, address = {}}) =>{<br />constvalidEmail =/.+\@.+\..+/.test(email)<br />if(!validEmail)thrownewError("Valid email pls")<br /><br />return{<br />email,<br />address: address ? address :null``<br />}<br />}<br /><br />constmember = createMember({email:"my@email.com"})<br />console.log(member)<br />复制代码<br />A:{ email: “my@email.com”, address: null }<br />B:{ email: “my@email.com” }<br />C:{ email: “my@email.com”, address: {} }<br />D:{ email: “my@email.com”, address: undefined }<br />答案 <br />答案: C<br />“address”的默认值是一个空对象“ {}”。 当我们将变量member设置为等于createMember函数返回的对象时,我们没有传递address的值,这意味着address的值是默认的空对象{}。 空对象是真实值,这意味着“address? address:null,条件返回“ true”。 address的值为空对象“ {}”。
156. 输出什么?
letrandomValue = {name:“Lydia”}randomValue =23`<br /><br />if(!typeofrandomValue ==="string") {<br />console.log("It's not a string!")<br />}else{<br />console.log("Yay it's a string!")<br />}<br />复制代码<br />A:It’s not a string!<br />B:Yay it’s a string!<br />C:TypeError<br />D:undefined<br />答案 <br />答案: B<br />“ if”语句中的条件检查“!typeof randomValue”的值是否等于““ string””。 “!”运算符将值转换为布尔值。 如果值为真,则返回的值为“ false”;如果值为虚假,则返回的值为“ true”。 在这种情况下,“ typeof randomValue”的返回值是真实值““ string””,这意味着“!typeof randomValue”的值是布尔值“ false”。<br />!! typeof randomValue ===“ string”总是返回false,因为我们实际上是在检查“ false ===” string“`。 由于条件返回了“ false”,因此将运行“ else”语句的代码块,并记录“是的,是字符串!”。
Q:什么情况下会碰到跨域问题?有哪些解决方法?
跨域问题是这是浏览器为了安全实施的同源策略导致的,同源策略限制了来自不同源的document、脚本,同源的意思就是两个URL的域名、协议、端口要完全相同。
script标签jsonp跨域、nginx反向代理、node.js中间件代理跨域、后端在头部信息设置安全域名、后端在服务器上设置cors。
Q:如何判断一个变量是对象还是数组?
判断数组和对象分别都有好几种方法,其中用prototype.toString.call()兼容性最好。
function isObjArr(value){
if (Object.prototype.toString.call(value) === “[object Array]”) {
console.log(‘value是数组’);
}else if(Object.prototype.toString.call(value)===’[object Object]’){//这个方法兼容性好一点
console.log(‘value是对象’);
}else{
console.log(‘value不是数组也不是对象’)
}
}
复制代码
ps:千万不能使用typeof来判断对象和数组,因为这两种类型都会返回”object”。
Q:定时器的执行顺序或机制。
这个问题还是挺经常被问到的,有一些会直接问定时器的机制,有一些是通过笔试题的方式问执行顺序然后问我为什么是这样。
长话短说,我们需要记住的是:因为js是单线程的,浏览器遇到setTimeout或者setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行事件队列里面,等到浏览器执行完当前代码之后会看一下事件队列里面有没有任务,有的话才执行定时器的代码。 所以即使把定时器的时间设置为0还是会先执行当前的一些代码。
上面是我写的一个栗子,如果还不清楚的话,可以看一下我之前写的这篇Js 的事件循环(Event Loop)机制以及实例讲解。
Q:html中title属性和alt属性的区别?
这个问题被问了一次,当时我只记得,alt属性是用于img标签的,当图片失效的时候会出现alt属性里面的内容,title用来标记页面的title,当时面试官问我还有没有其他的区别。我。。。
然后我就找了一篇文章来看,涨了点姿势:
1.
//1.当图片不输出信息的时候,会显示alt信息 鼠标放上去没有信息,当图片正常读取,不会出现alt信息
2.
// 2.当图片不输出信息的时候,会显示alt信息 鼠标放上去会出现title信息
//当图片正常输出的时候,不会出现alt信息,鼠标放上去会出现title信息
复制代码
另外还有一些关于title属性的知识:
title属性可以用在除了base,basefont,head,html,meta,param,script和title之外的所有标签
title属性的功能是提示。额外的说明信息和非本质的信息请使用title属性。title属性值可以比alt属性值设置的更长
title属性有一个很好的用途,即为链接添加描述性文字,特别是当连接本身并不是十分清楚的表达了链接的目的。
复制代码
Q:标准盒子模型与IE怪异盒子模型
这个问题主要会出现在笔试题上面,比如:
<div style=”width:100px;height=”100px;border:10px;padding:10px;”>
复制代码
这个盒子在w3c标准盒子模型和IE的怪异盒子模型下面它的宽度分别是多少?
标准盒子模型:总宽度=content100px+border 10px2+padding 10px2 //140px
怪异盒子模型: 总宽度=content60px+ border 10px2+padding 10px2 //100px
复制代码
ps:
box-sizing:content-box || border-box;//css3 box-sizing设置为border-box将使用怪异盒子模型
当怪异盒子的宽度小于border+padding的宽度的时候,content width将变为0,盒子的宽度会被border和padding的总宽度撑开
复制代码
ES5的继承和ES6的继承有什么区别?
ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。
ES6的继承机制完全不同,*实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。
ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。
Q:CSS3有哪些新增的属性?
这里可以分为边框、背景,渐变,阴影、2D转换 3D转换等之类的来说。
比如:边框(border-radius、border-shadow、border-image)之类的 。
复制代码
具体的可以参见菜鸟教程:链接。类似的镜像问题还有HTML5的新增属性,可以自己谷歌一下。
Q:你知道哪些http状态码?
1xx:1开头的是信息状态码
2xx:2开头的是请求成功
3xx:3开头的是重定向
4xx:4开头的是客户端错误
5xx:5开头的是服务器错误
复制代码
这个问题并不难,在笔试面试都有碰到过,巧的是之前我就总结过一篇类似的文章。
Q:如何对一个数组去重?
这个问题出现了好几次,而且很多面试官不满足你只给出一两种方法。
1、Set结构去重。
这是ES6 提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
let unique= […new Set(array)];
//es6 Set数据结构类似于数组,成员值是唯一的,有重复的值会自动去重。
//Set内部使用===来判断是否相等,类似’1’和1会两个都保存,NaN和NaN只会保存一个
复制代码
2、遍历,将值添加到新数组,用indexOf()判断值是否存在,已存在就不添加,达到去重效果。
let a = [‘1’,’2’,’3’,1,NaN,NaN,undefined,undefined,null,null, ‘a’,’b’,’b’];
let unique= arr =>{
let newA=[];
arr.forEach(key => {
if( newA.indexOf(key)<0 ){ //遍历newA是否存在key,如果存在key会大于0就跳过push的那一步
newA.push(key);
}
});
return newA;
}
console.log(unique(a)) ;//[“1”, “2”, “3”, 1, NaN, NaN, undefined, null, “a”, “b”]
//ps:这个方法不能分辨NaN,会出现两个NaN。是有问题的,下面那个方法好一点。
复制代码
3、遍历,将数组的值添加到一个对象的属性名里,并给属性赋值,对象不能添加相同属性名,以这个为依据可以实现数组去重,然后用Object.keys(对象)返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组。
let a = [‘1’, ‘2’, ‘3’, 1,NaN,NaN,undefined,undefined,null,null, ‘a’, ‘b’, ‘b’];
const unique = arr => {
var obj = {}
arr.forEach(value => {
obj[value] = 0;//这步新添加一个属性,并赋值,如果不赋值的话,属性会添加不上去
})
return Object.keys(obj);//
Object.keys(对象)返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组}
console.log(unique(a));//[“1”, “2”, “3”, “NaN”, “undefined”, “null”, “a”, “b”]
复制代码
注意:
这个方法会将 number,NaN,undefined,null,变为字符串形式,因为对象的属性名就是一个字符串,根据需求来吧,想想还是Set去重最简单也最有效。
Q:垂直居中有哪些方法?
单行文本的话可以使用height和line-height设置同一高度。
position+margin:设置父元素:position: relative;,子元素height: 100px; position:absolute;top: 50%; margin: -50px 0 0 0;(定高)
position+transform:设置父元素position:relative,子元素:position: absolute;top: 50%;transform: translate(0, -50%);(不定高)
百搭flex布局(ie10+),设置父元素display:flex;align-items: center;(不定高)
类似的还有很多,实际应用中,可能就会使用一两种方法,有兴趣的可以看下这篇文章
Q:翻转一个字符串
这个问题主要在笔试题碰到的多,思路就是先将字符串转成一个数组,然后用数组的reverse()+join()方法。
let str=”hello word”;
let b=[…str].reverse().join(“”);//drow olleh
Q:了解ES6的let和const变量声明吗?跟ES5的var有哪些区别?
let
在同一个作用域里面:var可以重复声明变量,let不能重复声明同一个变量。
es5是函数作用域,即一个函数里面才是一个作用域,es6是块级作用域(花括号’{这里面是一个作用域}’),如:if、for花括号里面都是一个作用域。
var有变量提升,可以在变量声明之前使用,let不存在变量提升,在变量之前使用会报错。
let 有暂时性死区,阮一峰大佬es6入门文档解释如下:
const
const的很多特性跟let的特性一样,都有:不可重复声明,不存在变量提升,有暂时性死区,都是块级作用域。
还有一些跟let命令不一样的地方:const必须在声明的时候赋值,不然就会报错。const声明的常量不能更改。
这里的常量指的是:数值、字符串、布尔值,对于引用类型(数组和对象),const只能保证指针是固定的,至于数组和对象内部有没有改变就是const不能控制的地方
Q:Css的优先级。
这类也通常出现在笔试题中,具体的题目记不太清了。权重优先级:!important>style(1000)>id(100)>class(10)!important``是优先级最高的不管权重多少,始终采取important。如果两个选择器作用在同一元素上,计算权重值,相加。权重高者属性生效。(笔试题就出现过层叠的class id选择器,作用在同一个标签上,然后问最后哪个css属性生效)
复制代码
有兴趣的可以看一下我写的你对CSS权重真的足够了解吗
Q:继承函数对象的实例方法、原型的继承。
函数对象的继承,在面试的时候,一般出现在笔试题那边,也碰到过几次,下面给出一个答案。function father(name){//``父函数this.name=name|'koro1';this.code=function(){ //``父类的实例方法console.log(this.name+'coding');}};father.prototype.add=function(food){ //``父类的原型方法console.log(this.name+'eat'+food);}function son(name){ //``子函数father.call(this); //``将this绑定到子类,绑定父类的实例方法code(原型方法add还未绑定)this.name=name|| 'OBKoro1';}son.prototype = new father();//``把父类的原型方法绑定到子类,实现继承var sonVar= new son('faker');//``这里也可以传参nameson.prototype.constructor = son;//``修复构造函数的指向console.log(sonVar.code());console.log(sonVar.add());//``可以调用父类的方法了
复制代码
Q:通过reduce函数来实现简单的数组求和,示例数组[3,4,8,0,9];
这是一个简单的笔试题,下面写了两种方法,一种是常见遍历的方法,还有一种是使用eval()方法。let reduce=(arr)=>{ //``第一种常规遍历。let num=0;for(let [index,value] of arr.entries()){num+=value;}return num;}let reduce=(arr)=>eval(arr.join("+")); //``第二种//join() ``方法把数组元素放入字符串 上面的栗子:arr.join("+")得到字符串:'3+4+8+0+9';// eval() ``函数计算字符串 ,并执行其中的的 JavaScript 代码//``经提醒:原来有一个reduce()数组求和的方法,把这个方法加上去let result=[3,4,8,0,9].reduce((total,value)=>{ //``这两个参数是默认参数不用设置的return total+value});
复制代码
Q:call()和apply()有什么区别?
call()和apply()第一个参数将用作函数内 this 的值,用于改变函数的this指向。call和apply的区别在于call()方法接受逗号分隔的参数作为后面的参数,apply()接受一个参数数组作为后面的参数。从别的博客那边看到一个简单的记忆方法:从call中的 C 联想到逗号分隔(comma-separated),从apply中的 A 联想到数组(array)。
复制代码
Q:position有哪些值?有什么作用?
static。默认值,不脱离文档流,top,right,bottom,left等属性不生效。
relative。不脱离文档流,依据自身位置进行偏离,当子元素设置absolute,将依据它进行偏离。
absolute。脱离文档流,依据top,right,bottom,left等属性在正常文档流中偏移位置。
fixed。通过浏览器窗口进行定位,出现滚动条的时候,不会随之滚动。
Q:如何实现一个闭包?闭包的作用有哪些?
在一个函数里面嵌套另一个函数,被嵌套的那个函数的作用域是一个闭包。
作用:创建私有变量,减少全局变量,防止变量名污染。可以操作外部作用域的变量,变量不会被浏览器回收,保存变量的值。
Q:请从2017-05-15T09:10:23 Europe/Paris提取出结果["2017","05","15","09","10","23"]
这是一道笔试题,正则相关的,看他们要的内容就可以知道,要把所有的数字都提取出来,可以写一个只获取数字的正则表达式。let str = '2017-05-15T09:10:23 Europe/Paris';let arr = str.match( /\d{1,}/g);//match``会返回一个数组,// \d ``查找数字// {1,} ``表示至少重复几次// /g``表示全局搜索
复制代码
Q:请描述一下Promise的使用场景,’Promise’它所解决的问题以及现在对于异步操作的解决方案。
这是一道笔试题,这是我当时的回答。
Promise的使用场景:ajax请求,回调函数,复杂操作判断。
Promise是ES6为了解决异步编程所诞生的。
异步操作解决方案:Promise、Generator、定时器(不知道算不算)、还有ES7的async
面试遇到的一些小问题:
这里主要是面试中遇到的一些小的问题,一两句话就可以说清的东西,大家可以稍微看一看。
函数参数变量提升function aa(val){ //``函数参数的变量也会提升console.log(val);//'``函数传参'var val='``变量声明';console.log(val);//'``变量声明'}aa('``函数传参');
复制代码
js有哪些方法定义对象?var obj=new Object();//new ``一个对象var obj={name:"OBKoro1"} //``对象字面量写法
复制代码
字符串数字转换运算的问题console.log(1+'2'+'2'); //122console.log(+'1'+-'2'+'2');//-12console.log('A'+'B'+'2');//AB2console.log('A'-'B'+2);//NaN//``两个都是数字才能相加,否则都是以字符串形式拼接。//``相减只能两个都是数字,字符串也会转成数字,如果不能转换,值就为NaN
复制代码
split()、join()的区别?split()``是将字符分割成一个数组,join()将数组转为一个字符串
复制代码
pop()push()unshift()shift()的作用?pop()``删除并返回数组的最后一个元素。push()``可向数组的末尾添加一个或多个元素,并返回新的长度。unshift() ``方法可向数组的开头添加一个或更多元素,并返回新的长度。shift() ``方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
复制代码
判断一个数是否是整数function isIntefer(x){return x%1===0; //``返回布尔}
复制代码
如何将字符串转为数字,如:12.3b?var num=parseFloat('12.3b')
复制代码
什么是外边距合并?
当两个垂直外边距相遇时,它们将形成一个外边距,合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
Q:你常用的git/svn 命令行有哪些?行内元素有哪些,块状元素有哪些?css有哪些选择器?``自行谷歌,类似的还有css3新增的属性,H5新增的属性之类的,有空的话,稍微背一背,都碰到过。
复制代码
Vue系列问题:
我在面试过程中很少被问到框架,很多是在笔试题中碰到的,在介绍自己项目的时候,有时候自己会解释这里用到了Vue的什么技术,这个时候面试官可能就会顺着问一问Vue,总的来说问的也不会太深。
以下是笔试真题:
vue-router怎么定义动态路由?怎么获取传过来的动态参数?``定义:path:'a/:value' 获取:this.$route.params.value。
复制代码
说出至少4中vue当中的指令和它的用法。vue文档显示13个指令
vue如何绑定事件。@click="``事件名"
v-show和v-if指令的共同点和不同点?1.v-if``是删除/添加Dom标签,不占据文档位置,v-show切换css的display属性,控制显示隐藏,还会占据文档位置。2.v-if``会删除dom标签所以v-if性能消耗会高一些,需要频繁切换的话,使用v-show会好一点。
复制代码<keep-alive></keep-alice>的作用的是什么?`<keep-alive>```是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
复制代码
列举三个Vue常用的生命周期钩子函数?Vue文档
分别写出webpack打包给服务器和本地开发预览的命令代码:npm run build npm run dev ``我都觉得很弱智。。
复制代码
vue 父子组件是怎么进行传参的?``父组件传参给子组件通过props,子组件传参给父组件是用事件传递的。细节见文档。
复制代码
v-model是用来做什么的,怎么使用。``用来为input输入框或者单选框、select选择框这类的东西做双向绑定的。``使用栗子:<input v-model="inputData"/>
复制代码
vuex的工作流程:
1、在vue组件里面,通过dispatch来触发actions提交修改数据的操作。
2、然后再通过actions的commit来触发mutations来修改数据。
3、mutations接收到commit的请求,就会自动通过Mutate来修改state(数据中心里面的数据状态)里面的数据。
4、最后由store触发每一个调用它的组件的更新
Vuex的作用:项目数据状态的集中管理,复杂组件(如兄弟组件、远房亲戚组件)的数据通信问题。
vue的服务端渲染
vue的双向绑定
正题
第 1 题
if(false){var a = 1;`let b = 2;<br />}<br />console.log(a);<br />console.log(b);<br />复制代码<br />查看解析 <br />// `输出undefined`<br />ReferenceError: b is not defined<br />复制代码<br />var不会产生块级作用域,let会产生块级作用域。<br />伪代码相当于:<br />var a;<br />if(false){<br /> a = 1;<br /> let b = 2;<br />}<br />console.log(a);<br />console.log(b);`
复制代码
第 2 题var a = 1;
if(true){console.log(a);`let a = 2;<br />}<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`ReferenceError: Cannot access `'a'` before initialization`<br />` `<br />复制代码<br />`let`声明的变量不会提升,并且会产生暂存死区。在`let`声明变量之前访问变量会抛出错误。<br />第 3 题<br />`var a = {n: 1}`<br />`var b = a`<br />`a.x = a = {n: 2}`<br />` `<br />`console.log(a.n, b.n);`<br />`console.log(a.x, b.x);`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />2 1<br /> <br />undefined {n: 2}<br /> <br />复制代码<br /> <br />var b = a,此时a和b指向同一个对象。`<br />` `<br />`.运算符比 = 运算符高,先计算a.x,此时 <br />b = {<br /> n:1,<br /> x:undefined<br />}<br /> <br />相当于给对象添加了x属性。<br /> <br />a.x = a = {n:2};<br /> <br />计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。<br />a = {<br /> n:2<br />}<br /> <br />a.x已经执行过了,此时对象的x属性赋值为a,此时`<br />` `<br />`对象 = {`<br />` n:1,`<br />` x:{`<br />` n:2`<br />` }`<br />`}`<br />` `<br />`即:`<br />`a = {`<br />` n:2`<br />`}`<br />` `<br />`b = {`<br />` n:1,`<br />` x:{`<br />` n:2`<br />` }`<br />`}`<br />` `<br />复制代码<br />[查看运算符优先级](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)<br />第 4 题<br />`console.log(c);`<br />`var c;`<br />function` c(a) {`<br />` console.log(a);`<br />` var a = 3;`<br />` `function` `a`(){`<br />` }`<br />`}`<br />`c(2);`<br />复制代码<br />查看解析 <br />`//输出 <br /> <br />function c(a){<br /> console.log(a);<br /> var a = 3;<br /> function a(){<br /> }<br />}<br /> <br />function a(){<br />}<br />复制代码<br />变量提升也有优先级, 函数声明> arguments > 变量声明<br />第 5 题<br />var c = 1;<br />function c(c) {<br /> console.log(c);<br /> var c = 3;<br />}<br />console.log(c);<br />c(2);<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`1`<br />` `<br />`TypeError: c is not a `function`<br />复制代码<br />由于函数声明会提升,当函数外的console.log(c)执行时,c已经被赋值为1。因此,执行c(2)时会抛出TypeError,因为1不是函数。<br />第 6 题<br />var name = 'erdong';<br />(function () {<br /> if (typeof name === 'undefined') {<br /> var name = 'chen';<br /> console.log(name);<br /> } else {<br /> console.log(name);<br /> }<br />})();<br />复制代码<br />查看解析 <br />// 输出 `<br />` `<br />`chen`<br />` `<br />复制代码<br />自执行函数执行时,会先进行变量提升(_这里涉及到执行上下文不过多说,一定要搞懂执行上下文_),在自执行函数执行时,伪代码为:<br />`var name = `'erdong'`;`<br />`(`function` () {`<br />` var name; //变量name会提升到当前作用域顶部<br /> if (typeof name === 'undefined') {<br /> name = 'chen'``<br /> console.log(name)<br /> } else {<br /> console.log(name)<br /> }<br />})();<br /> <br />复制代码<br />所以会执行if中的console.log(name)<br />第 7 题<br />var a = 10; <br />function test() { <br /> a = 100; <br /> console.log(a); <br /> console.log(this.a); <br /> var a; <br /> console.log(a); <br />}<br />test(); <br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`100`<br />`10`<br />`100`<br />复制代码<br />`test()`为函数独立调用,作用域中的`this`绑定为全局对象`window`。<br />`test`函数执行时,`var a`被提升到了作用域顶部,因此函数作用域中存在一个变量`a`。所以在函数中访问的`a`都是局部作用域中的`a`。<br />第 8 题<br />if` (!(`'a'` `in` window)) {`<br />` var a = 1;`<br />`}`<br />`console.log(a);`<br />复制代码<br />查看解析 <br />`//输出<br />undefined<br />复制代码<br />由于if后的{}不会产生块级作用域(不包含let,const时),此时的伪代码为:<br />var a;<br />if (!(a inwindow)) {<br /> a = 1;<br />}<br />console.log(a);<br />复制代码<br />var a相当于window.a。因此!(a in window)转成布尔值为false,不会执行a = 1。所有console.log(a)输出undefined。<br />第 9 题<br />var a = 1;<br /> <br />function c(a, b) {<br /> console.log(a);<br /> a = 2;<br /> console.log(a);<br />}<br />c();<br />复制代码<br />查看解析 <br />//输出`<br />` `<br />`undefined`<br />` `<br />`2`<br />复制代码<br />跟第4题类似。<br />第 10 题<br />`var val=1;`<br />`var obj={`<br />` val:2,`<br />` del:`function`(){`<br />` console.log(this); `<br />` this.val*=2;`<br />` console.log(val);`<br />` }`<br />`}`<br />` `<br />`obj.del();`<br />复制代码<br />查看解析 <br />`//输出<br />obj(指向的值)`<br />` `<br />`1`<br />` `<br />复制代码<br />当通过`obj.del()`调用`del`函数时,`del`函数作用域中的`this`绑定为`obj`。<br />在函数作用域中访问`val`时,由于函数中并没有变量`val`,因此实际上访问的是全局作用域中的`val`,即 `1`。<br />这里考察的是`this`的指向,一定要熟练掌握。<br />第 11 题<br />`var name = `"erdong"`;`<br />`var object = {`<br />` name: `"chen"`,`<br />` getNameFunc: `function` () {`<br />` `return` `function` () {`<br />` `return` this.name;`<br />` }`<br />` }`<br />`}`<br />`console.log(object.getNameFunc()());`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />erdong<br />复制代码<br />object.getNameFunc()(),先执行object.getNameFunc()返回一个函数:<br />function () {<br /> returnthis.name;<br />}<br />复制代码<br />返回的函数再执行,相当于<br />(function () {<br /> returnthis.name;<br />})();<br />复制代码<br />此时的this绑定为window。因此输出全局变量name的值erdong。<br />第 12 题<br />var name = "erdong";<br />var object = {<br /> name: "chen",<br /> getNameFunc: function () {<br /> var that = this;<br /> return function () {<br /> return that.name;<br /> }<br /> }<br />}<br />console.log(object.getNameFunc()());<br /> <br />复制代码<br />查看解析 <br />//输出`<br />` `<br />`chen`<br />复制代码<br />`object.getNameFunc()`执行时,此时`getNameFunc`中的`this`绑定为`object`,因此`that = object`。`object.getNameFunc()`返回的函数再执行时,产生闭包,因此返回的函数也能访问到外层作用域中的变量`that`,因此`object.name`为`object.name`,即`chen`。<br />第 13 题<br />`(`function`() {`<br />` var a = b = 3;`<br />`})();`<br />`console.log(typeof a === `'undefined'`);`<br />`console.log(typeof b === `'undefined'`);`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />true``<br /> <br />false``<br />复制代码<br />首先要明白var a = b = 3是怎样执行的,伪代码:<br />b = 3;<br />var a = b;<br />复制代码<br />因此在自执行函数执行时,b由于未经var等操作符声明,为全局变量。a为函数作用域中的局部变量。因此在外面访问a和b时,其值分别为ReferenceError: a is not defined和3。但是typeof检测未声明的变量不会抛出错误,会返回‘undefined’。因此typeof a和typeof b分别返回‘undefined’和‘number’<br />第 14 题<br />var a = 6;<br />setTimeout(function () {<br /> a = 666;<br />}, 0)<br />console.log(a);<br />复制代码<br />查看解析 <br />//输出`<br />` `<br />`6`<br />复制代码<br />`setTimeout`为宏任务。即使设置延迟为`0ms`,也是等待同步代码执行完才会执行。因此`console.log(a)`输出 `6`<br />第 15 题<br />function` `fn1`() {`<br />` var a = 2;`<br />` `function` `fn2` () {`<br />` a++;`<br />` console.log(a);`<br />` }`<br />` `return` fn2;`<br />`}`<br />`var f = fn1();`<br />`f();`<br />`f();`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />3<br />4<br />复制代码<br />由于fn1函数执行后返回函数fn2,此时产生了闭包。因此fn2中a访问的是fn1作用域中的变量a,因此第一次a++,之后a为3,第二次之后a为4。<br />第 16 题<br />var a = (function(foo){<br /> return typeof foo.bar;<br />})({foo:{bar:1}});<br /> <br />console.log(a);<br />复制代码<br />查看解析 <br />//输出`<br />` `<br />`undefined`<br />复制代码<br />实参`foo`的值为`{foo:{bar:1}`,因此`typeof foo.bar`为`undefined`。<br />`typeof foo.foo.bar`为`number`。<br />第 17 题<br />function` `f`(){`<br />` `return` f;`<br />`}`<br />`console.log(new f() instanceof f);`<br />` `<br />复制代码<br />查看解析 <br />`//输出<br /> <br />false``<br />复制代码<br />由于构造函数f的返回值为f。因此new f()的值为f。所以console.log(new f() instanceof f)为console.log(f instanceof f),即false。<br />第 18 题<br />function A () {<br />}<br />A.prototype.n = 1;<br /> <br />var b = new A();<br /> <br />A.prototype = {<br /> n: 2,<br /> m: 3<br />}<br />var c = new A();<br /> <br />console.log(b.n, b.m);<br />console.log(c.n, c.m);<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`1,undefined`<br />` `<br />`2,3`<br />` `<br />复制代码<br />`var b = new A();` 实例化`b`时,`A`的`prototype`为<br />`A.prototype = {`<br />` constructor:A,`<br />` n:1`<br />`}`<br />复制代码<br />当访问`b.n`和`b.m`时,通过原型链找到`A.prototype`指向的对象上,即`b.n = 1`,`b.m = undefined`。<br />`var c = new A();` 实例化`c`时,`A`的`prototype`为<br />`A.prototype = {`<br />` n: 2,`<br />` m: 3`<br />`}`<br />复制代码<br />当访问`a.n`和`a.m`时,通过原型链找到`A.prototype`指向的对象上,此时`A.prototype`重写,因此`a.n = 2`,`b.m = 3`。<br />第 19 题<br />`var F = `function`(){};`<br />`var O = {};`<br />`Object.prototype.a = `function`(){`<br />` console.log(`'a'`)`<br />`}`<br />`Function.prototype.b = `function`(){`<br />` console.log(`'b'`)`<br />`}`<br />`var f = new F();`<br />` `<br />`F.a(); `<br />`F.b(); `<br />`O.a();`<br />`O.b(); `<br />复制代码<br />查看解析 <br />`//输出<br /> <br />a<br />b<br />a<br />TypeError: O.b is not a function``<br /> <br />复制代码<br />F为函数,它也能访问Object原型上的方法,O为对象,不能访问Function原型上的方法。<br />F的原型链为:<br />F => F.proto => Function.prototype => Function.prototype.proto => Object.prototype<br />复制代码<br />由于Object.prototype在F的原型链上,所以F能访问Object.prototype上的属性和方法。即:F.a(),F.b()能正常访问。<br />O的原型链为:<br />O => O.proto => Object.prototype<br />复制代码<br />由于Function.prototype不在O的原型链上,因此O不能访问Function.prototype上的方法,即O.b()抛出错误。<br />如果你对原型和原型链掌握的好,试着理解下面的示例:<br />console.log(Object instanceof Function);<br /> <br />console.log(Function instanceof Object);<br /> <br />console.log(Function instanceof Function);<br /> <br />复制代码<br />第 20 题<br />function Person() {<br /> getAge = function () {<br /> console.log(10)<br /> }<br /> return this;<br />}<br /> <br />Person.getAge = function () {<br /> console.log(20)<br />}<br /> <br />Person.prototype.getAge = function () {<br /> console.log(30)<br />}<br /> <br />var getAge = function () {<br /> console.log(40)<br />}<br /> <br />function getAge() {<br /> console.log(50)<br />}<br /> <br /> <br />Person.getAge();<br />getAge();<br />Person().getAge();<br />new Person.getAge();<br />getAge();<br />new Person().getAge();<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`20`<br />`40`<br />`10`<br />`20`<br />`10`<br />`30`<br />复制代码<br />`Person.getAge();`此时执行的是`Person`函数上`getAge`方法。<br />`Person.getAge = `function` () {`<br />` console.log(20)`<br />`}`<br />复制代码<br />所以输出:20。<br />`getAge();`此时执行的是全局中的`getAge`方法。此时全局`getAge`方法为:<br />function` () {`<br />` console.log(40)`<br />`}`<br />复制代码<br />所以输出:40。<br />`Person().getAge();`由于`Person()`单独执行所以,作用域中的`this`绑定为`window`,相当于`window.getAge()`。同上,执行的都是全局`getAge` 方法,但是`Person`执行时,内部执行了<br />`getAge =`function` () {`<br />` console.log(10)`<br />`}`<br />复制代码<br />因此全局`getAge`方法现在为:<br />function` () {`<br />` console.log(10)`<br />`}`<br />复制代码<br />所以输出:10。<br />`new Person.getAge();`此时相当于实例化`Person.getAge`这个函数,伪代码:<br />`var b = Person.getAge;`<br />`new b();`<br />复制代码<br />所以输出:20<br />`getAge();`执行全局`getAge`方法,由于在`Person().getAge()`执行时把全局`getAge`方法赋值为:<br />function` () {`<br />` console.log(10)`<br />`}`<br />复制代码<br />所以输出:10。<br />`new Person().getAge();`此时调用的是`Person`原型上的`getAge`方法:<br />`Person.prototype.getAge = `function` () {`<br />` console.log(30)`<br />`}`<br />复制代码<br />所以输出:30。<br />这里要注意:1.变量提升及提升后再赋值。2.调用构造函数时,带`()`和不带`()`的区别。<br />第 21 题<br />`console.log(false.toString());`<br />`console.log([1, 2, 3].toString()); `<br />`console.log(1.toString());`<br />`console.log(5..toString());`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />'false'``<br />'1,2,3'``<br />Uncaught SyntaxError: Invalid or unexpected token<br />'5'``<br />复制代码<br />当执行1.toString();时,由于1.也是有效数字,因此此时变成(1.)toString()。没有用.调用toString方法,因此抛出错误。<br />正确的应该是:<br />1..toString();<br />1 .toString();<br />(1).toString();<br />复制代码<br />第 22 题<br />console.log(typeof NaN === 'number');<br />复制代码<br />查看解析 <br />//输出`<br />` `<br />true
复制代码NaN为不是数字的数字。虽然它不是数字,但是它也是数字类型。
第 23 题console.log(1 +“2”+“2”);`<br />console.log(1 + +"2" + "2");<br /> <br />console.log(1 + -"1" + "2");<br /> <br />console.log(+"1" + "1" + "2"); <br /> <br />console.log("A" - "B" + "2"); <br /> <br />console.log("A" - "B" + 2); <br />复制代码<br />查看解析 <br />//输出`<br />` `<br />'122'
‘32’<br />'02'
‘112’<br />'NaN2'NaN
复制代码
首先要明白两点:+a,会把a转换为数字。-a会把a转换成数字的负值(如果能转换为数字的话,否则为NaN)。
字符串与任何值相加都是字符串拼接。console.log(1 + "2" + "2");简单的字符串拼接,即结果为:'122'。console.log(1 + +"2" + "2");这里相当于console.log(1 + 2 + "2");,然后再字符串拼接。即结果为:'32'。console.log(1 + -"1" + "2");这里相当于console.log(1 + -1 + "2");,然后再字符串拼接。即结果为:'02'。console.log(+"1" + "1" + "2");这里相当于console.log(1 + "1" + "2");,然后再字符串拼接。即结果为:'112'。console.log( "A" - "B" + "2");,由于'A' - 'B' = NaN,所以相当于console.log( NaN + "2");, 然后再字符串拼接。即结果为:'NaN2'。console.log( "A" - "B" + 2);同上,相当于console.log(NaN + 2),由于NaN+任何值还是NaN,即结果为:NaN。
第 24 题var a = 666;console.log(++a);console.log(a++);console.log(a);
复制代码
查看解析 // ``输出`<br />667<br />667<br />668<br />复制代码<br />++a先执行+1操作,再执行取值操作。 此时a的值为667。因此输出667。<br />a++先执行取值操作,再执行+1。 此时输出667,随后a的值变为668。<br />—a和a—同理。<br />使用这类运算符时要注意:<br />1)这里的++、—不能用作于常量。比如<br /> 1++; // 抛出错误`<br />复制代码<br />2)如果`a`不是数字类型,会首先通过`Number(a)`,将`a`转换为数字。再执行`++`等运算。<br />第 25 题<br />`console.log(typeof a);`<br />function` `a`() {}`<br />`var a;`<br />`console.log(typeof a);`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />'function'``<br />'function'``<br />复制代码<br />跟第4题类似。函数会优先于变量声明提前。因此会忽略var a。<br />第 26 题<br />var a;<br />var b = 'undefined';<br />console.log(typeof a);<br />console.log(typeof b);<br />console.log(typeof c);<br /> <br />复制代码<br />查看解析 <br />// 输出`<br />'undefined'
‘string’<br />'undefined'
复制代码a为声明未赋值,默认为undefined,b的值为字符串'undefined',c为未定义。typeof一个未定义的变量时,不会抛出错误,会返回'undefined'。注意typeof返回的都是字符串类型。
第 27 题var x = 1;
if(function`f(){}){<br /> x += typeof f;<br />}<br /> <br />console.log(x);<br />复制代码<br />查看解析 <br />//输出`<br />` `<br />`1undefined`<br />复制代码<br />`function f(){}`当做`if`条件判断,其隐式转换后为`true`。但是在`()`中的函数不会声明提升,因此`f`函数在外部是不存在的。因此`typeof f = 'undefined'`,所以`x += typeof f`,相当于`x = x + 'undefined'`为`'1undefined'`<br />第 28 题<br />`var str = `"123abc"`;`<br />`console.log(typeof str++);`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />'number'``<br />复制代码<br />在24题解析时提到,使用++运算符时(无论是前置还是后置),如果变量不是数字类型,会首先用Number()转换为数字。因此typeof str++相当于typeof Number(str)++。由于后置的++是先取值后计算,因此相当于typeof Number(“123abc”)。即typeof NaN,所以输出‘number’。<br />第 29 题<br />console.log('b' + 'a' + +'a'+'a');<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`baNaNa`<br />复制代码<br />`'b' + 'a' + +'a'+'a'`相当于`'ba' + +'a'+'a'`,`+'a'`会将`'a'`转换为数字类型,即`+'a' = NaN`。所以最终得到`'ba' + NaN +'a'`,通过字符串拼接,结果为:`baNaNa`<br />第 30 题<br />`var obj = {n: 1};`<br />function` fn2(a) {`<br />` a.n = 2;`<br />`}`<br />`fn2(obj);`<br />`console.log(obj.n);`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />2<br />复制代码<br />函数传递参数时,如果是基本类型为**值**传递,如果是引用类型,为**引用地址的值**传递。其实都是值传递。因此形参a和obj引用地址相同,都指向同一个对象。当执行a.n,实际上共同指向的对象修改了,添加了个n属性,因此obj.n为2。<br />第 31 题<br />var x = 10;<br />function fn() {<br /> console.log(x);<br />}<br />function show(f) {<br /> var x = 20;<br /> f();<br />}<br />show(fn);<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`10`<br />复制代码<br />`JavaScript`采用的是词法作用域,它规定了函数内访问变量时,查找变量是从函数声明的位置向外层作用域中查找,而不是从调用函数的位置开始向上查找。因此`fn`函数内部访问的`x`是全局作用域中的`x`,而不是`show`函数作用域中的`x`。<br />第 32 题<br />`Object.prototype.bar = 1; `<br />`var foo = {`<br />` goo: undefined`<br />`};`<br />` `<br />`console.log(foo.bar);`<br />`console.log(`'bar'` `in` foo);`<br />` `<br />`console.log(foo.hasOwnProperty(`'bar'`));`<br />`console.log(foo.hasOwnProperty(`'goo'`));`<br />复制代码<br />查看解析 <br />`//输出<br /> <br />1<br />true``<br />false``<br />true``<br /> <br />复制代码<br />in操作符:检测指定对象(右边)原型链上是否有对应的属性值。hasOwnProperty方法:检测指定对象自身上是否有对应的属性值。两者的区别在于in会查找原型链,而hasOwnProperty不会。<br />示例中对象foo自身上存在goo属性,而它的原型链上存在bar属性。<br />通过这个例子要注意如果要判断foo上是否有属性goo,不能简单的通过if(foo.goo){}判断,因为goo的值可能为undefined或者其他可能隐式转换为false的值。<br />第 33 题<br />Object.prototype.bar = 1;<br /> <br />var foo = {<br /> moo: 2<br />};<br />for(var i in foo) {<br /> console.log(i); <br />}<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />'moo'
‘bar’<br />复制代码<br />`for...in...`遍历对象上除了`Symbol`以外的可枚举属性,包括原型链上的属性。<br />第 34 题<br />function` `foo1`() {`<br />` `return` {`<br />` bar: `"hello"};}
function`foo2() {<br /> return <br /> {<br /> bar: "hello"``<br /> };<br />}<br />console.log(foo1());<br />console.log(foo2());<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`{ bar: `"hello"` }`<br />` `<br />`undefined`<br />复制代码<br />两个函数唯一区别就是`return`后面跟的值,一个换行一个不换行。<br />当我们书写代码时忘记在结尾书写`;`时,`JavaScript`解析器会根据一定规则自动补上`;`。<br />return{bar:“hello”<br />`}`<br />`=>会被解析成<br />return;<br />{<br /> bar: "hello"``<br />};<br />复制代码<br />因此函数执行后会返回undefined。<br />第 35 题<br />console.log((function(){ return typeof arguments; })());<br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />'object'
复制代码arguments为类数组,类型为object。因此typeof arguments = 'object'。
第 36 题console.log(Boolean(false));console.log(Boolean(‘0’));console.log(Boolean(‘’));console.log(Boolean(NaN));
复制代码
查看解析 //``输出`<br />false``<br />true``<br />false``<br />fasle<br /> <br />复制代码<br />只有下面几种值在转换为布尔值时为false:<br />+0,-0,NaN,false,'',null,undefined。<br />复制代码<br />除此之外的值在转换为布尔值的时候全部为true。<br />第 37 题<br />console.log(Array(3));<br /> <br />console.log(Array(2,3));<br /> <br />复制代码<br />查看解析 <br />// 输出`<br />` `<br />`[empty × 3] `<br />` `<br />`[2,3]`<br />复制代码<br />使用`Array()`创建数组时,要注意传入的值的类型和数量。<br />第 38 题<br />`console.log(0.1 + 0.2 == 0.3);`<br />` `<br />复制代码<br />查看解析 <br />`//输出<br /> <br />false``<br />复制代码<br />第 39 题<br />var a=[1, 2, 3];<br />console.log(a.join());<br />复制代码<br />查看解析 <br />//`输出`<br />1,2,3<br />复制代码<br />join方法如果省略参数,默认以,分隔。<br />第 40 题<br />var a = [3];<br />var b = [1];<br />console.log(a - b); <br /> `
复制代码
查看解析
面试题:
1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构?
基本数据类型:Undefined、Null、Boolean、Number、String
值类型:数值、布尔值、null、undefined。
引用类型:对象、数组、函数。
堆栈数据结构:是一种支持后进先出(LIFO)的集合,即后被插入的数据,先被取出!
js数组中提供了以下几个方法可以让我们很方便实现堆栈:
shift:从数组中把第一个元素删除,并返回这个元素的值。
unshift: 在数组的开头添加一个或更多元素,并返回新的长度
push:在数组的中末尾添加元素,并返回新的长度
pop:从数组中把最后一个元素删除,并返回这个元素的值。
2.声明函数作用提升?声明变量和声明函数的提升有什么区别?
(1) 变量声明提升:变量申明在进入执行上下文就完成了。
只要变量在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;
(2) 函数声明提升:执行代码之前会先读取函数声明,意味着可以把函数申明放在调用它的语句后面。
只要函数在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;
(3) 变量or函数声明:函数声明会覆盖变量声明,但不会覆盖变量赋值。
同一个名称标识a,即有变量声明var a,又有函数声明function a() {},不管二者声明的顺序,函数声明会覆盖变量声明,也就是说,此时a的值是声明的函数function a() {}。注意:如果在变量声明的同时初始化a,或是之后对a进行赋值,此时a的值变量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a);
3.判断数据类型?
typeof返回的类型都是字符串形式,可以判断function的类型;在判断除Object类型的对象时比较方便。
判断已知对象类型的方法: instanceof,后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
4.异步编程?
方法1:回调函数,优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
方法2:时间监听,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以“去耦合”(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
方法3:发布/订阅,性质与“事件监听”类似,但是明显优于后者。
方法4:Promises对象,是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
5.事件流?事件捕获?事件冒泡?
事件流:从页面中接收事件的顺序。也就是说当一个事件产生时,这个事件的传播过程,就是事件流。
IE中的事件流叫事件冒泡;事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。对于html来说,就是当一个元素产生了一个事件,它会把这个事件传递给它的父元素,父元素接收到了之后,还要继续传递给它的上一级元素,就这样一直传播到document对象(亲测现在的浏览器到window对象,只有IE8及下不这样
事件捕获是不太具体的元素应该更早接受到事件,而最具体的节点应该最后接收到事件。他们的用意是在事件到达目标之前就捕获它;也就是跟冒泡的过程正好相反,以html的click事件为例,document对象(DOM级规范要求从document开始传播,但是现在的浏览器是从window对象开始的)最先接收到click事件的然后事件沿着DOM树依次向下传播,一直传播到事件的实际目标;
6.如何清除一个定时器?
window.clearInterval();
window.clearTimeout();
7.如何添加一个dom对象到body中?innerHTML和innerText区别?
body.appendChild(dom元素);
innerHTML:从对象的起始位置到终止位置的全部内容,包括Html标签。
innerText:从起始位置到终止位置的内容, 但它去除Html标签
分别简述五个window对象、属性
成员对象
window.event window.document window.history
window.screen window.navigator window.external
Window对象的属性如下:
window //窗户自身
window.self //引用本窗户window=window.self
window.name //为窗户命名
window.defaultStatus //设定窗户状态栏信息
window.location //URL地址,配备布置这个属性可以打开新的页面
8.数据持久化技术(ajax)?简述ajax流程
1)客户端产生js的事件
2)创建XMLHttpRequest对象
3)对XMLHttpRequest进行配置
4)通过AJAX引擎发送异步请求
5)服务器端接收请求并且处理请求,返回html或者xml内容
6)XML调用一个callback()处理响应回来的内容
7)页面局部刷新
9.回调函数?
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
10.什么是闭包?* 堆栈溢出有什么区别? 内存泄漏? 那些操作会造成内存泄漏?怎么样防止内存泄漏?
闭包:就是能够读取其他函数内部变量的函数。
堆栈溢出:就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了别的数据。经常会在递归中发生。
内存泄露是指:用动态存储分配函数内存空间,在使用完毕后未释放,导致一直占据该内存单元。直到程序结束。指任何对象在您不再拥有或需要它之后仍然存在。
造成内存泄漏:
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
防止内存泄露:
1、不要动态绑定事件;
2、不要在动态添加,或者会被动态移除的dom上绑事件,用事件冒泡在父容器监听事件;
3、如果要违反上面的原则,必须提供destroy方法,保证移除dom后事件也被移除,这点可以参考Backbone的源代码,做的比较好;
4、单例化,少创建dom,少绑事件。
11.平时工作中怎么样进行数据交互?如果后台没有提供数据怎么样进行开发?mock数据与后台返回的格式不同意怎么办?
由后台编写接口文档、提供数据接口实、前台通过ajax访问实现数据交互;
在没有数据的情况下寻找后台提供静态数据或者自己定义mock数据;
返回数据不统一时编写映射文件 对数据进行映射。
12 简述ajax执行流程
基本步骤:
var xhr =null;//__创建对象
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
}
xhr.open(“方式”,”地址”,”标志位”);//__初始化请求
xhr.setRequestHeader(“”,””);//__设置http头信息
xhr.onreadystatechange =function(){}//__指定回调函数
xhr.send();//__发送请求
13.自执行函数?用于什么场景?好处?
自执行函数:1、声明一个匿名函数2、马上调用这个匿名函数。
作用:创建一个独立的作用域。
好处:防止变量弥散到全局,以免各种js库冲突。隔离作用域避免污染,或者截断作用域链,避免闭包造成引用变量无法释放。利用立即执行特性,返回需要的业务函数或对象,避免每次通过条件判断来处理
场景:一般用于框架、插件等场景
14.html和xhtml有什么区别?
HTML是一种基本的WEB网页设计语言,XHTML是一个基于XML的标记语言。
1.XHTML 元素必须被正确地嵌套。
2.XHTML 元素必须被关闭。
3.标签名必须用小写字母。
4.空标签也必须被关闭。
5.XHTML 文档必须拥有根元素。
15. 什么是构造函数?与普通函数有什么区别?
构造函数:是一种特殊的方法、主要用来创建对象时初始化对象,总与new运算符一起使用,创建对象的语句中构造函数的函数名必须与类名完全相同。
与普通函数相比只能由new关键字调用,构造函数是类的标示
16. 通过new创建一个对象的时候,函数内部有哪些改变
function Person(){}
Person.prototype.friend = [];
Person.prototype.name = ‘’;
// var a = new Person();
// a.friend[0] = ‘王琦’;
// a.name = ‘程娇’;
// var b = new Person();
// b.friend
// b.name?_
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回this 。
17.事件委托?有什么好处?
(1)利用冒泡的原理,把事件加到父级上,触发执行效果
(2)好处:新添加的元素还会有之前的事件;提高性能。
18.window.onload ==? DOMContentLoaded ?
一般情况下,DOMContentLoaded事件要在window.onload之前执行,当DOM树构建完成的时候就会执行DOMContentLoaded事件,而window.onload是在页面载入完成的时候,才执行,这其中包括图片等元素。大多数时候我们只是想在DOM树构建完成后,绑定事件到元素,我们并不需要图片元素,加上有时候加载外域图片的速度非常缓慢。
19.节点类型?判断当前节点类型?
1. 元素节点
2. 属性节点
3. 文本节点
8. 注释节点
9. 文档节点
通过nodeObject.nodeType判断节点类型:其中,nodeObject为DOM节点(节点对象)。该属性返回以数字表示的节点类型,例如,元素节点返回 1,属性节点返回 2 。
20.如何合并两个数组?数组删除一个元素?
//三种方法。
(1)var arr1=[1,2,3];
var arr2=[4,5,6];
arr1 = arr1.concat(arr2);
console.log(arr1);
(2)var arr1=[1,2,3];
var arr2=[4,5,6];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);
(3)var arr1=[1,2,3];
var arr2=[4,5,6];
for (var i=0; i < arr2.length; i++) {
arr1.push( arr2[i] );
}
console.log(arr1);
21.强制转换 显式转换 隐式转换?
//强制类型转换:
Boolean(0) // => false - 零
Boolean(new object()) // => true - 对象
Number(undefined) // => NaN
Number(null) // => 0
String(null) // => “null”
parseInt( )
parseFloat( )
JSON.parse( )
JSON.stringify ( )
隐式类型转换:
在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加。之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的
(例如:x+”” //等价于String(x)
+x //等价于Number(x)
x-0 //同上
!!x //等价于Boolean(x),是双叹号)
显式转换:
如果程序要求一定要将某一类型的数据转换为另一种类型,则可以利用强制类型转换运算符进行转换,这种强制转换过程称为显示转换。
显示转换是你定义让这个值类型转换成你要用的值类型,是底到高的转换。例 int 到float就可以直接转,int i=5,想把他转换成char类型,就用显式转换(char)i
22. Jq中如何实现多库并存?
Noconfict 多库共存就是“$ ”符号的冲突。
方法一: 利用jQuery的实用函数$.noConflict();这个函数归还$的名称控制权给另一个库,因此可以在页面上使用其他库。这时,我们可以用”jQuery “这个名称调用jQuery的功能。$.noConflict();
jQuery(‘#id’).hide();
…..
//或者给jQuery一个别名
var $j=jQuery
$j(‘#id’).hide();
…..
方法二: (function($){})(jQuery)
方法三: jQuery(function($){})
通过传递一个函数作为jQuery的参数,因此把这个函数声明为就绪函数。 我们声明$为就绪函数的参数,因为jQuery总是吧jQuery对象的引用作为第一个参数传递,所以就保证了函数的执行。
23.Jq中get和eq有什么区别?
get() :取得其中一个匹配的元素。num表示取得第几个匹配的元素,get多针对集合元素,返回的是DOM对象组成的数组 eq():获取第N个元素,下标都是从0开始,返回的是一个JQuery对象
24.如何通过原生js 判断一个元素当前是显示还是隐藏状态?
if( document.getElementById(“div”).css(“display”)===’none’)
if( document.getElementById(“div”).css(“display”)===’block’)
$(“#div”).is(“:hidden”); // 判断是否隐藏
$(“#div”).is(“:visible”)
25.Jq如何判断元素显示隐藏?
//第一种:使用CSS属性
var display =$(‘#id’).css(‘display’);
if(display == ‘none’){ alert(“我是隐藏的!”); }
//第二种:使用jquery内置选择器
仅仅是测试所用
if($(“#test”).is(“:hidden”)){ $(“#test”).show(); //如果元素为隐藏,则将它显现 }else{ $(“#test”).hide(); //如果元素为显现,则将其隐藏 }
//第三种:jQuery判断元素是否显示 是否隐藏
var node=$(‘#id’);
if(node.is(‘:hidden’)){ //如果node是隐藏的则显示node元素,否则隐藏
node.show();
}else{
node.hide();
}
26.移动端上什么是点击穿透?
点击穿透现象有3种:
点击穿透问题:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了
解决方案:
1、只用touch
最简单的解决方案,完美解决点击穿透问题
把页面内所有click全部换成touch事件( touchstart 、’touchend’、’tap’)
2、只用click
下下策,因为会带来300ms延迟,页面内任何一个自定义交互都将增加300毫秒延迟
3、tap后延迟350ms再隐藏mask
改动最小,缺点是隐藏mask变慢了,350ms还是能感觉到慢的
4、pointer-events
比较麻烦且有缺陷, 不建议使用mask隐藏后,给按钮下面元素添上 pointer-events: none; 样式,让click穿过去,350ms后去掉这个样式,恢复响应缺陷是mask消失后的的350ms内,用户可以看到按钮下面的元素点着没反应,如果用户手速很快的话一定会发现
27.Jq绑定事件的几种方式?on bind ?
jQuery中提供了四种事件监听方式,分别是bind、live、delegate、on,对应的解除监听的函数分别是unbind、die、undelegate、off
Bind( )是使用频率较高的一种,作用就是在选择到的元素上绑定特定事件类型的监听函数;
Live( )可以对后生成的元素也可以绑定相应的事件,处理机制就是把事件绑定在DOM树的根节点上,而不是直接绑定在某个元素上;
Delegate( )采用了事件委托的概念,不是直接为子元素绑定事件,而是为其父元素(或祖先元素也可)绑定事件,当在div内任意元素上点击时,事件会一层层从event target向上冒泡,直至到达你为其绑定事件的元素;
on( )方法可以绑定动态添加到页面元素的事件,on()方法绑定事件可以提升效率;
28.Jq中如何将一个jq对象转化为dom对象?
方法一:
jQuery对象是一个数据对象,可以通过[index]的方法,来得到相应的DOM对象。
如:var $v =$(“#v”) ; //jQuery对象
var v=$v[0]; //DOM对象
alert(v.checked) //检测这个checkbox是否被选中
方法二:
jQuery本身提供,通过.get(index)方法,得到相应的DOM对象
如:var $v=$(“#v”); //jQuery对象
var v=$v.get(0); //DOM对象
alert(v.checked) //检测这个checkbox是否被选中
29.Jq中有几种选择器?分别是什么?
层叠选择器、基本过滤选择器、内容过滤选择器、可视化过滤选择器、属性过滤选择器、子元素过滤选择器、表单元素选择器、表单元素过滤选择器
30.Jq中怎么样编写插件?
//第一种是类级别的插件开发:
//1.1 添加一个新的全局函数 添加一个全局函数,我们只需如下定义:
jQuery.foo = function() {
alert(‘This is a test. This is only a test.’); };
//1.2 增加多个全局函数 添加多个全局函数,可采用如下定义:
jQuery.foo = function() {
alert(‘This is a test. This is only a test.’); };
jQuery.bar = function(param) {
alert(‘This function takes a parameter, which is “‘ + param + ‘“.’); }; 调用时和一个函数的一样的:jQuery.foo();jQuery.bar();或者$.foo();$.bar(‘bar’);
//1.3 使用jQuery.extend(object);
jQuery.extend({
foo: function() {
alert(‘This is a test. This is only a test.’);
},
bar: function(param) {
alert(‘This function takes a parameter, which is “‘ + param +’”.’);
}
});
//1.4 使用命名空间
// 虽然在jQuery命名空间中,我们禁止使用了大量的javaScript函数名和变量名。
// 但是仍然不可避免某些函数或变量名将于其他jQuery插件冲突,因此我们习惯将一些方法
// 封装到另一个自定义的命名空间。
jQuery.myPlugin = {
foo:function() {
alert(‘This is a test. This is only a test.’);
},
bar:function(param) {
alert(‘This function takes a parameter, which is “‘ + param + ‘“.’);
}
};
//采用命名空间的函数仍然是全局函数,调用时采用的方法:
$.myPlugin.foo();
$.myPlugin.bar(‘baz’);
//通过这个技巧(使用独立的插件名),我们可以避免命名空间内函数的冲突。
//第二种是对象级别的插件开发
//形式1:
(function($){
$.fn.extend({
pluginName:function(opt,callback){
// Our plugin implementation code goes here.
}
})
})(jQuery);
//形式2:
(function($) {
$.fn.pluginName = function() {
// Our plugin implementation code goes here.
};
})(jQuery);
//形参是$,函数定义完成之后,把jQuery这个实参传递进去.立即调用执行。
//这样的好处是,我们在写jQuery插件时,也可以使用$这个别名,而不会与prototype引起冲突
31.$(‘div+.ab’)和$(‘.ab+div’)哪个效率高?
$(‘div+.ab’)效率高
32.$.map和$.each有什么区别
map()方法主要用来遍历操作数组和对象,会返回一个新的数组。$.map()方法适用于将数组或对象每个项目新阵列映射到一个新数组的函数;
each()主要用于遍历jquery对象,返回的是原来的数组,并不会新创建一个数组。
33.编写一个getElementsByClassName 封装函数?
34.简述下工作流程
我在之前的公司工作流程大概是这样的:公司定稿会结束以后,会进行简单的技术研讨,然后我们前端会进行先期的技术准备。前端切图人员会进行psd设计稿切图,并且将css文件进行整合。我们主要编写JS部分,其中包括搭建前端框架(大项目),编写js业务和数据持久化操作,我们也会编写js插件并且进行封装方便使用,还有就是编写JS前端组建和JS测试单元,最后将完成的JS部分与切图人员提供的HTML页面进行整合。最后对完成的页面进行功能测试、页面兼容、产品还原。然后对产品进行封存,提交测试。如果出现BUG会返回给我们开发人员进行修改,再提交测试,最后测试成功,进行版本封存。等到程序全部上线的时候进行线上测试。
35.一般使用什么版本控制工具?svn如何对文件加锁
svn加锁目的:为了避免多个人同一时间对同一个文件改动的相互覆盖,版本控制系统就必须有一套冲突处理机制。
svn加锁两种策略:乐观加锁:所有签出的文件都是可读写的,对文件的修改不必获得文件的锁,当你修改完文件签入时,会首先要求你更新本地文件,版本控制系统不会覆盖你的本地修改,而是会让你自己合并冲突后签入。
严格加锁:所有签出的文件都是只读的,任何对文件的修改必须要获得文件的锁,如果其他人没有拥有该文件的锁,那么版本控制系统就会授权给你文件的锁,并将文件设置为可编辑的。
svn两种加锁步骤:乐观加锁:选择你想要获取锁定的文件,然后右键菜单点击TortoiseSVN 选取获取锁定。
严格加锁:在想要采取严格加锁的文件或目录上点击右键,使用TortoiseSVN 属性菜单,点击新建属性,选择需要锁定。
36. git 和 svn的区别?
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。
Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
37. jquery和zepto有什么区别?
1.针对移动端程序,Zepto有一些基本的触摸事件可以用来做触摸屏交互(tap事件、swipe事件),Zepto是不支持IE浏览器的,这不是Zepto的开发者Thomas Fucks在跨浏览器问题上犯了迷糊,而是经过了认真考虑后为了降低文件尺寸而做出的决定,就像jQuery的团队在2.0版中不再支持旧版的IE(6 7 8)一样。因为Zepto使用jQuery句法,所以它在文档中建议把jQuery作为IE上的后备库。那样程序仍能在IE中,而其他浏览器则能享受到Zepto在文件大小上的优势,然而它们两个的API不是完全兼容的,所以使用这种方法时一定要小心,并要做充分的测试。
2.Dom操作的区别:添加id时jQuery不会生效而Zepto会生效。
3.zepto主要用在移动设备上,只支持较新的浏览器,好处是代码量比较小,性能也较好。
jquery主要是兼容性好,可以跑在各种pc,移动上,好处是兼容各种浏览器,缺点是代码量大,同时考虑兼容,性能也不够好。
38. $(function(){})和window.onload 和 $(document).ready(function(){})
window.onload:用于当页面的所有元素,包括外部引用文件,图片等都加载完毕时运行函数内的函数。load方法只能执行一次,如果在js文件里写了多个,只能执行最后一个。
$(document).ready(function(){})和$(function(){})都是用于当页面的标准DOM元素被解析成DOM树后就执行内部函数。这个函数是可以在js文件里多次编写的,对于多人共同编写的js就有很大的优势,因为所有行为函数都会执行到。而且$(document).ready()函数在HMTL结构加载完后就可以执行,不需要等大型文件加载或者不存在的连接等耗时工作完成才执行,效率高。
39. Jq中 attr 和 prop 有什么区别
对于HTML元素本身就带有的固有属性,在处理时,使用prop方法。
对于HTML元素我们自己自定义的DOM属性,在处理时,使用attr方法。
40. 简述下 this 和定义属性和方法的时候有什么区别?Prototype?
this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window; 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。
prototype本质上还是一个JavaScript对象。 并且每个函数都有一个默认的prototype属性。
在prototype上定义的属性方法为所有实例共享,所有实例皆引用到同一个对象,单一实例对原型上的属性进行修改,也会影响到所有其他实例。
41. 什么是预编译语音|预编译处理器?
Sass是一种CSS预处理器语言,通过编程方式生成CSS代码。因为可编程,所以操控灵活性自由度高,方便实现一些直接编写CSS代码较困难的代码。
同时,因为Sass是生成CSS的语言,所以写出来的Sass文件是不能直接用的,必须经过编译器编译成CSS文件才能使用。
CSS 预处理器是一种语言用来为 CSS 增加一些编程的的特性,无需考虑浏览器的兼容性问题,例如你可以在 CSS 中使用变量、简单的程序逻辑、函数等等在编程语言中的一些基本技巧,可以让你的CSS 更见简洁,适应性更强,代码更直观等诸多好处。最常用的css预处理器有sass、less css、stylus。
42.ajax 和 jsonp ?
ajax和jsonp的区别:
相同点:都是请求一个url
不同点:ajax的核心是通过xmlHttpRequest获取内容
jsonp的核心则是动态添加
