面试题 题目-答案-扩展
if (!foo) { alert("foo!") }
对于非boolean类型,js会将值先转换成boolean类型,而后取反。0、null、NaN、undefined、"" 转成布尔值为false 其他则一律返回true;(那么!!呢?就是 取反在取反)
那么为什么{} 和 [] 不是false呢?
空数组或者是空对象都是 object 那么作为条件就会转成true !true===false所以无法输出
答案: D F G H L J
二、请将一下属性按照盒模型由内而外的顺序排序
A.padding B.border C.height D.margin
分析一下 盒子模型有两种 标准盒子模型和IE盒子模型又称怪异盒子
答案:C A B D (标准) 和 A B C D (怪异)
三、要在十秒后调用checkState,下列写法哪个是正确的?
A. window.setTimeout(checkState(),10) B. window.setTimeout(checkState,10) C. window.setTimeout(checkState(),10000) D. window.setTimeout(checkState,10000)
分析:先回忆一下setTimeout 再来做这道题
语法:
setInterval(function, milliseconds, param1, param2, ...)
第一个参数:必需。要调用一个代码串,也可以是一个函数。
第二个参数:必需。周期性执行或调用 code/function 之间的时间间隔,以毫秒计。
param1,param2...: 选填传递给函数的其他参数
//代码串 setTimeout(function () { alert("Hello"); }, 3000); //函数 var fn = function () { alert("Hello"); } setTimeout(fn, 3000); //函数调用 var fn = function () { alert("Hello"); } setTimeout("fn()", 3000);
C会立即执行
答案:D
四、下面哪种方式可以删除节点elm
A.elm.parentNode.removeChild(elm
B.document.createElement('fragment').appendChild(elm) C.elm.parentNode.deleteChild(elm) D.elm.parentNode.remove(elm)
分析:删除节点的方式
<div id="box"> <p id="p1">这是一个段落</p> <p id="p2">第二个段落</p> </div> <script> var p1=document.getElementById("p1");
//直接找到这个元素删除 p1.remove(); //或者要删除的子节点的父节点删除子节点 p1.parentNode.removeChild(p1); </script>
答案:A
扩展一下dom的操作
// 创建: createDocumentFragment() //创建一个DOM片段 //创建一个具体的元素 createElement() //创建一个文本节点 createTextNode() //添加节点 appendChild() //举例 var node = document.createElement("LI"); var textnode = document.createTextNode("Water"); node.appendChild(textnode); document.getElementById("myList").appendChild(node); // 移出: removeChild() remove() /* 替换 node.replaceChild(newnode,oldnode) newnode 你要插入的节点对象。 oldnode 你要移除的节点对象 */ replaceChild() document.getElementById("myList").replaceChild(newnode,oldnode); /* 插入 node.insertBefore(newnode,existingnode) newnode 你要插入的节点对象。 existingnode 可选。在其之前插入新节点的子节点。如果未规定,则 insertBefore 方法会在结尾插入 newnode。 */
insertBefore() document.getElementById("myList").insertBefore(newItem,existingItem); //末尾插入节点 document.getElementById("myList").appendChild(newItem) /* 插入 node.insertBefore(deep) deep (boolean) 可选。该方法将复制并返回调用它的节点的副本。如果传递给它的参数是 true,它还将递归复制当前节点的所有子孙节点。否则,它只复制当前节点。 */
cloneNode(true)
var node=document.getElementById("myList2").lastChild.cloneNode(true);
document.getElementById("myList1").appendChild(node);
五、下列表达式的结果是true的有:
A.typeof(null)==='object' B.''==false C.Function instanceof Object D.[].constructor === Array
分析:
先看B选项
所以" "是string 0是number false是boolean 当它们的比较用===则都为false
typeof
操作符返回一个字符串,表示未经计算的操作数的类型。
//number typeof(42) typeof 42 // string typeof '' typeof String(1) //String 将任意值转换为字符串,比 toString 更安全 typeof (3).toString() //boolean typeof false typeof !!(1) // 两次调用 ! (逻辑非) 操作符相当于 Boolean() //undefined var str typeof str typeof declaredButUndefinedVariabl //声明但未定义变量 typeof undeclaredVariable //不可声明变量 //function typeof function() {} //object typeof {a: 1} typeof null /* 在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。 对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00), 因此,null 的类型标签是 0,typeof null 也因此返回 "object" */ //使用new操作符 除 Function 外的所有构造函数的类型都是 'object' var str = new String('String'); var num = new Number(100); typeof str; // 返回 'object' typeof num; // 返回 'object' var func = new Function(); typeof func; // 返回 'function'
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
语法 :object instanceof constructor (object-某个实例对象 constructor某个构造函数)
function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } var auto = new Car('Honda', 'Accord', 1998); auto instanceof Car; //true auto instanceof Object; //true /* 如果表达式 obj instanceof Foo 返回 true, 则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变, 改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。 举例如下 */ // 定义构造函数 function C(){} var o = new C(); o instanceof C; // true C.prototype instanceof Object // true,同上 C.prototype = {}; var o2 = new C(); o2 instanceof C; // true /*这里给o重新继承 o = new C(); 在执行下一句就是true了*/ o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.
constructor 属性返回对创建此对象的数组函数的引用。 这个我也不是很理解这句话的意思等我以后会了再来补充 如果有会的也可以评论教我~~
语法:object.constructor
test='123'; test.constructor == String test=456; test.constructor == Number test={}; test.constructor == Object test=[]; test.constructor == Array test=true; test.constructor == Boolean test=new Date(); test.constructor == Date
答案 A B C D
六、关于数组的说法不正确的是?
A.对数组里数据的排序可以用sort函数,如果排序效果非预期,可以给sort函数加一个排序函数的参数
B.reverse用于数组数据的倒叙排序
C.向数组的最后位置加一个新元素,可以用pop方法
D.unshift方法用于删除数组第一个元素;
分析:
sort()
/* sort() 方法用于对数组的元素进行排序。 语法 arrayObject.sort(sortby) sortby 可选。规定排序顺序。必须是函数。 */ // 调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。 // 按字母顺序 a-z 排列 arr=["George","John","Thomas","James","Adrew", "Martin"] arr.sort()
//数字排序 // 无参数 arr1=["10","5","40","25","100", "1"] arr1.sort() //有参数 a-b 按照数值大小 -升序 arr1.sort((a,b)=>{ return a-b; }) // 有参数 b-a 按照数值大小 -降序 arr1.sort((a,b)=>{ return b-a; })
实际应用中可以通过对象的某一个属性进行排序
例如:按照person数组中对象的age属性排序
let person = [{ name: "小可爱", age: 12 }, { name: "陈怡baby", age: 22 }, { name: "小仙女", age: 18 }] function sequencing(property) { return function (a, b) { return a[property] - b[property]; } } console.log(person.sort(sequencing('age')))
reverse()
/* reverse() 方法用于颠倒数组中元素的顺序。 arrayObject.reverse() 该方法会改变原来的数组,而不会创建新的数组。 */ arr = [3,5,7,42,65] arr.reverse() // 扩展:将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组 var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]; // 分析一下:先转成一维数组然后去重最后排序 [...new Set(arr.flat(Infinity))].sort((a,b)=>{ return a-b}) // 或者: Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b}) /* flat()默认只会“拉平”一层, 如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。 */ let arr1 = [1,2,[3,[4]]]; // 常用 /* toString() 方法可把数组转换为字符串,并返回结果。 join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。 split() 方法用于把一个字符串分割成字符串数组。 */ let arr2 = arr1.toString().split(','); // ["1", "2", "3", "4"] let arr3 = arr1.join().split(','); // ["1", "2", "3", "4"] // 但是缺点是 把数组中的每一项都变成了字符串 // 数组map方法做一个类型转换 arr3一样不做展示 arr2.map(item => Number(item)) // [1, 2, 3, 4] // 有了es6以后一步搞定 arr1.flat(Infinity)
选择C D都是对数组的操作 一起总结
回忆一下数组增删的操作 数组的基本操作不做举例
答案:A B
七、以下代码运行后,控制台输出结果是:
var num = 100; function fn (){ var num = num+1; return num; } console.log(fn())
A.101 B.1 C.undefined D.NaN
函数外部申明num全局变量 函数内部也声明了一个num局部变量 但是var还存在变量提升
改写:
var num = 100; function fn (){ var num; num= num+1; // undefined + 1 return num; } console.log(fn()) //NAN var num = 100; function fn (){ num= num+1; //内部没有num全局找 return num; } console.log(fn()) //101 那么let没有变量提升改用let呢? let不存在变量提升所有 无法再初始化前访问
答案:D
八、下面哪个不属于Promise的状态
A.Resolved
B.Unfulfilled //未完成
C.Rejected //拒绝
D.Pause //暂停
Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。同一时间只能存在一种状态,且状态一旦改变就不能再变。
答案:B D
九、代码运行输出结果是:
var Core = { title:"Core", show:function(){ return this.title } } title = 'window' fn = Core.show; fn(); A.Core B.window C.不确定
这是this指向的问题 this指向当前的函数 当前函数是全局的所以windows.title
var Core = { title:"Core", show:function(){ return this.title } } fn = Core.show; fn(); //undefined 因为windows里面没有title属性
答案 : B
十、以下代码输出什么结果,为什么?
var getFn = function () { var arrs = []; for (var i = 0; i < 3; i++) { arrs.push(function () { return i; }) } return arrs; } var fns = getFn(); console.log(fns[0]()+fns[1]())
按照我们正常的推算 i分别push为 0 1 2 那么打印的就是 0+1 为1 但是控制台可以看一下 这输出的是6
for循环中设置循环变量的部位是一个父作用域,循环体内部是个子作用域。
每次子作用域中的i改变的时候 污染了父作用域中全局变量 i 最后一次i不符合条件的时候是3 所以全局也被修改成了三 fn[0],fn[1],fn[2] 都是3
改写:
//用闭包改写 输出1 var getFn = function () { var arrs = []; for (var i = 0; i < 3; i++) { (function (i) { arrs.push(function () { return i; }) })(i) } return arrs; }
// 用let 输出1 var getFn = function () { var arrs = []; for (let i = 0; i < 3; i++) { arrs.push(function () { return i; }) } return arrs; }
十一、以下代码输出顺序?
console.log(1); new Promise(function(resolve,reject){ reject(true); window.setTimeout(function(){ resolve(false); },0) }).then(function(){ console.log(2) },function(){ console.log(3) }) console.log(4)
答案:1 4 3
promise 基础
new Promise( function (resolve, reject) { // 一段耗时的异步操作 resolve('成功') // 数据处理完成 // reject('失败') // 数据处理出错 } ).then( (res) => {console.log(res)}, // 成功 (err) => {console.log(err)} // 失败 )
对应看一下题目
1.答应1 先执行
2.promise是异步所以不影响 4 的打印
3.执行promise的时候 里面有reject() 和 resolve() 但是成功的resolve在setTimeout中及时调用时间为0立即调用但是他依然是异步要等待
所以这时候的状态先走一步变成了reject() promise同一时间只能存在一种状态,且状态一旦改变就不能再变。因此就是失败了
按照上面语法打印为 1 4 3
new Promise(resolve => { setTimeout(() => { resolve('hello') }, 3000) }).then(res => { console.log(res) })
执行的那一刻就进入了 pending状态 三秒后输出hello
//一般失败都是放在catch中写法如下
new Promise(function(resolve,reject){ reject(false); resolve(true); }).then(function(res){
console.log(res) }).catch(function(res){ console.log(res) }).finally(function(){ console.log('成功失败都有我') })
new Promise(function(resolve,reject){ resolve(true); reject(false); }).then(function(res){ console.log(res) }).catch(function(res){ console.log(res) }).finally(function(){ console.log('成功失败都有我') })
总结:
1.reject() 和 resolve()谁先执行状态就是谁的 不会再改变
2. .then()中是正确回调
3. .catch()中是错误信息
4. .finally()中 无论失败还是成功都会执行
十二、 最后一个编程题~~~~~~~~~~~~~~
编写一个javascript函数fn,该函数有一个参数n(number),其返回值是一个数组,该数组是n个随机且不重复的整数,且整数取值范围是[2,32];
先写一个
function fn(n,min,max){}
fn(n,min,max)
想想我们的随机数公式 : Math.floor(Math.random() * (min - max + 1) + max);
n次循环 然后创建一个[]第一次追加进去 其余的判断里面有没有追加过的 如果有就i-- 多一次循环 思路有了 整合一下
function fn(n,min,max) {
if(typeof n !== 'number'){
let arrs = []; for (let i = 0; i < n; i++) { let rand = Math.floor(Math.random() * (min - max + 1) + max); if (arrs.length == 0) { arrs.push(rand) } else { if (arrs.indexOf(rand) != -1) { i--; } else { arrs.push(rand) } } } return arrs; } console.log(fn(5,2,32))
通过这些题学习了很多 到这里就结束了~~~~~~~~~~~~~