Open whitejy opened 5 years ago
二、class 1、类中定义的方法等同于使用原生js的原型定义。即:构造函数的prototype。 2、类中的方法都是不可枚举的,即object.keys(class.prototype)为空。而通过构造函数定义的prototype上的方法是可以枚举的。 3、可不可以枚举通过是不是可以被for in遍历到。 4、object.keys只会遍历自身属性,而不会遍历原型链上的属性。
js中哪些属性可枚举,哪些不可枚举?######
js基本数据类型自带的原型属性不可枚举。
通过Object.defineProperty()方法指定enumeralbe为false的属性不可枚举。
js中哪些方法会访问到enumerable为true的对象属性?######
for...in操作
Object.keys()方法(和for...in的区别就是Object.keys()不会返回对象原型链上的属性)
JSON.stringify()方法。
Object.assign()
三、for in和for of区别 推荐在循环对象属性的时候,使用for...in,在遍历数组的时候的时候使用for...of。
for...in循环出的是key,for...of循环出的是value
注意,for...of是ES6新引入的特性。修复了ES5引入的for...in的不足
for...of不能循环普通的对象,需要通过和Object.keys()搭配使用
for in 遍历数组会将原型链上的属性遍历
foreach 方法没办法使用 break 语句跳出循环,或者使用return从函数体内返回
for of 不能遍历普通对象的原因:for of只能遍历可变量对象,而普通对象是不可遍历的。而array是可变量对象,故需要通过object.keys生成数组对象后在使用for of遍历。
四、解构赋值 1、要将一个已经声明的变量用于解构赋值
let x;
{x} = {x: 1};
// SyntaxError: syntax error
因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法
let x;
({x} = {x: 1});
五、字符串扩展 1、 for of 可以遍历汉字(大于oxFFFF)。 \uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。 2、新增方法
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat方法返回一个新字符串,表示将原字符串重复n次。
3、模板字符串之中还能调用函数 (模板字符串中可以处理任意js表达式、运算,但必须首先需要声明,不然报错)
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
4、字符串模板
let template = `
<ul>
<% for(let i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %></li>
<% } %>
</ul>
`;
该模板使用<%...%>放置 JavaScript 代码,使用<%= ... %>输出 JavaScript 表达式。
5、嵌套调用
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
六、正则扩展 1、RegExp构造函数 1) 参数是正则表达式,不允许第二个参数(但ES6允许,且以第二个参数的flag为准)
var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;
//后面再加参数报错,但ES6则可以,如:
new RegExp(/abc/ig, 'i') //最后以i为准
2) 参数是表达式
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
七、数组扩展 1、object.is() ---ES6新增方法,比较两个数值严格相等。与===的不同之处在于,object.is在判断+0和-0是不相等的,且NaN等于自身。 即:
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
2、indexOf和findIndex区别 indexOf方法无法识别数组的NaN成员,但是findIndex方法可以借助Object.is方法做到;且findIndex后面参数是一个回调函数。
3、find() 后面接两个参数----第一个为回调函数,第二个参数用来绑定回调函数里面 this对象
function f(v){
return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person); // 26
回调函数的三个参数----第一个为当前值value,第二个为当前索引index,第三个为整个数组array。
4、数组新增方法 1) find、findIndex; 2)includes 3) entries、keys、values
八、深拷贝和浅拷贝的区别 简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝。 深拷贝:
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
或者,使用JSON转换:
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
或者,jquery的extend方法
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
使用JSON实现深拷贝的原理: 1.堆(stack)和栈(heap)
stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不定也不会自动释放。
2.值与引用
js中有基本数据类型和引用类型;
基本数据类型的变量和值都是存放在栈中,声明之后会分配一块内存区域,基本数据类型之间的赋值是直接把栈内存中存的值赋值给变量(传值)
引用类型的变量存在栈中,但值是存在堆中,实际上栈存放的是指向堆中的地址,也叫引用,引用类型直接的赋值实质是把引用赋值给一个变量(传址),所以其指向的堆内存中的值是一样的。
九、Object.creat()和new Object()区别 Object.creat()直接从第一个参数传递的对象继承的对象; 而new则是继承自构造函数的原型;
使用场景: new----生成实例对象的常用方法,就是使用new命令,让构造函数返回一个实例.
Object.create---但是很多时候,只能拿到一个实例对象,它可能根本不是由构建函数生成的,那么能不能从一个实例对象,生成另一个实例对象呢?JavaScript 提供了Object.create方法,用来满足这种需求。
参考:https://fe2x.cc/2017/10/14/Object-create-and-new-JavaScript/ https://fe2x.cc/2017/10/14/Object-create-and-new-JavaScript/
十、promise 1、一旦状态改变,就不会再变,任何时候都可以得到这个结果。与事件不同的是事件是错过了再去监听此事件是得不到结果的。 2、不设置回调函数,内部错误消息是无法反应到外部的。 3、Promise对象接受两个函数(resolve/reject---默认是由浏览器引擎自动处理,不需要额外去实现)作为参数创建实例,这两个参数函数,一个输出成功的结果,一个输出失败的结果。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
而then则是将上面输出的成功或者失败的结果进行处理回调,then接收两个回调函数作为参数,第一个是成功时的,第二个是失败时候的(可以省略)
promise.then(function(value) {
// success
}, function(error) {
// failure
});
4、catch() catch()既能捕获promise的reject异常,还能捕获then()回调函数产生的异常。(异常捕获具有冒泡性质)
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
5、如果promise首先抛出异常,那么状态就变为reject,那么后面如果接resolve是不会执行的,因为状态只能变一次。
const promise = new Promise(function(resolve, reject) {
resolve('ok'); // 里面的状态只要是成功或者失败,就会自动执行resolve或者reject的,
throw new Error('test'); // 不需要特意去写resolve或者reject,如这个throw抛出的异常,那么状态
// 会自动变为reject,就能被后面的catch捕获
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
6、finally() 不管promise什么状态,都会执行。
7、Promise.all() 用于将多个 Promise 实例,包装成一个新的 Promise 实例。接收一个iterator对象作为参数(数组或者其他可遍历对象)
const p = Promise.all([p1, p2, p3]);
结果:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
当p1/p2/p3中存在catch后,那么这个promise对象抛出异常,最后的p也不能捕获到。因为catch也是一个promise对象,返回之后就等同于正常的resolve了,故最后不能被p中的catch捕获到。
8、Promise.race()
const p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
9、Promise.resolve 将对象转为promise对象
10、Promise.reject() Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
十一、ajax、fetch、axios区别 1、ajax对原生xhr封装,引用需要引入jquery,体积太大,对MVVM框架不符合。 2、fetch脱离了xhr,是一种新的http请求方式。对错误的处理欠缺,只对网络请求报错,对400,500都当做成功的请求。没办法原生监控支持请求的进度。也是支持promise异步请求的。 3、axios是对xhr的promise封装,支持promise接口,体积小,支持并发请求接口。客户端支持防止CSRF。
一、promise 1、promise实现ajax
2、普通实现ajax