21、变量提升与函数提升的区别?(必会)
变量提升
简单说就是在 JavaScript 代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提 升至其对应作用域的最顶端,函数内声明的变量只会提升至该函数作用域最顶层 当函数内部定义的一个变量与外部相同时,那么函数体内的这个变量就会被上升到最顶端
举例来说:
console.log(a); //undefined
var a = 3;
//预编译后的代码结构可以看做如下运行顺序
var a; // 将变量 a 的声明提升至最顶端,赋值逻辑不提升。
console.log(a);// undefined
a = 3; // 代码执行到原位置即执行原赋值逻辑
函数提升:
函数提升只会提升函数声明式写法,函数表达式的写法不存在函数提升
函数提升的优先级大于变量提升的优先级,即函数提升在变量提升之上
22、什么是作用域链?(必会)
作用域链
当代码在一个环境中执行时,会创建变量对象的一个作用域链 由子级作用域返回父级作用域中寻找变量,就叫做作用域链
作用域链中的下一个变量对象来自包含环境,也叫外部环境。而再下一个变量对象则来自下一个包含环境,一直延续到全局执行环境。
全局执行环境的变量对象始终都是作用域链中的最后一个对象
作用域链前端始终都是当前执行的代码所在环境的变量对象,如果环境是函数,则将其活动对象作为变量对象
23、如何延长作用域链?(必会)
作用域链是可以延长的
延长作用域链:
执行环境的类型只有两种,全局和局部(函数)。但是有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除
具体来说就是执行这两个语句时,作用域链都会得到加强
- 1、try - catch 语句的 catch 块;会创建一个新的变量对象,包含的是被抛出的错误对象的声明
- 2、with 语句。with 语句会将指定的对象添加到作用域链中
23、判断一个值是什么类型有哪些方法?(必会)
方法 1、typeof 运算符 2、instanceof 运算符 instanceof 严格来说是 Java 中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:
// 判断 foo 是否是 Foo 类的实例
function Foo(){}
var foo = new Foo();
console.log(foo instanceof Foo) //true
3、Object.prototype.toString方法 在 JavaScript 里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”, ”string”, ”undefined”, ”boolean”,”object”,“function”,“symbol” ( ES6 新增) 七种 对于数组、null、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串 要想区别对象、数组、函数单纯使用 typeof 是不行的,JavaScript 中,通过 Object.prototype.toString 方法,判断某个对象值属于哪种内置类型。
在介绍 Object.prototype.toString 方法之前,我们先把 toString()方法和 Object.prototype.toString.call()方法进行对比
toString()方法和 Object.prototype.toString.call()方法对比
var arr=[1,2];
//直接对一个数组调用 toString()
arr.toString();// "1,2"
//通过 call 指定 arr 数组为 Object.prototype 对象中的 toString 方法的上下文
Object.prototype.toString.call(arr); //"[object Array]"
25、JavaScript变量按照存储方式区分为哪些类型,并描述其特点?(必会)
- 值类型和引用类型
- 值类型存储的是值 ,赋值之后原变量的值不改变
- 引用类型存储的是地址 ,赋值之后是把原变量的引用地址赋值给新变量 ,新变量改变 原来的会跟着改变
26、如何实现数组的随机排序?(必会)
方法一:
var arr = [1,2,3,4,5,6,7,8,9,10];
function randSort1(arr){
for(var i = 0,len = arr.length;i < len; i++ ){
var rand = parseInt(Math.random()*len);
var temp = arr[rand];
arr[rand] = arr[i];
arr[i] = temp;
}
return arr;
}
console.log(randSort1(arr));
方法二:
var arr = [1,2,3,4,5,6,7,8,9,10];
function randSort2(arr){
var mixedArray = [];
while(arr.length > 0){
var randomIndex = parseInt(Math.random()*arr.length);
mixedArray.push(arr[randomIndex]);
arr.splice(randomIndex, 1);
}
return mixedArray;
}
console.log(randSort2(arr));
方法三:
var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
return Math.random() - 0.5;
})
console.log(arr);
27、Function foo() {}和 var foo = function() {}之间 foo的用法上的区别?(必会)
区别
1、var foo = function () {}
这种方式是声明了个变量,而这个变量是个方法,变量在JavaScript 中是可以改变的。
2、function foo() {}
这种方式是声明了个方法,foo 这个名字无法改变 例:
function b(){
document.write("aa");
}
var a=function(){
document.write("123");
}
b();
a();
好像并没有什么区别,看下边
b();
a();
function b(){
document.write("aa");
}
var a = function(){
document.write("123");
}
是不是有区别了 function b(){} 为函数声明,程序运行前就已存在 var a = function(){} 为函数表达式,是变量的声明,属于按顺序执行,所以 a 为 undefined
28、索引有哪几种类型,有什么区别?(了解)
索引是对数据库表中一列或多列的值进行排序的一种结构,例如 employee 表的姓(name)列。如果要按姓查找特定职员,与必须搜索表中的所有行相比,索引会帮助您更快地获得该信息
索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引的方式与您使用书籍中的索引的方式很相似:它搜索索引以找到特定值,然后顺指针找到包含该值的行。在数据库关系图中,您可以在选定表的“索引/键”属性页中创建、编辑或删除每个索引类型。当保存索引所附加到的表,或保存该表所在的关系图时,索引将保存在数据库中。
可以基于数据库表中的单列或多列创建索引。多列索引使您可以区分其中一列可能有相同值的行。如果经常同时搜索两列或多列或按两列或多列排序时,索引也很有帮助。例如,如果经常在同一查询中为姓和名两列设置判据,那么在这两列上创建多列索引将很有意义。确定索引的有效性:检查查询的 WHERE 和 JOIN 子句。在任一子句中包括的每一列都是索引可以选择的对象。对新索引进行试验以检查它对运行查询性能的影响。考虑已在表上创建的索引数量。最好避免在单个表上有很多索引。检查已在表上创建的索引的定义。最好避免包含共享列的重叠索引。 检查某列中唯一数据值的数量,并将该数量与表中的行 数进行比较。比较的结果就是该列的可选择性,这有助于确定该列是否适合建立索引,如果适合,确定索引的类型
建立索引的优点: 1、大大加快数据的检索速度; 2、创建唯一性索引,保证数据库表中每一行数据的唯一性; 3、加速表和表之间的连接; 4、在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
索引类型 根据数据库的功能,可以在数据库设计器中创建四种索引:唯一索引、非唯一索引、主键索引和聚集索引。 尽管唯一索引有助于定位信息,但为获得最佳性能结果,建议改用主键 或唯一约束
唯一索引: 唯一索引是不允许其中任何两行具有相同索引值的索引。当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中 创建重复键值的新数据。例如,如果在 employee 表中职员的姓 (lname) 上创建了唯一索引,则任何两个员工都不能同姓
非唯一索引: 非唯一索引是相对唯一索引,允许其中任何两行具有相同索引值的索引。当现有数据中存在重复的键值时,数据库是允许将新创建的索引与表一起保存。这时数据库不能防止添加 将在表中创建重复键值的新数据
主键索引: 数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引 要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。
聚集索引(也叫聚簇索引): 在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与 非聚集索引相比,聚集索引通常提供更快的数据访问速度
29、简述 Array.form和 Array.of的使用及区别?(了解)
一、 Array.from(): 将伪数组对象或可遍历对象转换为真数组
Array.from()用法
Array.from 接受三个参数,但只有 input 是必须的:
- input: 你想要转换的类似数组对象和可遍历对象
- map: 类似于数组的 map 方法,用来对每个元素进行处理,将处理后的值放入返回的数组
- context: 绑定 map 中用到的 this
只要是部署了 iterator 接口的数据结构,Array.from 都能将其转为数组:
let arr = Array.from('juejin');
console.log(arr); //["j", "u", "e", "j", "i", "n"]
Array.from还可以接受第二个参数,作用类似于数组的 map 方法,用来对每个元素进行处理,处理后的值放入返回的数组
Array.from([1, 2, 3], (x) => x * x)// [1, 4, 9]
// 等同于
Array.from([1,2,3].map(x => x * x))
如果 map 函数里面用到了 this 关键字,还可以传入 Array.from 的第三个参数,用来绑定 this
Array.from()可以将各种值转为真正的数组,并且还提供 map 功能。这实际上意味着,只要有一个原始的数据结构,你就可以先对它的值进行处理,然后转成规范的数组结构,进而就可以使用数量众多的数组方法
Array.from({ length: 2 }, () => 'jack')// ['jack', 'jack']
二、Array.of(v1, v2, v3): 将一系列值转换成数组
当调用 new Array( )构造器时,根据传入参数的类型与数量的不同,实际上会导致一些不同的结果, 例如:
let items = new Array(2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // undefined
console.log(items[1]) ;
let items = new Array(1, 2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // 1
console.log(items[1]) ; // 2
当使用单个数值参数来调用 Array 构造器时,数组的长度属性会被设置为该参数。 如果使用多个参数(无论是否为数值类型)来调用,这些参数也会成为目标数组的项。数组的这 种 行为既混乱又有风险,因为有时可能不会留意所传参数的类型
ES6 引入了Array.of( )方法来解决这个问题。该方法的作用非常类似 Array 构造器,但在使用单个数值参数的时候并不会导致特殊结果。Array.of( )方法总会创建一个包含所有传入参数的数组,而不管参数的数量与类型:
let items = Array.of(1, 2);
console.log(items.length); // 2
console.log(items[0]); // 1
console.log(items[1]); // 2
items = Array.of(2);
console.log(items.length); // 1
console.log(items[0]); // 2
Array.of 基本上可以用来替代Array()或 newArray(),并且不存在由于参数不同而导致的重载,而且他们的行为非常统一
30、根据你的理解,请简述 JavaScript脚本的执行原理(了解)
原理
JavaScript 是一种动态、弱类型、基于原型的语言,通过浏览器可以直接执行
当浏览器遇到<script><\script>标记的时候,浏览器会执行之间的 javascript 代码。嵌入的 JavaScript 代码是顺序执行的,每个脚本定义的全局变量和函数,都可以被后面执行的脚本所调用。
变量的调用,必须是前面已经声明,否则获取的变量值是 undefined