前端笔试做题笔记----JavaScript篇
-
-
-
-
- 1、this五种情况
- 2、({}+‘b‘>{}+‘a‘)返回值是() (考察 隐式类型转换)
- 3 、 js 函数定义方式
- 4、 js 单线程机制相关题目
- 5、变量提升和函数提升
- 6、 JavaScript 常见事件
- 7、 NOSCRIPT标签的作用
- 8、 JavaScript 数据类型那些事
- 9、立即执行函数
- 10、Array常用方法
- 11、String常用方法
- 12、Number常用方法
- 13、Math常用方法
- 14、Date常用方法
- 15、cookie、 localStorage、sessionStorage
- 16、JavaScript中bind、call和apply方法
- 17、代码分析
- 18、继承
-
-
-
1、this五种情况
- 当在函数调用的时候指向widow
- 当方法调用的时候指向调用对象
- 当用apply和call上下文调用的时候指向传入的第一个参数
- 构造函数调用指向实例对象
- 箭头函数中使用this指向该函数所在的作用域指向的对象
2、({}+‘b‘>{}+‘a‘)返回值是() (考察 隐式类型转换)
因为有比较运算符,且两边的数据类型都不同,所以隐式类型转换
{}+‘b’:
toPrimitive({},String)这里为什么是String,而不是Number。我是通过 {} + ‘b’ === “[object Object]b”//true验证的。
(ps:个人猜测因为都有字符串且是 + ,所以这里是转成String的原始值)
{}.valueOf();//{}空对象
{}.toString();//“[object,object]”
toPrimitive(“[object,object]”,String)
所以{}隐式类型转换的原始值为String(“[object,object]”);//“[object,object]”
所以:{}+‘b’ ==>“[object,object]”+‘b’
{}+'a’同理
因此最后{}+‘b’>{}+‘a’ ==> “[object,object]b” > “[object,object]a”;
为了验证是这样:console.log({}+‘2’>{}+‘3’);//false;
3 、 js 函数定义方式
- 函数声明语法定义:
function sum(num1,num2){return num1+num2}
- 函数表达式定义函数:
var sum = function(num1,num2){return num1+num2};
var sum = new Function("num1","num2","return num1+num2");
Function构造函数可以接受任意数量的参数,但最后一个参数始终被看成函数体,注意函数表达式定义函数的方法与声明其他变量时一样需要加分号。
4、 js 单线程机制相关题目
var声明的变量i不具有块级作用域
- 异步任务–点击事件
这里考的是JS的运行机制! 事件(click,focus等等),定时器(setTimeout和setInterval),ajax,都是会触发异步,属于异步任务;js是单线程的,一个时间点只能做一件事,优先处理同步任务; 按照代码从上往下执行,遇到异步,就挂起,放到异步任务里,继续执行同步任务,只有同步任务执行完了,才去看看有没有异步任务,然后再按照顺序执行! 这里for循环是同步任务,onclick是异步任务,所以等for循环执行完了,i变成4了,注意:这里因为i是全局变量,最后一个i++,使得i为4(后面的onclick函数,最后在循环外面执行,不受i<length限制); 所以for循环每执行一次,onclick事件函数都会被挂起一次,共4次; for循环结束后,点击事件 触发了4个onclick函数,接着输出4个4!
- 异步任务–定时器 (let和var)
第一个:let将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;输出为0,1.
第二个:settimeout是异步执行,1s后往异步任务队列里面添加一个任务,只有同步的全部执行完,才会执行异步任务队列里的任务,当主线执行完成后,i是2,所以此时再去执行任务队列里的任务时,所以输出两次2.
5、变量提升和函数提升
- 函数声明提升优先级高于变量声明提升
当变量和函数同名时,优先留下函数的值,即函数的优先级更高
- 提升就是声明(变量/函数)提至当前作用域的最顶部,赋值语句留在原地
//原来的代码
var a = 2;
function fn(){
b();
return ;
var a = 1;
function b(){
console.log(a);
}
}
fn();
//实际上的代码
var a = 2;
function fn(){
function b(){
console.log(a);
}
var a //变量声明提升,默认赋值为undefined
b(); //执行函数b,在当前作用域找到a,值为undefined
return;//return后面的语句不再执行,a没有被赋值为1
a = 1; //在原来的位置才会赋值,但不会执行到这里
}
fn();
- 函数创建有3个形式,函数声明和函数表达式( 以及 new Function构造函数),只有函数声明才有函数提升
//函数声明
function f1(){
console.log('我是函数声明')
}
//函数表达式
var f2 = function () {
console.log('我是函数表达式')
}
函数发生提升后
// 函数声明--提升
function f1() {
console.log('我是函数声明')
}
var f2;
f1() //'我是函数声明'
f2() //error:f2 is not a function
// 函数表达式
f2 = function() {
console.log('我是函数表达式')
}
6、 JavaScript 常见事件
- 鼠标事件
- 键盘事件
- 焦点事件
- 滚轮事件
7、 NOSCRIPT标签的作用
NOSCRIPT标签用来定义在脚本未被执行时的替代内容。也可以用在检测浏览器是否支持脚本,若不支持脚本则可以显示NOSCRIPT标签里的innerText
noscript:用以在不支持js的浏览器中显示替代的内容,这个元素可以包含能够出现在文档中任何html元素,script元素除外。包含在noscript元素的内容只有在下列情况下才会显示出来
- 浏览器不支持脚本
- 浏览器支持脚本,但脚本被禁用
8、 JavaScript 数据类型那些事
- undefined和null与任何有意义的值比较返回的都是false,但是null与undefined之间互相比较返回的是true。
- Symbol类型
- Symbol为ES6新增的基本数据类型,表示独一无二的值。
- Symbol()函数会返回symbol类型的值,每个从Symbol()返回的symbol值都是唯一的。
- Symbol.for() 返回由给定的 key 找到的 symbol,否则就是返回新创建的 symbol
- 用Symbol来创建Symbol对象时,不使用new运算符
- NaN==NaN为假,NaN是一个不确定数,所以NaN不能等于NaN
- null instanceof Object为假,在js中 typeof null会返回object,这并不意味着null是object类型,只是遗留错误。null不是object创建的实例对象
9、立即执行函数
答案:E
function() {output(“Hello World!”)})()
匿名的立即执行函数
1.先立即执行匿名函数,输出Hello World! 2.函数执行后无返回值,则输出未定义
10、Array常用方法
indexOf()
搜索数组中的元素,并返回它所在的位置。var fruits = ["Banana", "Orange", "Apple", "Mango"]; var a = fruits.indexOf("Apple"); //输出 2
includes()
判断一个数组是否包含一个指定的值。let site = ['runoob', 'google', 'taobao']; site.includes('runoob'); // true site.includes('baidu'); // false arr.includes(searchElement, fromIndex) //searchElement 必须。需要查找的元素值。 //fromIndex 可选。从该索引处开始查找 searchElement。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜索。默认为 0。 //如果 fromIndex 为负值,计算出的索引将作为开始搜索searchElement的位置。如果计算出的索引小于 0,则整个数组都会被搜索。 var arr = ['a', 'b', 'c']; arr.includes('a', -100); // true arr.includes('b', -100); // true arr.includes('c', -100); // true
concat()
连接两个或更多的数组,并返回结果。var hege = ["Cecilie", "Lone"]; var stale = ["Emil", "Tobias", "Linus"]; var kai = ["Robin"]; var children = hege.concat(stale,kai); //children 输出结果: Cecilie,Lone,Emil,Tobias,Linus,Robin
reduce()
将数组元素计算为一个值(从左到右)。some()
检测数组元素中是否有元素符合指定条件。some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
如果没有满足条件的元素,则返回false。
注意: some() 不会对空数组进行检测。
注意: some() 不会改变原始数组。find()
返回符合传入测试(函数)条件的数组元素。find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
find() 方法为数组中的每个元素都调用一次函数执行:
当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 undefined
注意: find() 对于空数组,函数是不会执行的。
注意: find() 并没有改变数组的原始值。filter()
检测数值元素,并返回符合条件所有元素的数组。//filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 //注意: filter() 不会对空数组进行检测。 //注意: filter() 不会改变原始数组。 var ages = [32, 33, 16, 40]; function checkAdult(age) { return age >= 18; } function myFunction() { document.getElementById("demo").innerHTML = ages.filter(checkAdult); } //输出结果为: 32,33,40
every()
检测数值元素的每个元素是否都符合条件。every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。unshift()
向数组的开头添加一个或更多元素,并返回新的长度。##### 11、String常用方法//unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。 //注意: 该方法将改变数组的数目。 var fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.unshift("Lemon","Pineapple"); //输出: Lemon,Pineapple,Banana,Orange,Apple,Mango
push()
将新项目添加到数组的末尾const fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.push("Kiwi"); document.getElementById("demo").innerHTML = fruits; //输出: Banana,Orange,Apple,Mango,Kiwi
slice()
选取数组的一部分,并返回一个新数组。//slice() 方法可从已有的数组中返回选定的元素。 //slice()方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。 //注意: slice() 方法不会改变原始数组。 var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]; var citrus = fruits.slice(1,3); //输出: Orange,Lemon
forEach()
数组每个元素都执行一次回调函数。//forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。 //注意: forEach() 不会改变原数组 //注意: forEach() 对于空数组是不会执行回调函数的。 var arr = [1, 2, 3, 4, 5]; arr.forEach(function (item) { if (item === 3) { return; } console.log(item); });
isArray()
判断对象是否为数组,isArray() 方法用于判断一个对象是否为数组。
如果对象是数组返回 true,否则返回 false。
11、String常用方法
includes()
查找字符串中是否包含指定的子字符串。concat()
连接两个或更多字符串,并返回新的字符串。indexOf()
返回某个指定的字符串值在字符串中首次出现的位置。replace()
在字符串中查找匹配的子串, 并替换与正则表达式匹配的子串。//replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。 //如果想了解更多正则表达式教程请查看本站的:RegExp 教程 和 our RegExp 对象参考手册. //该方法不会改变原始字符串。 var str="Visit Microsoft! Visit Microsoft!"; var n=str.replace("Microsoft","Runoob"); // 输出结果: Visit Runoob!Visit Microsoft!
slice()
提取字符串的片断,并在新的字符串中返回被提取的部分。split()
把字符串分割为字符串数组。//split() 方法用于把一个字符串分割成字符串数组。 //提示: 如果把空字符串 ("") 用作 separator,那么 stringObject 中的每个字符之间都会被分割。 //注意: split() 方法不改变原始字符串。 var str="How are you doing today?"; var n=str.split(" "); //输出一个数组的值: How,are,you,doing,today?
substr()
从起始索引号提取字符串中指定数目的字符。var str="Hello world!"; var n=str.substr(2,3) // 输出结果: llo
substring()
提取字符串中两个指定的索引号之间的字符。trim()
去除字符串两边的空白var str = " Runoob "; alert(str.trim()); //输出结果: Runoob
toString()
返回一个字符串。var str = "Runoob"; var res = str.toString(); //输出结果: Runoob
12、Number常用方法
valueOf()
返回一个 Number 对象的基本数字值。//返回一个 Number 对象的基本数字值: var num = 15; var n = num.valueOf(); //输出结果: 15
toFixed()
把数字转换为字符串,结果的小数点后有指定位数的数字。//把数字转换为字符串,结果的小数点后有指定位数的数字: var num = 5.56789; var n=num.toFixed(2); //输出结果: 5.57
13、Math常用方法
random()
返回 0 ~ 1 之间的随机数。//返回介于 0(包含) ~ 1(不包含) 之间的一个随机数: Math.random(); //输出结果: 0.13704677732303505
round(x)
四舍五入。//round() 方法可把一个数字舍入为最接近的整数: Math.round(2.5); //输出结果: 3
floor(x)
对 x 进行下舍入。//返回小于等于x的最大整数: Math.floor(1.6); //以上实例将输出: 1
ceil(x)
对x进行上舍入。//对一个数进行上舍入: Math.ceil(1.4) //输出结果: 2
14、Date常用方法
getDate()
从 Date 对象返回一个月中的某一天 (1 ~ 31)。var d = new Date(); var n = d.getDate(); //输出结果: 6
getDay()
从 Date 对象返回一周中的某一天 (0 ~ 6)。getFullYear()
从 Date 对象以四位数字返回年份。getHours()
返回 Date 对象的小时 (0 ~ 23)。getMinutes()
返回 Date 对象的分钟 (0 ~ 59)。getMonth()
从 Date 对象返回月份 (0 ~ 11)。getSeconds()
返回 Date 对象的秒数 (0 ~ 59)。setDate()
设置 Date 对象中月的某一天 (1 ~ 31)。var d = new Date(); d.setDate(15); //输出结果: Thu Apr 15 2021 11:27:56 GMT+0800 (中国标准时间)
setFullYear()
设置 Date 对象中的年份(四位数字)。setHours()
设置 Date 对象中的小时 (0 ~ 23)。setMinutes()
设置 Date 对象中的分钟 (0 ~ 59)。setMonth()
设置 Date 对象中月份 (0 ~ 11)。
15、cookie、 localStorage、sessionStorage
16、JavaScript中bind、call和apply方法
-
call()、apply()、bind() 都是用来重定义 this 这个对象的
以上出了 bind 方法后面多了个 () 外 ,结果返回都一致!由此得出结论,bind 返回的是一个新的函数,你必须调用它才会被执行。
-
对比call 、bind 、 apply 传参情况下
微妙的差距!从上面四个结果不难看出:
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面
obj.myFun.call(db,'成都', ... ,'string' )
。apply 的所有参数都必须放在一个数组里面传进去
obj.myFun.apply(db,['成都', ..., 'string' ])
。bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
17、代码分析
- 分析如下代码打印出的结果
var foo = {
n:1};
(function(foo){
console.log(foo.n);
foo.n = 3;
var foo = {
n:2};
console.log(foo.n);
})(foo);
console.log(foo.n);
解析:
var foo = {
n:1};
(function(foo){
//形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
var foo; //优先级低于形参,无效。
console.log(foo.n); //输出1
foo.n = 3; //形参与实参foo指向的内存空间里的n的值被改为3
foo = {
n:2}; //形参foo指向了新的内存空间,里面n的值为2.
console.log(foo.n); //输出新的内存空间的n的值
})(foo);
console.log(foo.n); //实参foo的指向还是原来的内存空间,里面的n的值为3.
- 分析如下代码打印的结果为
var a = 4399 < 0 || typeof(4399 + '');
console.log(a);
解析:
&&运算,如果前面值为true,则结果为后面的值。如果前面值为false,则值为false.
||运算,如果前面值为true,则结果为前面的值,如果前面的值为false,则结果为后面的值。
18、继承
- 原型继承
function Animal(){
this.type = '动物'
}
function Cat(name,color){
this.name = name;
this.color = color
}
Cat.prototype = new Animal()
var c1 = new Cat('x','白色')
var c2 = new Cat('f','花色')
console.log(c1)
console.log(c2)
优点:同一个原型对象
缺点:不能修改原型对象,会影响所有实例
- 构造函数的继承
function Animal(){
this.type = '动物'
}
function Cat(name,color){
Animal.apply(this) //将Animal对象的成员赋值到Cat对象上
this.name = name;
this.color = color
}
var c1 = new Cat('x','白色')
var c2 = new Cat('f','花色')
console.log(c1)
console.log(c2)
优点:不存在需修改原型对象影响所有实例,各自拥有独立属性
缺点:父类的成员会被创建多次,存在冗余且不是同一个原型对象
通过apply/call只能拷贝成员,原型对象并不会拷贝
- 组合继承
function Animal(){
this.type = '动物'
}
Animal.prototype.eat = function(){
console.log('吃吃')}
function Cat(name,color){
Animal.apply(this) //将Animal对象的成员赋值到Cat对象上
this.name = name;
this.color = color
}
Cat.prototype = new Animal()
var c1 = new Cat('x','白色')
var c2 = new Cat('f','花色')
c1.type = '我是x' //修改当前构造器中的属性
c2.__proto__.type='我是动物' //修改原型对象的值,但 不影响c1、c2的值
console.log(c1.type)
console.log(c2.type)
console.log(c1.__proto__.type)
console.log(c2.__proto__.type)
持续更新中…