目录
10、js 中Object.is () 与比较运算符 === 和 == 的区别
15、js中 isNaN 与 Number.isNaN() 的区别
16、es6中的 const 定义的 对象的属性 可以修改吗?
17、ES6中 let、 const 和 var 之问的用法以及区别
24、js 中如何判断 一个属性 是属于实例对象 还是继承与构造函数
25、js 中bind 和call 、apply 的作用以及他们的区别
27、什么是回调地狱(多个串联的异步操作)以及如何使用Promise解决
31、Js中ajax(Async Javascript and XML)的原理是什么?如何实现
32、Js中localstorage和sessionStorage的区别
1、JS基本数据类型中null和undefined区别
// 基本数据类型中null和undefined的区别以及应用:
// 都是代表没有值
/*
null表示“没有对象”, 该处不应该有值
undefined表示“缺少值”, 该处应该有值,但是还没有定义
转为数值也不同,null转为数值为e,undefined转为数值NaN(不是一个数字)
*/
console.log(Number(null));
console.log(Number(undefined));
/*
什么时候会有null:
1、作为函数的参数,表示该函数的参数不是对象2、作为对象原型链的终点
什么时候会出现undefined:
1、变量被声明了。但是没有赋值,就等于undefined.
2、调用函数时,应该提供的参数没有提供,该参数就等于undefined。3、对象没有赋值的属性,该属性的值为undefined。
4、函数没有返回值时,默认返回undefined。
*/console.log(object.getPrototypeof(object.prototype));
var a;
console.log(a)
2、js有哪八种 数据类型
// javascript有哪些数据类型,它们的区别? // 总共有八种
// 基本数据类型: string/number/boolean/null/undefined/BigInt/symbo1(代表创建之后独一无二并且不可变的数据类型)
//引用数据类型: object
/* 区别
1、声明变量时的存储分配
基本数据类型 存储在栈中,var a=10
引用数据类型 存储在堆中, var arr=[1,2,3,4,5,...]2、不同的内存分配机制也带来了不同的访问机制
不可以直接访问堆内存空间的位置以及直接操作堆内存空间,只能操作对象在栈内存中引用地址基本数据类型直接访问到,引用数据类型访问引用地址,根据引用地址找到堆中实体
3、复制变量时的不同
基本数据类型:var a=1,var b=a,将原始值的副本赋值新的变量
引用数据类型:var obj={name:'张三"}, var obj1=obj,将引用地址赋值给新的变量*/
var a=[1,2,3,4,5];
var b=a;
var c=a[0];
console.log(b); //[1,2,3,4,5]
console.log(c); //改变数值 1
b[4]=6;
c=7;
console.log(a[4]); //[1,2,3,4,6]
console.log(a[0]); // 1
3、作用域与作用域链
// 全局
// let name= ' 你好啊 '
// 声明变量 js => 1: let name => 作用域集合中,有继续,没有添加这个name属性 2:执行name= ‘你好啊’ ,在运行时赋值
-------
// console.log(name) // 变量提升 声明的变量没有赋值,为undefined
// var name=' 你好啊 '
------------------------------------------------------------------------------------
// 局部作用域
function fun(){
let name= ' 你好啊 '
console.log(name) // 你好啊
}
fun ()
--------------------------------------------------------------------------------------
let name2 =' 悟空1'
function fun(){
console.log(name2)}
fun() //悟空1
全局:name2 fun() 局部:name2// 作用域: 就是一个规则 用来查找变量
// 作用域链:多层嵌套作用域
//
let d = 4
function fn(){
let c = 3 + dconsole.log(c) // 7
function fn1(){
let b = 2 + d // 6console.log(b) // 6
function fn2() {
let a = 1
}}
fun1()
}
console.log(fn()) // fn()没有返回值,默认返回 undefined
-----------------------------------------------------------------------------------
// 面试题
let a =1
let a= 1
function fn1(){
function fn2(){
console.log(a) // fn2 的作用域里没有a ,找上一级 fn1 a=2
}
function fn3(){
let a= 4fn2()
}
let a= 2 //在 fn2 的作用域里return fn3 // 最后执行的是 fn2
}let fn = fn1()
fn() // 返回 fn3
//
//全局 a =1 fn1()
//fn1 fn2 fn3 a=2
//fn2
//fn3-----------------------------------------------------------
let a= 1
function fn1(){
function fn3(){
function fn2(){
console.log(a)//
}
let a // 没有赋值
fn2() 执行到这里的时候,内存里面已经有一个没有赋值的a了a = 4
}
let a= 2return fn3()
}
let fn = fn1()console.log(fn) // undefined
4、闭包
//概念:
1 函数中返回一个函数
2 函数的声明的作用域和函数使用的作用域不同
//用途:1 获取私有作用域的中的变量
2 这些变量可以保存到内存中
function a(){
let n = R //保存到内存中function add(){
n++
return n}
return add
}
let getN = a()
console.log( getN()) // console.log( getN()) //2
5、js数据类型检测的方式有哪些?
// 1、typeof() 检测数据类型的运算符
// console.log("数值"",typeof 10); // 数值 number// console.log("布尔" ,typeof true); // 布尔 boolean
// console.log("字符串",typeof"你好"); // 字符串 string
// console.log("数组"",typeof []); // 数组 object 引用类型
// console.log(""函数"",typeof function O0); // 函数 function// console.log("对象"",typeof 0); // 对象 object 引用类型
// console.log("undefined",typeof undefined); // undefined undefined// console.log("null"",typeof nul1); // null object 基本数据类型 null为0,被识别为0(所有的值在计算机中是以二进制编码存储,浏览器把前三位为0的识别为object对象)
// 2、instanceof 检测某一个实例是否属于这个类 (不能用来检测 null和 undefined)可以正确判断对象的类型,内部运行机制 判断他在原型链上能否找到这个类型的原型
// console.log("数值"",10 instanceof Number); // 数值 false// console.log("布尔"",true instanceof Boolean); // 布尔 false
// console.log("字符串","你好’instanceof String); // 字符串 false
// console.log("数组"",D]instanceof Array); // 数组 true
// console.log("函数"",function O)0instanceof Function); // 函数 true// console.log(""对象"",0 instanceof 0bject); // 对象 true
// 3、constructor 检测实例和类的关系,从而检测数据类型,引用原来构造该对象的函数(不能用来检测 null和 undefined)
// console.log(“数值”,(10).constructor === Number); // 数值itrue// console.log("布尔"",(true) . constructor === Boolean); // 布尔 true
// console.log("字符串”,(你好:).constructor === String); // 字符串true
// console.log("数组"",([]).constructor === Array); // 数组ltrue
// console.log("函数" ,(function()0).constructor === Function); // 函数true// console.log("对象"",(0).constructor === 0bject); // 对象 true
// 4、Object-prototype.tostring.call ()
// var a=Object.prototype.tostring;
// console.log("数值" , a.cal1(10)); // 数值 [object Number]// console.log("布尔"", a.cal1(true)); // 布尔 [object Boolean]
// console.log("字符串", a.call(你好")); // 字符串 [object String]
// console.log("数组", a.cal1([])); // 数组 [object Array]
// console.log("函数" , a.call(function())); // 函数 [object Function]// console.log(""对象"", a.cal1(0)); // 对象 [object object]
// console.log("undefined",a.call(undefined)); // undefined [object undefined ]// console.log("null",a.cal1(nul1)); // null [object Null]
6、instanceOf操作符的实现原理及实现
// Js中instanceof操作符的实现原理以及实现
// instanceof 操作符 用于判断 构造函数 的 prototype 属性是否出现在对象的原型链中的任何位置。console.log(0 instanceof objecty;
// 构造函数 相当于一个类
function Person(name){
this. name= name
}
let obj= new Person(' 张三 ')
console.log( Object.getPrototypeOf(obj) ) //
console.log( Object.prototype ) //打印原型
console.log( Object.getPrototypeOf(obj)===Object.prototype ) // true
console.log(obj instanceof Person ): // true
console.log(obj instanceof Object ): // true
console.1og(object.getPrototypeof(object.getPrototypeof(obj))===Object.prototype); // true
--------------------------------------------------------------------------------------手写实现原型链的实现原理
function instance(left,right){ // 获取对象的原型 let proto = object.getPrototypeof(left); // 获取构造函数的 prototype 属性 let prototype= right.prototype; while(true) { //判断原型能不能获取到 if( !proto) { // 取不到返回 false return false } if(proto===prototype){ // 判断对象的原型和构造函数的原型 相等 return true } // 如果没有找到,就继续在原型链上找 proto = object.getPrototypeOf(proto) } }
7、js 中 typeof NaN的结果是什么
// NaN ( not a number ) 不是一个数字 ,表示是否属于number类型的一种状态,是或否,不是确切的值
// js中 number 数据类型除了浮点型和整数型,还有一个特殊值NaN
console.log( typeof NaN ) // Number
var a = ' abc '
console.log( Number(a));
//NaN,表达式中存在不可转化的变量,返回了无效的结果,不是返回确切的值
// NaN不等于本身,不是确切的值,代表一个范围
console.log(NaN == NaN) ; // false // 因为NaN不是一个确切的值
console.log(NaN I== NaN); // true
8、js 中判断数组的方法
1 、JS中判断数组的方法
// 通过object.prototype.tostring.call () 做判断;console.log(Object.prototype.toString.call ( [ ] ) ) // 是字符串 [Object Array ] console.log(Object.prototype.toString.call ( [ ] ). slice(8, -1) ) // Array console.log(Object.prototype.toString.call ( [ ] ). slice(8, -1) === 'Array' ) //true
// 通过原型链 做判断
// 对象的隐式原型等于构造函数的显式原型
console.log([._proto__a === Array.prototype);
// 通过ES6的 Array.isArray() 做判断console.log(Array.isArray());
// 通过 instanceof 做判断
console.log( [] instanceof Array);
// 通过Array.prototype.isPrototypeOf 做判断 判断Array是否在传入内容的的原型链上console.log(Array.prototype .isPrototypeof( [] );
9、js 中操作符什么时候用于字符串的拼接
// js 中 + 操作符什么时候用于字符串拼接
// 如果+操作符其中一个操作数是字符巾(或者通过ToPrimitive操作之后最终得到的字符串),则执行字符串的拼接,否则执行数字加法var a={nane :”张三"》; //===> [object ojbect] // a.valueof() // a.tostring() var b= { age:18 }; //===> [object ojbect] // b.valueof() // b.tostring() var c = 1 ; console.log( a+c ); // [object ojbect] 1 console.log( a+b ); // [object ojbect][object ojbect] console.log(1+1+'23'); // 2+'23' ===> '223' console.log(1+'23'+4+5); // '123' +4+5 ===> '1234' +5 ===>'12345'
10、js 中Object.is () 与比较运算符 === 和 == 的区别
// js中object.is() 与 比较操作符 “===“(严格相等运算符) 和”==" (相等运算符) 的区别
// 双等号(==): 如果两边的类型不一致,进行强制类型转换,然后再去进行比较
console.log(1==true); // -->1==1 --> true true被转换为 number 1
console.log(1=='1'); // --> 1==1 --> true// 三等号(===): 如果两边的类型不一致,不会进行强制类型转换,直接返回false,等型等值console.log(1=== true); // false
console.log(1==='1') ; // false
console.log(NaN === NaN) ; // false 实际希望为 trueconsole.log(+0 === -0) ; // true 实际希望为 false
不够严谨,使用es6新增 Object.is () 解决
// Object.is(): 用来判断两个值是否严格相等,处理一些特殊的情况,-0和+9不再相等,两个NaN是相等的
console.log( Object.is(NaN,NaN) ); // true
console.log( Object.is(+0,-0 ) ) ; // false
11、js中如何进行隐式类型转换
// js中如何进行隐式类型转换 主要发生在运算符之间
/*
ToPrimitive方法 : 这是Js中每个值隐含的自带的方法,用来将值(无论是基本类型值还是对象)转换为基本类型值 , 如果值为基本类型 , 则直接返回值本身 : 如果值为对象,其看起来大概是这样:
ToPrimitive( obj , type )
obj --> 需要转换的对象type --> 期望的结果类型
type的值可以为number或者string,默认情况下为number1、当type为number时规则如下:
(1) 调用obj的valueof方法,如果为原始值,则返回,否则下一步(2) 调用obj的toString方法,如果为原始值,则返回,否则下一步
(3) 指出TypeError异m
2、当type为string时规则如下:
(1) 调用obj的tostring方法,如果为原始值,则返回,否则下一步(2) 调用obj的valueof方法,如果为原始值,则返回,否则下一步
(3) 抛出TypeError异常
*/
var objToNumber = function (value) { return Number(value.valueOf().tostring()) } console.log(objToNumber(0)=a= 0); // --> 0 console.log(objToNumber(0)-sE NaN);//-->NaN // +操作符的两边有至少一个string类型变量时,两边的变量都会被隐式转换为字符串:其他情况下两边的变量都会被转换为数字。 // console.log(1 +"23" ); // 123 // console.log(1 + false); // 1 // console.log('1' + false); // 1false // console.log(true + false); // 1 // - 、*、/ 操作运算符会转换为数字 // console.log(25 - "23""); // 2 // console.log(1 * false); // 0 // console.log(1 / 'aa'); // NaN // 对于 == 操作符来说 // console.log(3 == true); // false // console.log('0' == false); // true // console.log('0' == e); // true //对于< 和 > 比较符,(字母按照字母的排列顺序进行比较) // console.log('c' > 'b'); // true // console.log('de' > 'fg'); // false //其他情况下,转换为数字再比较 // console.log( '12'< 13); // true // console.log(false < -1); // false 0 > -1 //对象 // var a= {} // 空对象 // console.log( a > 2); // false /* 转换过程 console.log(a.valueof(); // {} console.log(a.toString()); // [object Object ] console.log(Number(a.tostring())); // NaN */
12、 js中的深拷贝和浅拷贝的区别
// JS中 深拷贝 和 浅拷贝 的区别
// 主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变
// 浅拷贝 :// 只是指向被复制的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会改变
// 新旧对象共享内存,修改其中一个,另一个也会受到影响
// 深拷贝 :// 在内存中开辟一块新的地址用于存放复制的对象
// 新旧对象不会共享内存,修改其中的一个不会影响另一个
// 浅拷贝:
// 通过 = 直接赋值
var obj = { name:"张三", age:18 } var obj1 = obj; console.log(obj1); // { name:张三", age: 18} cbj1.age = 20; console.log(obj); // {name :张三", age: 20} consolc.log(cbj1); // {name: "涨三", age: 20} // 浅拷贝常见的方法 Object.assign() 方法 var obj = {name:"张三",age:18}; var obj1 = Object.assign(obj) obj1.age = 20; console.log(obj); // {name: "涨三", age: 20} console.log(obj1); // {name: "涨三", age: 20}
// 深拷贝:
1、通过JSON 对象实现深拷贝
// JSON.stringify : 将js的值(对象或者数组)转为一个SON字符电
// JSON.parse : 用来解析sON字符串,转换为0bject类型
var obj = {name:"张三" , age:18); var obj1 = JSON.parse(soN.stringify(obj)); obj1.age = 20; console.log(obj); // {name: "涨三", age: 18} console.log(obj1); // {name: "涨三", age: 20}
2、使用扩展运算符实现深拷贝
var obj = {name:"张三" , age:18); var obj1 = {...obj,age:20} console.log(obj); // {name: "涨三", age: 18} console.log(obj1); // {name: "涨三", age: 20}
13、js中与和或操作符的返回值
// js中 && (与) 和 ||(或) 操作符的返回值
// 首先对第一个操作数进行条件判断,如果不是布尔值,就先强制转换为布尔类型,然后进行条件判断// || (或)
console.log1 ll 2); //-->1(真),如果第一个操作数为真,返回第一个操作数的值console.log(0 ll 2); //-->2(真),如果第一个操作数为假,返回第二个操作数的值
// &&(与)
console.log(1 && 0); //-->0(假),如果第一个操作数为真,返回第二个操作数的值console.log(e && 2); //-->0(假),如果第一个操作数为假,返回第一个操作数的值// || 和 && 不是返回条件判断的结果返回它们其中一个操作数的值
14、 js 中 == 操作符的强制类型转换规则
// js 中==操作符的强制类型转换规定
// 首先判断两者的类型是否相同,如果不相同会进行类型转换,相同的话就比较大小1/转换情况:// 1、字符串和数字之间的相等比较,将字符串转换为数字之后再进行比较大小
1== '1' --> 1 == 1 -->true
// 2、其他类型和布尔类型之间的相等比较,先将布尔值转换为数字后,再应用其他规则进行比较true == '1' --> 1=='1' --> 1==1 --> true
// 3、nul1和undefined之间的相等比较,结果为真,其他值和它们进行比较都返回假值// 4、对象和非对象之间的相等比较,会将对象先转为基木数据类型再进行判断
‘1’=={} --> '1' == "[object object]"
// 5、如果两个操作值都是对象,则比较它们是不是指向同一个对象,如果两个操作数都指向同一个对象,则相等操作符返回true ,否则返回falsevar a={} ;
var b=a;var c={};
console.log(a==b); // trueconsole.log(a==c); // false
15、js中 isNaN 与 Number.isNaN() 的区别
// js中 isNaN 和 Number.isNaN 的区别?
// isNaN : 为了到断一个计算结果或者变量的值是否为NaN// isNaN(value) : value表示检测的值
// isNaN 的判断过程 : 首先进行类型检测,如果传入的参数不是数值类型,第二步将传入的参数转为数值类型,然后再进行是否为NaN的判断
Number("") // 0 Number(null) // 0 Number(true) // 1 Number(false) // 0 Number(undefined) // NaN Numben('aa') // NaN -----------isNaN()--------------- //isNaN() console.log(isNaN(NaN)); // true console.log(isNaN(true)); // false console.log(isNaN('aaa')); // true console.1og(isNaN(null)); // false console.log(isNaN('')); // false consoie.1og(isNaN(undefined)); // true --------Number.isNaN()---------------' // Number.isNaN() ES6出来的Number对象的扩展的方法 // Number.isNaN(value): value表示检测的值 // Number.isNaN的判断的过程:首先进行类型检测,如果传入的参数不是数值类型,直接返回felse ,如果判断是数值类型,然后isNaN()的方式进行判断 console.log(Nunber.isNaN(true)); //false console.log(Number.isNaN("")); //false console.log(Number.isNaN(nul1)); //false console.log(Number.isNaN(NaN)); //true console.log(Number.isNaN(123)); //false console.log(Nunber.isNaN( 'aaa')); //false console.1og(Number.isNaN(undefined)); //false
16、es6中的 const 定义的 对象的属性 可以修改吗?
// ES6中const定义的对象的属性可以修改吗?
// 可以修动
// const 是保证 变量指向内存地址 不能改动,变量的值 可以改动const obj = (name:”张三",age:18); obj.name= “ 李四 ” //可以修改 obj={} console.log(obj); // 报错
17、ES6中 let、 const 和 var 之问的用法以及区别
// ES6中let、 const和var之问的用法以及区别
var:
1、使用var声明的变量既是顶级交量(顶层对象(window对象)的属性)也是全局变量2、使用var声明的变量存在变量提升的情况
3、使用var可以对一个变量进行多次声明,后面的声明会覆盖前面的变量声明4、在函数中再次使用var声明这个变量的时候,这个变量就是局部的,如果不是用var,那就全局的
// 使用var声明的变量既是顶级交量(项层对象(window对象)的属性)也是全局变量 var a=10; console.log(window.a); // 10 // 使用var声明的变量存在变量提升(提升变量声明)的情况 console.log(b); // undefined var b = 10; //声明并且赋值 // 运行过程 // var b; // console.log(b); // undefined // b=10; // 使用var可以对一个变量进行多次声明,后面的声明会覆盖前面的变量声明 var c= 10; var c= 40; console.log(c); // 40 //在函数中再次使用var声明这个变量的时候,这个变量就是局部的,如果不是用var,那就全局的 var d=10; function fun1((){ var d=20; } fun1() console.log(d); //10
let:
1、 let 所声明交量只在let命令所在的代码块中生效let不存在变量提升
2、 let 不允许在相同的作用域下重复声明
// let所声明变量只在let命令所在的代码块中生效/块级作用域 let num=18 console.1og(num); // 18 } // let不存在交量提升 let num1; console.log(num1); // 报错 // let不允许在相同的作用域下重复声明 num1 = 20 // 报错
const :
const声明一个只读的常量,一旦声明,常量的值就不能改变const一旦声明,就必须赋值
除了以上的其他的都和let一样的// const声明一个只读的常量。一且声明,常量的值就不能改变 const sum =103; sum = 200; console.log(sum); // 报错,不能再次赋值 // const一旦声明,就必须赋值 const total; console.log(total); // 报错,缺少初始值
区别:交量提升:
var声明的变量存在变量提升,let和lconst不存在变量提升块级作用域:
var不存在块级作用域,let和const存在块级作用域,只在所在代玛块生效重复声明:
var允许重复声明,let和const不允许在同一个作用域重复声明修改声明的变量:
var和let可以改变声明的变量,const,不可以,一旦声明,必须赋值,并且常经的值不能改变
18、js中如何的断一个对象是空对象
// js中如何的断一个对象是空对象
// 使用JSON自带的.stringify方法来判断 var obj={ name:"张三" } console.log(JSON.stringify(obj)); // {} 是一个字符串 if (JSON.stringify(obj) === “0") { console.log(“是一个空对象""); } // 使用object.keys()来判断//key:键名 // value:键值 var obj1= { name:"张三", age:18 }; console.log(Object.keys(obj1)); // 返回一个数组 if ( Object.keys(obj1).length==0 ) { console.1og("是一个空对象); }
19、 ES6中new一个箭头函效会怎么样 --->报错
ES6中new一个箭头函效会怎么样 --->报错
// new关键字的执行过程
/*
new构造函效会内存中创建一个空对象this就会指向刚才创建的这个空对象
执行构造函数中代码,给空对象添加属性和方法返回这个新的对象(所以构造函数中不需要return)*/
/箭头函数 //箭头函数内的this是静态的,指向定义时所在的对象,而不是调用时,this指向不可以改变的var id=10; var obj=i id:100, a:function(){ // 谁调用这个函数,this就指向谁 console.log(this.id) }, b:()=>{ // this是静态的,指向定义时所在的对象(window对象),所以箭头函数不可以当做构造函数来使用 console.log(this.id); } ) obj.a() // 100 obj.b() //10 console.log(new obj.a()); undefined console.log(new obj.b()); a{}
20、js 中对原型的理解
//JS中对原型的理解
// 构造函数
function Person(){
}
// prototype(原型)属性,默认对应着一个空对象(没有我们制定的方法和属性),这个空对象就是我们所说的原型对象,每一个prototype都是不相等的console.log(Person.prototype) //
// 显式原型和隐式原型
// 每一个函数都有一个prototype属性,就是显式原型
// 每一个实例对象都有一个_proto_,就是隐式原型
// 实例对象的隐式原型 等于 对应的构造函数的 显示原型的值// 构造函数
function Fun( ){ //内部语句:Fun(this). prototype={}
}
console.1log(Fun.prototype);
var fun=new Fun()、// 内部语句:fun(this)._proto__=Fun. prototypeconsole.log(fun._proto_):
console.log(Fun.prototype===fun._proto__); // true
// 总结:
// 函数的prototype属性,在定义函数是自动添加的,默认值是一个空对象
// 对象的_proto__属性,创建对象的时自动添加的,默认值是构造函数的prototype属性
21、js中对原型链的理解
// Js中对原型链的理解:查找对象的属性(方法)
function Fun{ // Fun(this).prototype={} this.test1=function(){ console.log( 'test1()"); } } Fun.prototype.test2=function(){ console.log( 'test2()'); } console.log(Fun.prototype); console.log( object.prototype.__proto__); var fun=new Fun(); // fun(this)._proto__=Fun. prototype fun.test1(); // test1 fun.test2(); // test2 console.log(fun.tostring()) // [ object Object ] fun.test3(); // 报错
22、 js 对原型的修改和重写
/ JS中对原型的修改和重写 function Person(name){ this.name=name } //修改原型 Person.prototype.getName = function(){ console.log(this.name); } var p=new Person("张三"); // 修改原型不会影响构造函数的显式原型 等于 实例对象的隐式原型 console.log(p._proto_=== Person.prototype);//true console.log(p.___proto__=== p.constructor.prototype);//true //重写原型 会有影响 p.constructor 的指向改变了 Person. prototype={ getName:function(){ console.log(this.name); } } // 直接给Person的原型对象用对象进行赋值时,p的构造函数指向根构造函数 objectvar p=new Person("张三"); // p(this)._proto__=Person.prototype console.log(p._proto__===Person.prototype); //true console.log(p.constructor); // object 指向改变了 console.log(p._proto__===p.constructor.prototype); //false // 通过constructor 让p的指向恢复 p.constructor=Person; console.log(p._proto__===p.constructor.prototype); //true
23、for ...of 和 for ... in 的区别
ES6中 for. . .of 和 for . . .in (性能差)的区别
// for. . .of遍历获取对象的键值,for. . .in获取对象的键名// for. . .of只遍历当前对象, for. . .in会遍历对象整个原型链
// 对于数组的遍历
// for . ..in返回数组中所有可枚举的属性
// for ..of返回数组的下标对应的属性值
function Person(name,age,sex){ this.name=name this.age=age this.sex=sex } Person.prototype.height=188 var p=new Person(“张三"",18,男") P[Symbol.iterator]=function(O){ var keys = object.keys(this); var index = 0; return { next({ if(index<keys.length){ return {value:p[keys[index++]],done:false} }else{ return {value:undefined,done:true}} } } } for(let value of p){ console.1og(value); // 张三 18 男 } ------------------------------ for(let key in p){ console.log(key); // name age sex height } ------------------------- var arr=[1,2,3,4,5] console.log(arr); for(let i in arr) console.log(i); } for(let i of arr){ console.log(i); }
for . ..in,主要是为了遍历对象而产生,不适用于遍历数组 , for ..of,我环可以用来遍历数组,类数组对象,字符串,set map .....
24、js 中如何判断 一个属性 是属于实例对象 还是继承与构造函数
JS中如何判断一个属性是属于实例对象还是继承于构造函数
通过hasOwnProperty() // 检测一个属性是否属于自身对象,还是继承于原型链上的,function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sex = "男" ;var p=new Person ("张三",18);
p.phone=12345;
p.height=188;console.log(p);
console.log(p.hasOwnProperty("phone")); //trueconsole.log(p.hasOwnProperty ( "sex")); //true
for (let i in p){
if (p.hasOwnProperty(i)){ // hasOwnProperty() 筛选掉原型链上的属性
console.log(p[i]);
}
}
25、js 中bind 和call 、apply 的作用以及他们的区别
Js中 bind 和call、apply 的作用 以及它们的区别
作用: 改变函数运行时 this 的指向
var uname = " 张三 "
var obj={
uname : "李四" ,say: function() {
console.log(this.uname);
}
}
obj.say() //李四
setTimeout(obj.say,0) // 张三
setTimeout(obj.say.bind(obj),0) // 李四
// setTimeout 里面函数里面的this 指向 window 的 this区别
aplly: 两个参数,第一个是this指向,第二个是函数接收的参数,以数组的形式传入function fun(...argus){
console.log(this);console.log(...argus);
}
var person={
myname : "王五"}
fun.apply(person,[1,2,3,4]); // 传入的参数必须是一个数组fun(1,2,3,4)
// 如果第一个参数 null 或者 undefined ,this 默认指向 windowfun.apply(nul1,[1,2])
fun.apply(undefined,[1,2])
call : 两个参数,第一个是this指向,第二个是参数列表
fun.call(person,1,2,3,4)
// call和aplly改变this指向原函数立即执行,临时改变this指向一次fun(1,2,3,4)
// bind:两个参数,第一个是this指向,第二个是参数列表
// 改变this指向不会立即执行,返回一个永久改变this指向的函数
var bindFun= fun.bind(person)bindFun(1,2,3,4)
bindFun()
总结:三者第一个都是this指向,第二个是函数接收的参数
26、es6 对 promise 的理解以及他的实例方法
ES6中对Promise的理解以及它的实例方法
// 是异步编程的一种解决方案
// 三种状态:pending(进行中),fulfi1led(已成功),rejected(已失败)
// 特点:状态不受外界的影响,只有异步操作的结果,决定当前是哪一种状态
// 一旦状态改变就不会再变(pending-->fufilled , pending-->rejected)
// 用法:Promise是一个构造函数,用来生成Promise实例
//Promise构造函数接收一个函数作为参数,这个函数有两个参数const p=new Promise(function(resolve,reject) {
// resolve函数:将Promise对象的状态从未完成变成成功,在异步操作成功的时候调用, resolve() // 返回异步操作的结果,作为参数传递出去
// reject函数:将Promise对象的状态从未完成变成失败,在异步操作失败的时候调用, reject() // 返回异步操作的结果,作为参数传递出去
})// Promise实例方法
const p = new Promise( function (resolve,reject) {
setTimeout(O=>{
const time=new Date().getTime(if( time%2 == 0){
resolve('成功的数据。 time = '+time)}else{
reject(·失败的数据,time = '+time)
}},1000)
})
p.then((value)=>{ // resolved(己成功)的状态
console.log( 成功的' + value);
},(reason)=>{ // rejected(已失败)的状态
console.log( 失败的' + reason);
}).catch((value) => {console.log(value)
}).finally(() => {
console.log('最后的结果')
})
// then():当实例状态发生改变的时候的回调函数,放回的是一个新的Promise 实例,也就是Promise 可以链式书写的原因。
// catch() :用于指定发生错误的回调函数,一般来说通过 catch 替代 then 中第二个参数// finally() :用来指定不管Promise对象状态最后如何,都会执行的操作
setTimeout(() => { // 例如多个嵌套 // 多个串联嵌套的异步操作形成的回调地狱
console.log(111);setTimeout(() => {
console.log(222);setTimeout(() => {
console.log(333);},3000)
},2000)},1000)
----------------------------------------------------
function fun(ms, val,nextval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
console.log(111);},ms)
})
}
fun(1000).then((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(value);resolve(333)
},2000);})
}).then ((value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.1og(value);
},3000)
})})
27、什么是回调地狱(多个串联的异步操作)以及如何使用Promise解决
什么是回调地狱(多个串联的异步操作)以及如何使用Promise解决
通过 then 链式调用
//歌单--->歌单列表--->歌曲的信息
//需求:一秒钟之后输出1,然后两秒钟之后输出2,然后三秒之后输出3setTimeout(() =>{
console.log(1);setTimeout(0 =>{
console.log(2);setTimeout(() =>{
console.log(3);}, 3000)
}, 2000)},1000)
------------------使用promise 实现------------------------
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1);resolve(2)
},1000)
})
}
getData() . then ((value)=>{
return new Promise((resolve, reject) =>{
setTimeout(() => {
console.log(value);resolve(3)
},2000)
})}).then((value)=>{
return new Promise((resolve,reject) => {
setTimeout(() =>{
console.log(value);}, 3000)
})
})
28、ES6中对Promise.all的理解以及应用场景
ES6中对Promise.all的理解以及应用场景
// 用于将多个Promise实例,包装或一个新的Promise实例let p1=new Promise((resolve,reject)=>{
resolve("成功81")
)
let p2=new Promise((resolve,reject)=>i
resolve("成功e2")
)
let p3=new Promise((resolve,reject)=>{
resolve("成功83")
)
// 参数可以不是数组,但是必须是iterator接口let pAll=Promise.al1([p1,p2,p3])
console.log(pAll)
// pAll的状态,由p1,p2,p3来决定,只有当这三个都为成功,pAll才会为成功,
// 但是有一个失败,那么就是失败,这个时候第一个失败的实例的返回值,会传递给pA11的回调函数//如果作为参数的实例,自己定义了catch方法,那么它一旦rejected,不会触pAll的catch方法pAl1.then((value)=>{
console.log(value);}).catch((reason)=>{
console.log(reason)})
// 多个请求结果合并在一起function getBannerList(){
return new Promise((resolve,reject)=>{
setTimeout(O=>{
resolve( 轮播图的数据")},108e)
})
}
function getMusicList(() {
return new Promise((resolve,reject)=>{
setTimeout(() => {resolve( "歌曲列表的数据')
} ,2000)
})
}
function getCateList(){
return new Promise((resolve,reject)=>i
setTimeout(() => {
resolve(歌单分类的数据')},3000)
}
function initLoad() {
let All= Promise.al1([getBannerList(),getMusicList(),getcateList(])console.log(All);
All.then((value) => {
console.log(value);”
}
initLoad()
29、ES6中Promise.race的用法以及使用场景
ES6中Promise.race的用法以及使用场景
// 将多个Promise实例包装成一个新的Promise实例let p1 = new Promise((resolve,reject) =>{
setTimeout(() =>{
resolve(p1成功)}, 2000)
})
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p2成功‘)},1000)
})
//调用
const prace=Promise.race([p1,P2];console.log(prace);
//Promise.race区别于Promise.all:只要实例中有一个先改变状态,就会把这个实例的多数的返回值传给prace的回调函的/使用场景:请求超时提示
function request(){
return new Promise((resolve,reject)=>{
setTimeout(() =>{
resolve("请求成功")},4000)
})
}
function timeout() {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject(网络不佳,请求超时")},3000)
})}
Promise.race( [request(),timeout()] ).then((value)=>{
console.1og(value);
}).catch((reason) => {
console.log(reason);})
30、 ES6中使用Promise封装ajax
// ES6中使用Promise封装ajax
// http://localhost:3808/personalized21imit-10
function getsON(ur1){ return new Promise((resolve, reject) =>{ //创建一个实例对象 let xhr = new XMALHttpRequest(); //新建一个http请求 xhr.open( 'GET", url, true); //发送http请求 xhr.send(null) //设置状态的监听函数 xhr.onreadystatechange = function(){ if(xhr.readyState !== 4) return//表示请求完成 //当请求成功或者失败,需要改变promise实例的状态 if (xhr.status >=200 && xhr.status < 300){ resolve(xhr.responseText)/请求结果 }else{ reject(new Error((xhr. statusText)) } } //设置错误的监听函资 xhr.onerror = function (){ reject(new Error(xhr.statusText)) } //设置响应数据的类型 // xhr.responseType - 'json"” }) } getJSON( " http://localhost:3000/personalized?1imit-10').then((value)=> { console.1og(as0w. parse(value)); }).catch((reason) =>{ console.log(reason); })
31、Js中ajax(Async Javascript and XML)的原理是什么?如何实现
Js中ajax(Async Javascript and XML)的原理是什么?如何实现
原理: 通过XNLHttpRequest对象来向服务器发送异步请求,从服务器获取数据,然后用js来操作DOM去更新页面
实现过程:
-创建Ajax的核心对象 XMLHttpRequest对象new XMLHttpRequest(()实例化对象
-通过 XMLHttpRequest对象的 open()方法与服务端建立连接new XMLHttpRequest().open(method:表示请求方式,url:服务器的地址)
-构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send()方法发送给服务器端。new XMLHttpRequest(.send(body:发送的数据)
如果使用get 请求发送数据,send()参数设置为null
-通过 XNLHttpRequest对象提供的 onreadystatechange事件监听服务器端的通信状态
new XNLHttpRequest().onreadystatechange主要监听的属性是实例化对象中readyState(五个状态):
0:open()未调用,
1: send()未调用,
2:send()已经调用,响应头和响应状态已经返回,
3:响应体正在下载,responseText(接收服务端响应的结果)获取到部分的数据,
4: 整个请求过程已经完毕
只要readystate属性值发生了改变,onreadystatechange被触发
-接受并处理服务端向客户端响应的数据结果
-将处理结果更新到HTML页面中const xhr =new XMLHttpRequest(){ xhr.open("GET",'http:/ /localhost: 30e0/ personalized?limit=10') xhr.send(nul1) xhr.onreadystatechange=function(){ if(xhr.readystate === 4){ if(xhr.status>=200 && xhr.status<300){ console.1og(xhr.responseText); } let obj=JSON.parse(xhr.responseText) console.log(obj); obj.result.forEach(item =>{ var div=document.createElement('div'); div.innerHTML=item.name document.querySelector( 'body' ).appendchild(div) }) }else if(xhr.status>=400){ console.1og(“错误信息"+xhr.status); } } }
http:// localhost: 30ee/personalized?limit=10
32、Js中localstorage和sessionStorage的区别
Js中localStorage和lsessionStorage的区别
localstorage:永久存储在本地,适合保存在本地的数据
sessionStorage:会话级的存储,敏感账号一次性登录相同点:
都是保存在浏览器端
不会把数据自动的发送给服务器,仅在本地保存
只能存储字符串,可以将对象JSON.stringfy()编码之后进行存储不同点:
存储大小限制不同:sessionStorage存储的大小为5M, 1ocalstorage存储大小为20M
数据有效期不同:localStorage: 始终有效,窗口关闭或者浏览器关闭,一直保存,持久保存数据sessionStorage: 仅在当前浏览器窗机关闭前有效,会话级存储
作用域不同:sessionStorage: 在不同的浏览器窗口否会进行共享,只有同一个页面中
localStorage: 在所有的同源的窗口下可以共享的
33