whitejy / learn

学习使用
0 stars 0 forks source link

ES6 #13

Open whitejy opened 5 years ago

whitejy commented 5 years ago

一、promise 1、promise实现ajax

function ajax(url,type){
    return new Promise((resolve,reject) => {
        var XHR = new XHRHttpRequest();
        XHR.open(type,url,true);
        XHR.send();
        XHR.onreadystatechange = () => {
            if(XHR.readyState == 4) {
                if(XHR.status == 200) {
                    try {
                        let response = JSON.parse(XHR.responseText);
                        resolve(response);
                    } catch(e) {
                        reject(e);
                    }
                } else {
                    reject(new Error(XHR.statusText));
                }
            }
        }
    });
}

2、普通实现ajax

var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();

XHR.onreadystatechange = function() {
    if (XHR.readyState == 4 && XHR.status == 200) {
        result = XHR.response;
        console.log(result);
    }
}
whitejy commented 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()
whitejy commented 5 years ago

三、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遍历。

whitejy commented 5 years ago

四、解构赋值 1、要将一个已经声明的变量用于解构赋值

let x;
{x} = {x: 1};
// SyntaxError: syntax error

因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x;
({x} = {x: 1});
whitejy commented 5 years ago

五、字符串扩展 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>
`;
whitejy commented 5 years ago

六、正则扩展 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;
whitejy commented 5 years ago

七、数组扩展 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

whitejy commented 5 years ago

八、深拷贝和浅拷贝的区别 简单点来说,就是假设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中有基本数据类型和引用类型;

基本数据类型的变量和值都是存放在栈中,声明之后会分配一块内存区域,基本数据类型之间的赋值是直接把栈内存中存的值赋值给变量(传值)

引用类型的变量存在栈中,但值是存在堆中,实际上栈存放的是指向堆中的地址,也叫引用,引用类型直接的赋值实质是把引用赋值给一个变量(传址),所以其指向的堆内存中的值是一样的。

whitejy commented 5 years ago

九、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/

whitejy commented 5 years ago

十、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。

whitejy commented 5 years ago

十一、ajax、fetch、axios区别 1、ajax对原生xhr封装,引用需要引入jquery,体积太大,对MVVM框架不符合。 2、fetch脱离了xhr,是一种新的http请求方式。对错误的处理欠缺,只对网络请求报错,对400,500都当做成功的请求。没办法原生监控支持请求的进度。也是支持promise异步请求的。 3、axios是对xhr的promise封装,支持promise接口,体积小,支持并发请求接口。客户端支持防止CSRF。