数据类型


- B选项。
- 任何数值除以0都会导致错误而终止程序执行。但是在 JavaScript 中,会返回出特殊的值,因此不会影响程序的执行。
- 比0大的数除以0,则会得到无穷大,所以 js 用 Infinity 来显示出来。
- 也就是1/0得到的是Infinity。
- isNaN(1/0)返回的是false。但是isNaN(0/0)返回的就是true
- C选项。
- in操作符,对于数组属性需要指定数字形式的索引值来表示数组的属性名称(固有属性除外,如length)。
- 所以说在这里,1 in [1]并不是表示数字1在不在数组里。而是表示数组中含不含有1这个索引index值。
数组长度为1,所以只含有的index值为0,这个表达式返回fasle。

变量a为number类型,属于基本数据类型,基本数据类型在传参时,通过拷贝值进行传递。
因此,在函数内部修改形参时,不会对实参产生影响,故输出a的值为10。
数组
解构赋值
for(let i=0;i<12;i++){} console.log(i);const a = 12;a=13;console.log(a);const g = {b:3};console.log(g.b);g.b=12;console.log(g.b);let [head,...tail] = [1,2,3,4];conole.log(tail);//i not defined,TypeError,3,12,[2,3,4]
1.let 与var不同,存在块级作用域,在for循环中声明,循环之外销毁 所以 i not defined
2.const 声明一个常量无法更改,所以TypeError
3.const 声明的是一个常量所以是无法更改的
如果const出来的是一个对象他的属性是可以更改的。
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。var a = 1; var b = 2; var c = 3;
ES6允许写成下面这样。
var [a, b, c] = [1, 2, 3];let [foo, [[bar], baz]] = [1, [[2], 3]];foo // 1 bar // 2 baz // 3let [x, , y] = [1, 2, 3];x // 1 y // 3let [x, y, ...z] = ['a'];x // "a" y // undefined z // []let [head, ...tail] = [1, 2, 3, 4];head // 1 tail // [2, 3, 4]let [ , , third] = ["foo", "bar", "baz"];third // "baz"
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
如何判断为数组
A:Array 为 js 的原生对象,它有一个静态方法:Array.isArray(),能判断参数是否为数组
B:instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例(题目中 instance of , emem)
C: typeof 能判断类型有:number、string、boolean、symbol、undefined、function;
object、array、null 的变量都返回 object
D:Object.prototype.toString() 为 Object 对象的实例方法,默认情况下(即不重写该方法),返回参数的类型字符串。
对象
let obj = {num1: 117}let res = obj;obj.child = obj = { num2: 935 };var x = y = res.child.num2;console.log(obj.child);console.log(res.num1);console.log(y);
this
1)当在函数调用的时候指向widow
2)当方法调用的时候指向调用对象
3)当用apply和call上下文调用的时候指向传入的第一个参数
4)构造函数调用指向实例对象
var obj ={a:1,b:function () {alert(this.a)}};var fun = obj.b;fun();// 输出undefined// 虽然fun是obj.b的一个引用,但是实际上,它引用的是b函数本身,因此此时的fun()// 其实 是一个不带任何修饰的函数调用,所以this指向window。
var obj = {};obj.log = console.log;obj.log.call(console,this);obj.log = console.log;//在本行中obj对象中创建了一个函数(即console.log)的引用log,//因为是个这个函数的引用如果想要执行可以有两种方法,第一种是后边加(),//第二种是使用apply()或者call(),二者第一个参数都是this,//接下来的参数apply是参数数组或者是"arguments",而call的参数是直接的参数值obj.log.call(console,this);//如上所述,call的第二个参数是要被传入obj.log()的参数,//这行代码其实可等价于console.log(this),而因为这三行代码都是在global环境下定义的//(不是函数中的局部变量),所以this就是window.//至于第一个参数为什么是console而不是this,我觉得console被按照this处理了,//我试了试,替换后的执行结果相同
迭代器
function control(x) {if (x == 3) throw new Error("break");}function foo(x = 6) {return {next: () => {control(x);return {done: !x, value: x && x--};}}}let x = new Object;x[Symbol.iterator] = foo;for (let i of x) console.log(i);
1、什么是迭代器?
迭代器是一个对象,需要满足:对象内部有方法next,next方法要求返回对象{done: true或false, value:值 }
!!!(注意区分:迭代器 和可迭代对象 是不一样的)
2、一个迭代器是如何遍历的?
constarr = ["a","b"]// 数组默认是一个可迭代对象,就好比题目中的对象xconstiterator = arr[Symbol.iterator]() // 拿到迭代器console.log(iterator.next());console.log(iterator.next());// { value: 'a', done: false }// { value: 'b', done: false }// { value: undefined, done: true }
不难看出,value表示每次遍历的值,而done表示遍历是否完成。
3、for…of…补充
for… of…的使用需要是一个可迭代对象,这道题的x,也是因为是一个可迭代对象,所以才可以用的for…of
可以理解为:for..of..就是上面调用iterator.next()的语法糖,直到最后done为true表示遍历完了。…
4、什么是可迭代对象?
如果一个对象,实现了[Symbol.iterator]方法,且这个方*返回一个迭代器(这个方法就是一个生成迭代器的函数,比如题目中的foo函数)
function foo(x = 6) {return{ // 返回一个迭代器next: () => {control(x);return{done: !x, value: x&&x-- };}}}// x成为可迭代对象x[Symbol.iterator] = foo
5、得结果
for(let i of x) console.log(i);
既然x是可迭代对象,那他可以用for…of…进行遍历,遍历时会自动去执行foo,foo返回迭代器。
上面也说了for…of…的遍历就是:一次次的调用iterator的next,拿到value,直到next返回的done为true。
function foo(x = 6) {return {next: () => {control(x);return {done: !x, value: x && x--};}}}
里层next函数调用的x是foo的参数x(闭包),x默认赋值为6,通过题目中的control函数可以知道,x=3的时候,就抛错,结束了。
当x=6,return{ done:!x, value: x && x—}
done为false,value是x && x—
6 && 6, &&前者为true,value结果取后者,return { done:false, value : 6},
然后x—变成5
继续。。。。最后结果
6,5,4,抛错
闭包
function outer(){var num = 0;function inner(){num++;console.log(num);}return inner;}var f1 = outer();f1();f1();var f2 = outer();f2();f2();// 1 2 1 2
闭包变量为num,内部函数inner可以访问到外部函数outer的num变量,这相当于授权该变量可以被延迟使用,每次调用外部函数时,都会开辟相应的内存空间,闭包变量num会保存在该内存空间中,直到该外部函数的内存空间被销毁。
在本题中,调用外部函数outer时开辟一个内存空间,变量num保存在该内存空间中,因此两次调用f1的输出结果为1 2;当再次调用外部函数outer时,又重新创建一个内存空间,因此两次调用f2的输出结果同样为1 2。
Javascript 预处理
Javascript分为预处理阶段和执行阶段,尽管if里面的语句不会被执行,但是在预处理阶段还是会将其提升,因此最终还是undefined。
var a = 1;function test() {console.log(a);if(false) {var a = 2;}}test();————————————————————————————————————————————————————————————————————————————————————//其实代码执行过程如下:var a ;a = 1;function test() { //函数会先去找自己内部的变量,内部有就不会往外面找,内部没有才去外面找var a; //变量提升console.log(a);if(false) { //因为false没有满足if的条件,所以不能进入if语句里进行赋值a = 2; //if语句的条件把false改成true,就可以进入if语句赋值}}test();// 因此最终输出undefined
promise
:::warning
三个状态 pending fulfilled rejected
两个过程 pending->fulfilled(resolve) pending->rejected(reject)
一个方法 then
:::
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
- promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
- then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
