1.undefined 和 null 有什么区别?
他们的相同之处: 他们都是javascript的7种基本类型, 它们都是虚值, 他们转为布尔值都是false, undefined == null 返回true. 严格相等下返回false, 因为他们的类型不同,
区别在于undefined
是指为指定特定的变量的默认值.或者没有显示返回值的函数.还包括对象中不存在的属性, 这些js引擎都会为其分配undefined值.
let a;
const obj = {name:"ww"};
console.log(obj.age) // undefined
function add(){}
console.log(a)// undefined;
console.log(add())// undefined;
null是表示不代表任何值的值, null是已明确给定定义变量的值, 在使用typeof 判断null的类型时返回的是object;
typeof null // object
2 &&运算符可以做什么?
&&符也可以叫做逻辑与,在其操作数找到第一个虚值,虚值即false并返回它,如果没有找到任何虚值,则返回最后一个真值表达式.它采用短路来防止不必要的工作;
通过用于判断条件表达式是否都成立, 如果都成立,则返回true, 否者返回false;
let a = 32;
if(a > 20 && a % 2 == 0){ // 只有当判断条件都为true时,才会打印a
console.log(a)
}
3 . ||运算符可以做什么
||也可以叫做逻辑或, 在其操作数中找到第一个真值表达式并返回它,它也使用了短路来防止了不必要的工作,在es6支持函数参数默认值之前, 它用于初始化函数中的默认值.
function log(target){
var = target || "params";
console.log(target)
}
上面的代码中当函数log的参数target没有传递时, 此时target为false, 此时|| 操作符返回 第二个操作数 params;
通常 || 也用与if判断条件, 只有当判断条件中有一个为true, 整体就返回true
4 使用+或一元运算符是将字符串转为数字的最快方法吗?
根据MDN文档, +是将字符串转为数字的最快方法, 因为如果值是数字, 他不会执行任何操作.
let str = "32,21"
let result = str.split(",").map((v) => +v);
console.log(result)// [32, 21]
上面的代码可以很优雅的将类型数组的字符串 转为一个真正的数组
5. DOM是什么
DOM
表示文档对象模型. 是HTML和XML文档接口(API). 当浏览器第一次读取HTML文档时, 它会创建一个大对象, 一个基于HTML文档的非常大的对象, 这个对象就是DOM
.它是一种HTML文档建模的树状结构.通常DOM用于交互和修改DOM
结构或特定元素的节点.
假设我们有如下的HTML结构;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello document</h1>
</body>
</html>
等价的DOM
是这样的
在js中, document对象表示DOM,它为我们提供了许多方法, 我们可以用这些方法来选择元素或者更新元素内容等等.
6. 什么是事件传播?
当事件发生在DOM元素上时, 改事件并不完全发生在那个元素上.在冒泡阶段
中事件冒泡向上传播到父级.,一直到window为止. 而个捕获阶段
时,事件从window开始向下触发元素, 事件活event.target.
事件传播有三个阶段 顺序如下:
- 捕获阶段 -- 事件从window开始.然后向下到每个元素, 直到到达目标元素.
- 目标阶段 -- 事件已达到目标元素.
- 冒泡阶段 -- 事件从目标元素冒泡, 然后上升到每个元素, 直到window.
7 什么是事件冒泡?
当事件发生在DOM元素上时, 该事件并不完全发生在那个元素上. 在冒泡阶段,事件冒泡.事件会一直往它到底父级向上传播,直到window为止.
假设我们有如下的htmll结构代码
<div class="parent">
<div class="child"></div>
</div>
js部分如下
let parent = document.querySelector(".parent"),
child = document.querySelector(".child");
parent.addEventListener("click", function(){
console.log("parent");
},false)
child.addEventListener("click", function(){
console.log("child");
},false)
addEventListener的方法接受第三个可选参数, 其默认值为false,此时事件在冒泡阶段执行,如果为true,则在捕获阶段执行.
当我们点击child触发点击事件时. 此时事件在冒泡阶段执行,控制台会先打印child,然后在打印parent.事件会一直传播到window对象上, 这就是事件冒泡.
8 . 什么是事件捕获?
当事件发生在DOM
上时, 改事件并不完全只发生在那个元素上,在捕获阶段,事件从window开始传播, 一直到触发事件的元素时结束
如果把上道题的绑定的事件监听第三个参数为true时, 此时事件在捕获阶段执行, 此时如果点击了child, 控制台会先打印parent,然后在打印child
9 . event.preventDefalut ()和 event.stopProPagation ()方法之间有什么区别?
event.preventDefalut()
方法用来阻止元素的默认行为.如果在表单元素中使用, 它将会阻止其提交, 如果在锚元素中使用. 它将会阻止其导航.元素的默认行为通常是元素身上自带的事件行为.例如当点击a标签时,会跳转到别的网页.
event.stopProPagation 方法()通常用来阻止捕获和冒泡阶段中当前事件的进一步传播。
10 . 如何知道是否在元素中使用event.stopProPagation属性?
我们可以通过事件对象调用event.defalutPrevented属性, 它返回一个布尔值用来表明在特定元素中是否调用了
event.stopProPagation();
10 . 为什么此代码 obj.some.x会发生错误?
const obj = {}
console.log(obj.some.x)
因为obj本身并没有some属性,此时obj.some为undefined, 对象不存在的属性,默认为undefined,显然undefined并没有属性x, 访问试图访问就会报错.
12 . 什么是event.target
简单来说, event.target
就是当前发生事件的目标元素或触发事件的元素.
假设我们有下面的html结构代码
<div>
<button>点击</button>
</div>
假设我们给button和div都绑定了点击事件, 当我们点击了button时,此时event.target为button元素.
当我们点击了div,此时event.target为div元素.
因此我们得出结论, event.target就是触发事件的元素.
13 什么是event.currentTarget
?
event.currentTarget
是我们在其显式附加事件处理程序的元素.
同上,当我们点击了button元素时, 如果我们在控制台打印event.currentTarget
,此时不仅会打印button也会打印div元素.我们可以得出结论,event.currentTarget会监听触发了事件的所有元素.并将他们返回.
14 .== 和 === 有什么区别?
== 运算符也叫 相等, 用来判断两个操作数是否相等. 这里的相等定义非常宽松,在比较的时候可以允许类型转换, === 用于严格比较. 只要类型不一致就会返回fasle;
在== 比较下,假设如果我们要比较 x 和 y的值
- 当俩数类型都相同时, 则js 引擎会换成 === 操作符进行比较
- 当俩数类型一个为string另一个为number时, 那么此时类型为string的会发生隐式类型转换,转为number类型进行比较
- 当俩数类型中有一个为boolean类型时,俩数都会被转为数字类型进行比较.
console.log("1" == 1) //true
console.log("1" === 1) //false
15 .为什么在JS中比较两个相似的对象会返回false?
let one = {a:1};
let two = {a:1};
let c = a;
console.log(a === b) // false ,因为他们在内存指向的不是同一个对象
console.log(a === c) // true
js比较基本数据类型时,比较的时他们的值,而在引用数据类型比较时, js会比较他们的引用或储存变量的内存地址.所以第一个返回false.第二个返回true, 因为他们都在内存中都指向同一个地址或引用
16. !! 运算符能做什么?
!!运算符可以将右侧的值强制转为布尔值.这也是将值转为布尔值的一种简单方法.
console.log(!!null) // false;
console.log(!!undefined1)// fallse
17 . 如何在一行中计算多个表达式的值?
可以使用,运算符在一行中计算多个表达式.它从左往右求值,并返回最后一个项目或最后一个操作数的值
let x = 4;
x = (x++,x = addSix(x), x *= 5, x += 10);
function addSix(num){
return num + 6
}
上面的结果最后得到的x的值为65,首先我们让x++到5,如何调用函数返回11并赋值给x, 然后在计算x 加上x * 5然后 赋值给x,此时x为55.接着在让x += 10 此时x为 65;
18. 什么是提升?
提升
就是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语
为了理解提升,需要了解一下执行上下文
.执行上下文是当前正在执行的代码环境
.执行上下文有两个阶段:编译
和执行
编译
-在此阶段,JS引擎会获取所有的函数声明并将其提升到作用域顶部, 以便我们稍后可以引用它们并获取所有的变量声明(使用var关键字声明), 还会为它们提供默认值undefined
执行
- 在这个阶段,它将值赋值给之前提升的变量, 并执行或调用函数(对象中的方法).
注意
只有使用var声明的变量, 或者函数声明才会提升,其他使用箭头函数,或者函数表达式,let和cosnt声明的变量,这些都不会提升
变量提升和函数提升在代码中的位置是不会变的,而是在编译阶段放在内存中
console.log(a) //变量a存在提升,此时a的默认值为undefined, 所以此时打印undefined
var a = 1;
console.log(a) // 1
console.log(sayHi("ww"));// helloww
function sayHi(name){
return "hello" + name
}
上面的代码在编译阶段其实是这样的
function sayHi(name){
return "hello" + name
}
var a;// 默认值为undefined
// 等待编译完成., 然后开始"执行"阶段;
console.log(a);// undefined
a = 1;// 此时变量给 a 赋值
console.log(a) //1;
console.log(sayHi("ww"))
函数声明会提提升到作用域最顶层并赋值,所以我们可以在函数声明之前调用函数,
19 . 什么是作用域?
javascript中作用域是指我们能够有效访问变量或函数中的区域.JS有三种类型的作用域:全局作用域
,函数作用域
和块级作用域
(ES6)
全局作用域
-- 在全局命名空间中声明的变量或函数位于全局作用域, 因此在代码中的任何区域都可以访问到他们
var say = "hello"
function global(name){
console.log(say) // hello
return "hello" + name
}
global()
函数作用域
-- 在函数中声明的变量,函数和参数都可以在函数内部访问, 但不能在外部访问,只能在函数内部进行访问.
function myFn(){
var a = 45;
}
console.log(a)// a is not defined
块级作用域
-- 在块{ } 中声明的变量(let,const
)只能在其中访问。
function fn(){
if(true) {
let x = 2
}
console.log(x)
}
fn()//x is not defined
作用域链一种用于查找变量的规则,如果变量在当前作用域内不存在,它就会往外部作用域链内查找,如果该变量还是不存在,他会一直找直到全局作用域,如果找到了就可以使用它,否者就报错.这种查找过程就叫作用域链
作用域链只能从内部作用域往外部作用域进行查找,不能从当前作用域往内部作用域查找.
20 . 什么是闭包?
闭包是一种函数和对其周围状态的引用捆绑在一起构成闭包.也就是是闭包可以让你从函数内部作用域访问函数内部作用域.在js中,每当函数被创建,就会在函数生成时形成闭包.
var three = "three";
function fn(one){
return function(two){
console.log(one,two,three)
}
}
fn("one")("two")
上面的代码会打印 one, two,three,当我们调用了函数fn时,此时我们传递的值会被赋值给变量one,此时fn函数作用域内就有变量one,因为fn调用完返回了一个新函数,此时我们可以加括号继续调用,此时我们传递了一个参数,此时返回的函数内部变量two的值就为two, 当返回的函数在内部进行打印时,它会在作用域链依次查找变量one,two,three,因为此时产生了闭包,所以我们可以访问到外部函数内的变量one,然后接着访问到了自身作用域的two,接着访问到了全局作用域的three.
21 . 虚值是什么?
简单的来说虚值就是在转换为布尔值时变为false的值.
const falseValues = ["",null,undefined,NaN,false,0]
22 . 如何检测值是否为虚值?
使用Boolean
函数或者!!运算符
23. "use strict"是干嘛用的?
use strict
是ES5的特性, 它使我的的代码在函数或整个脚本中处于严格模式.严格模式帮助我们在代码的早起避免bug,并为其添加限制.
设立严格模式的目的,主要有几个:
- 消除javascript语法的一些不合理, 不严谨之处, 减少一些怪异行为
- 消除代码运行的一些不安全之处, 保证代码运行的安全
- 提高编译器效率, 增加运行速度
- 为未来新版本的javascript做好铺垫
- 规范我们写代码的时要遵守的限制.减少了bug.
24 javascript中this
值是什么?
基本上. this
指的是当真执行或调用改函数的对象的值.this的值的变化取决于我们使用它的上下文和我们在哪里使用它.
const student = {
Name:"张三",
Score:45,
getStudentInfo(){
return "学生姓名为" + this.Name + "成绩为" + this.Score
}
}
console.log(student.getStudentInfo())// 学生姓名为张三成绩为45
let child = studnet.getStudentInfo;
console.log(child())// 学生姓名为undefined成绩为undefined
child = studnet.getStudentInfo.bind(student)
console.log(child())// 学生姓名为张三成绩为45
上面的代码中我们通过对象student调用了getStudentInfo方法, 此时函数内部this指向了student,所以我们可以得到this.name和this.age的值. 说明了this指向了当前调用函数的对象的值
如果我们通过child执行函数时,此时调用函数的对象则时window, 因为window上没有Name和Score属性,所以返undefined,如果我们要让child的函数this绑定在student,可以通过bind方法显式的改变函数的this指向.此时我们就可以在控制台打印出想要的数据.
网友评论