1、基本类型和引用类型的区别
(分别从内存,赋值,函数传参的角度描述)
答: 1)、内存的角度: 基本类型在内存中,占据一块空间,空间里存储的就是值,所以也叫,值类型。获取值是属于直接获取 引用类型在内存中,占据两块空间,第一块存储的是地址,第二块存储的是值。也叫地址类型。获取数据是属于间接取值。 2)、赋值: 基本类型:赋的就是值 引用类型:赋的就是地址 3)、函数传参:(等价于把实参赋值给形参) 基本类型:传的是值 引用类型:传的是地址
4)、
基本类型有:Undefined、Null、Boolean、Number、String、Symbol,还有:Bigint,
引用类型有:统称为 Object 类型。
5)、可以写应用场景:
number:表示数字,如:年龄,成绩,金额,等会做加减乘除,比较大小等数学运算的数据
string:非数字信息的描述
boolean:表示是否(两种情况)
Symbol:表示唯一性时
引用类型:表示复杂的数据时,即:一个数据中包括了若干个信息时。
2、Undefined和null的区别
相同点:
都是数据类型,隐式转换为boolean类型时都是false。
概念上的区别:
1)、undefined: 是JavaScript的数据类型,表示定义变量后,没有赋值,表示值的缺失 2)、null: 对象没有引用的值,即就是:引用类型里没有存储地址。Null还可以用来清除堆区的标记,防止内存泄漏。表示对象的缺失
代码示例:
1) undefined:
var a; //JavaScript中定义一个变量,没有赋值时,默认为undefined
console.log(typeof a); // undefined
console.log(b); // 报错,因为b没有定义。所有,在浏览器的控制台中会报 b is not defined
2) null:
var person = null;//定义了一个引用类型,没有指向。
console.log(person); //输出null。
console.log(typeof person);//输出object,person的数据类型是Object,值是null
typeof的结果不同
1)、typeof undefined 的结果是undefined
2)、typeof null 的结果是object,所以,它个对象有关系。表示对象的缺失。
场景不同:
1)、undefined:
- 变量声明且没有赋值
- 获取对象中不存在的属性
- 函数需要实参,但是调用时没有传值,形参是undefined
- 函数调用没有返回值或者return后没有数据,接受函数返回值的变量
2)、null:
- 对象不存在就是null
- 手动设置变量的值或某一个属性值为 null
- JS 获取 DOM 元素,如果没有获取到指定的元素对象,返回 null
- 正则捕获时,如果没有捕获到,返回 null
- Object.prototype.proto 的值是 null
- document 和 body 很多属性都是 null
3、==和===的区别
1、相同点:
都是用来判断两个数据是否相等。
2、判断原理不同的:
===(恒等) 1、如果类型不同,就[不相等] 2、如果两个都是数值,并且是同一个值,那么[相等]。 3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等] 4、如果两个值都是true,或者都是false,那么[相等]。 5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。 6、如果两个值都是null,或者都是undefined,那么[相等]。
==(等同) :
1、如果两个值的类型相同,则按照===的思路进行比较
2、如果两个值的类型不同,先做隐式转换,把两个数据转换成同种类型,再进行判断。所以,给大家的感觉是不判断类型。
隐式转换规则:
```js
a、如果一个是null、一个是undefined,那么[相等]。 b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。 c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。 d、任何其他组合,都[不相等]。 ```
4、js的声明提升
答: js在预编译阶段,会对声明进行提升,如:声明变量(var),声明函数(function 函数名(){}) 1)、用声明的方式定义变量或者函数,会有提升 2)、声明的变量和函数会提升当前作用域的最顶端。 3)、变量声明,只提升声明不提升赋值;
5、Var、Let,const的区别?
答: 相同点:
这三个关键字都是用来定义变量的 不同点: 1)、var定义的变量会声明提升,let和const定义变量不会声明提升 2)、var定义的变量作用域是全局作用域和函数(局部)作用域,let和const是块级作用域(所在花括号) 3)、var定义的全局变量是window对象的属性,let和const定义的全局变量不是window的属性 4)、var可以定义多个同名的变量,let和const不行 5)、let有暂时性死区 6)、let在循环里,可以暂存循环变量。 7)、const定义的变量是只读的。const修饰的是直接指向(修饰)的内存。
6、const 定义一个数组,改变下标0的值,会报错吗
不会报错,const修饰的是数组,而不是数组的元素。
补充:const修饰引用类型时,都修饰的是地址。而不是数据。
<script type="text/javascript">
//const修饰的变量是只读,不能修改的,即是常量
//const修饰的是直接指向(修饰)的内存
function testf1(){
//1、const修饰的变量是只读,不能修改的,即是常量
//const temp1 = 100;//定义了一个变量temp1,赋值为100,const表示以后不能再修改了
//temp1 = 200;//这句话会报错,不能给只读变量赋值(Assignment to constant variable.)
//2、const修饰的是直接指向(修饰)的内存
const arr = [12,23,34];//引用类型在内存中是两块区域,const修饰的是arr(arr是在栈区)
arr[0]=100;//修改的是堆区的内存
console.log(arr);
arr = [1,2,3];//这句话要报错,因为,这句话像改变arr(栈区)的地址
}
window.onload = function(){
testf1();
}
</script>
7、作用域和作用域链
作用域: ,就是变量起作用的区域(范围)。或者说,js代码执行时,查找变量的范围。
作用域链: :当js编译器在寻找变量时,先在最近的作用域(花括号)里找,如果找不到,则朝上一级作用域(花括号)里找,依次类推,直到找到或者找不到为止。这就是作用域链。
详细请阅读:blog.csdn.net/jiang770103…
8、数组的api
9、请描述你对事件流的理解
答:事件流就是事件的流向。事件流分为三个阶段:捕获阶段,事件源,冒泡阶段。
https://blog.csdn.net/jiang7701037/article/details/81481550
10、事件委托
1)、原理和思路:
利用dom事件的冒泡,完成,把dom元素的事件由父元素进行处理。即:在父元素进行事件绑定,完成子元素想要完成的功能。并在父元素的事件处理函数里,使用事件对象的target来判断是否为子元素触发事件。
2)、优点:
减少了代码量
让动态添加的子元素也会具有事件的功能。即:子元素的dom操作,不会影响事件绑定。
3)、示例:
假设一个ul标签里有5个li,请使用事件委托的方式完成,点击每个li,显示每个li里的内容
Ul.onclick = function(event){
Let e = event ||window.event;
if(e.target.tagName.toLowerCase()==”li”){
Console.log(e.target.innerHTML);
}
}
11、this的理解?
1、是什么?
this是函数的内置对象。this是代名词。this代表谁,需要看场景(上下文),在js中函数就是this的场景。所以,this一般都是出现在函数内部(其实这个本质是作用域)。
2、this的几种情况(静态的描述) 以下情况所说的函数是非箭头函数。
1)、当this所在函数是事件处理函数时,this表示事件源。
2)、当this所在函数是构造函数时,this表示new出来的对象。
3)、当this所在函数是实例(对象)的方法时,this表示调用该方法的对象。
4)、当this所在函数是全局声明的函数时,
4.1)、非严格模式下:this表示window。(其实这个点和第三点一样)。因为,全局函数都是window对象的方法
4.2)、严格模式下:this是undefined。
5)、this在script标签里,表示window。
3、真正的this,需要看调用(深深的知道就行,面试时,可以不用回答这个)如:。
1)、call,apply,bind是可以改变this指向的。
2)、所谓的构造函数,我也可以不用new调用把。
3)、所谓的全局函数,我也可以把它赋给事件属性。
4、箭头函数是没有this的。
既就是:在判断this指向时,不要把箭头函数当函数看待。
一般人我不告诉他:箭头函数在编译的原理里是词法分析域
12、call,apply和bind的区别
一、文字描述:
1、相同点:
三个函数都会改变this的指向(调用这三个函数的函数内部的this)
2、不同点:
1)、bind会产生新的函数,(把对象和函数绑定死后,产生新的函数),新的函数的所有调用都会是绑定的this。
2)、call和apply不会产生新的函数,只是在调用时,绑定一下而已。
3)、call和apply的区别,第一个参数都是要绑定的this,apply第二个参数是数组(是函数的所有参数),call把apply的第二个参数单列出来。
二、示例代码:
<body>
<!-- <input type="button" value="测试" onclick="testf()" /> -->
</body>
<script type="text/javascript">
//demo07面试题:请问bind,call,apply的区别
//1、相同点:
// 三个函数都会改变this的指向(调用这三个函数的函数内部的this)
//2、不同点:
// 1)、bind会产生新的函数,(把对象和函数绑定死后,产生新的函数)
// 2)、call和apply不会产生新的函数,只是在调用时,绑定一下而已。
// 3)、call和apply的区别,第一个参数都是要绑定的this,apply第二个参数是数组(是函数的所有参数),call把apply的第二个参数单列出来。
//示例代码:
var p1 = {
name:"隔壁老王",
}
function eat(str,drinkstr) {
console.log(this.name+"在吃"+str+",同时在喝"+drinkstr);
}
//1、bind:
let f1 = eat.bind(p1);//f1是个函数。即,用bind把eat函数和p1对象绑死,产生新的函数叫作f1
f1("油条","豆浆");//调用f1,就相当于 p1.eat();,内部的this就是p1,永远都是p1,不会是window
//2、call:
eat.call(p1,"油泼面","面汤");//不会产生新的函数,只是临时把eat函数和p1对象绑定一下。
//3、apply:(与call的意思一样,只是第二个参数是数组,是原函数eat的参数)
eat.apply(p1,["油泼面","面汤"]);//不会产生新的函数,只是临时把eat函数和p1对象绑定一下。
</script>
13、构造函数和普通函数的区别(面试题):
1)、函数名的首字母大写
2)、构造函数的调用,是用new运算符。
3)、构造函数内部,在预编译时,还会增加 var this = new Object();
4)、构造函数(看上去)没有返回值,但是,其实是有的。即:虽然程序员没有写返回值,预编译时,会增加返回值
预编译时,会增加一句:return this。
14、构造函数的执行过程(面试时有时会问):
1、立刻在堆内存中申请空间,这个空间就是新的对象的内存空间
2、将新建的对象设置为函数中的this
3、逐个执行函数中的代码
4、将新建的对象作为返回值 return this
15、原型和原型链
1、原型:
1)、每个构造函数(类)都会有一个原型属性(prototype)。
2)、原型属性的目的:
让所有实例共享属性和方法,共享的是构造函数(类)的原型属性(prototype)上的属性和方法。因此,节约了内存。实例是通过 __proto__属性找到构造函数(类)的prototype属性的。
3)、原型属性里还有一个constructor属性,指向构造函数(类)本身。
2、原型链
当使用对象访问属性或者方法时,先从对象本身的内存中寻找,如果找不到,就去 __proto__(原型)指向的内存中(类的prototype)寻找,如果找不到,则在类的原型的 __proto__(父类的prototype)寻找,以此类推,一直找到Object,如果没有找到,则显示出错(如: *** is not defined)。
这种一直沿着属性 __proto__ 朝上寻找,就是原型链的寻找。也就是原型链的意思。