跳至主要內容

js 基础

技术中心大约 10 分钟

js 基础

ES5 和 ES6 的区别

系统库的引入

Es5:需要先使用 require 导入 React 包,成为对象,再去进行真正引用

Es6:可以使用 import 方法来直接实现系统库引用,不需要额外制作一个类库对象

在ES5里,如果使用CommonJS标准,引入React包基本require进行
ES5
var React = require("react");
var {
    Component,
    PropTypes
} = React;  //引用React抽象组件

var ReactNative = require("react-native");
var {
    Image,
    Text,
} = ReactNative;  //引用具体的React Native组件

在ES6里,import写法更为标准
ES6
import React, {
    Component,
    PropTypes,
} from 'react';
import {
    Image,
    Text
} from 'react-native'

导出及引用单个类

Es5:要导出一个类给别的模块用,一般通过 module.exports 来实现。引用时,则依然通过 require 方法来获取

Es6:可以使用 export default 来实现相同的功能,使用 import 方法来实现导入

导出
在ES5里,要导出一个类给别的模块用,一般通过module.exports来导出
ES5
var MyComponent = React.createClass({});
module.exports = MyComponent;

在ES6里,通常用export default来实现相同的功能:
ES6
export default class MyComponent extends Component {}

引用
ES5
var MyComponent = require('./MyComponent');

ES6
import MyComponent from './MyComponent';

定义组件

Es5:组件类的定义通过 React.createClass 实现

Es6:组件类继承 React.Component 类

在ES5里,通常通过React.createClass来定义一个组件类
ES5
var Photo = React.createClass({
    render: function () {
        return (
            <Image source={this.props.source} />
        );
    },
 });
 在ES6里,我们通过定义一个继承自React.Component的class来定义一个组件类
ES6
class Photo extends React.Component {
    render() {
        return (
            <Image source={this.props.source} />
        );
    }
}

组件内部定义方法

Es5:采用的是 ###:function()的形式,方法大括号末尾需要添加逗号

Es6:省略了【: function】这一段,并且结尾不需要加逗号来实现分隔

ES5
var Photo = React.createClass({
    componentWillMount: function () {

    },
    render: function () {
        return (
            <Image source={this.props.source} />
        );
    },
});
ES6
class Photo extends React.Component {
    componentWillMount() {

    }
    render() {
        return (
            <Image source={this.props.source} />
        );
    }
}

定义组件的属性类型和默认属性

Es5:属性类型和默认属性分别通过 propTypes 和 getDefaultProps 方法来实现

Es6:统一使用 static 来实现

在ES5里,属性类型和默认属性分别通过propTypes和getDefaultProps方法来实现
ES5
var Video = React.createClass({
    getDefaultProps: function () {
        return {
            autoPlay: false,
            maxLoops: 10,
        };
    },
    propTypes: {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    },
    render: function () {
        return (
            <View />
        );
    },
});

在ES6里,可以统一使用static来实现
ES6
class Video extends React.Component {
    static defaultProps = {
        autoPlay: false,
        maxLoops: 10,
    };  注意这里有分号
    static propTypes = {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    }; 注意这里有分号
    render() {
        return (
            <View />
        );
    }  注意这里既没有分号也没有逗号
}

初始化 STATE

Es5:初始化 state 的方法是固定的 getInitialState

Es6:第一种,直接构造 state 函数;第二种,相当于 OC 中的方法重写,重写 constructor 方法

ES5
var Video = React.createClass({
    getInitialState: function () {
        return {
            loopsRemaining: this.props.maxLoops,
        };
    },
})

ES6
第一种
class Video extends React.Component {
    state = {
        loopsRemaining: this.props.maxLoops,
    }
}
第二种
class Video extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            loopsRemaining: this.props.maxLoops,
        };
    }
}

ES5 常用方法

indexOf

返回某个指定的字符串值在字符串中首次出现的位置

    /**
       * string.indexOf(searchvalue,fromindex) 。
       * searchvalue	必需。规定需检索的字符串值。
       * fromindex	可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。
       */

       var str = "Hello world!";
       console.log(str.indexOf("Hello") + "<br />");

forEach

方法用于调用数组的每个元素,并将元素传递给回调函数

注意:

不会对空数组进行检测

/*array.forEach(function(currentValue,index,arr){},thisValue)
       * 参数1:函数,必须
       *    1)当前元素(必须)
       *    2)当前元素的索引值(可选)
       *    3)当前元素所属的数组对象(可选)
       *
       * 参数2:可选,传递给函数的值,一般用“this”的值,如果参数为空,undefined传递给this值
       * */
       let myArr = [0, 1, 2, 3];
       myArr.forEach(function (item, index, arr) {
         console.log("item:" + item); //1
         console.log(this); //{sex: "女"}
       }, obj);

map

遍历所有元素,将所有元素给一个函数处理,处理后的新元素组成一个新数组返回

map 方法会按照原始数组元素顺序依次处理元素

注意:
1.不会对空数组进行检测
2.不会改变原始数组

    * array.map(参数1,参数2)
       * 参数1:函数 (必须)
       *         函数可传三个参数 :
       *         1)当前元素的值(必须)
       *         2)当前元素的索引值 index(可选)
       *         3) 当前元素属于的数组对象(可选)
       * 参数2 :可选,做为执行函数回调的时候使用,传递给函数,用作this 的值*/

      let num = [1, 2, 3, 4, 5, 6, 7, 8, 9];
      let cs = { a: "ceshi" };
      num.map(function (item, index, num) {
        console.log("item:" + item); //1数组第几位下标的内容
        console.log("index:" + index); //0,数组的下标
        console.log("num:" + num); //1,2,3,4,5,6,7,8,9
        console.log(this);
      },cs);

filter

将数组中所有满足条件的元素组成一个新数组返回

注意:
1.不会对空数组进行检测
2.不会改变原始数组

   /**
       *  array.filter(参数1,参数2,参数3)
       *  参数1	当前元素的值(必须)
       *  参数2	当前元素的索引值(可选)
       *  参数3	当前元素属于的数组对象(可选)
       * **/

       let data = [0, 1, 2, 3];
      let arrayFilter = data.filter(function (item) {
         return item > 0;
       });
       console.log(arrayFilter); //[1, 2, 3]

some

用于检测数组中的元素是否满足指定条件

依次执行数组的每个元素:

如果有一个元素满足条件,则表达式返回 true , 剩余的元素不会再执行检测

如果没有满足条件的元素,则返回 false

注意:
1.不会对空数组进行检测
2.不会改变原始数组

       var obj = {
         a: "qq",
       };
       var arr = [11, 22, 33, 44, 55];
       var result1 = arr.some(function (item, index, arr) {
         console.log(item, index, arr, this);
         console.log("this", this);
         return item > 22;
       }, obj);
       console.log(result1);

every

用于检测数组所有元素是否都符合指定条件

依次执行数组的每个元素:

如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测

如果所有元素都满足条件,则返回 true

注意:
1.不会对空数组进行检测
2.不会改变原始数组

  var obj = {
         a: "qq",
       };
  var arr = [11, 22, 33, 44, 55];
  var result2 = arr.every(function (item, index, arr) {
      console.log(item, index, arr, this);
        return item > 22;
    }, obj);
console.log(result2);

ES6 常用方法

let 变量声明

1.不存在变量提升

     console.log(b1); // 报错:es6.html:19 Uncaught ReferenceError: Cannot access 'b1' before initialization ===> 不能在初始化之前访问'b1'
     let b1 = 10;

2.块作用域

     if (1) {
       var a1 = 100;
       let b2 = 10;
     }
     console.log(a1); // 100
     console.log(b2)  // 报错:b2 is not defined  ===> b2没有定义

3.同一作用域下不能声明同名变量

   let a2 = 100;
   let a2 = 10;
    console.log(a2)
   //  控制台报错:Identifier 'a2' has already been declared  ===> 标识符'a2'已经声明

const 变量声明

1.一旦声明必须赋值,不能使用 null 占位

    const ceshi
    //Uncaught SyntaxError: Missing initializer in const declaration  未捕获的SyntaxError: const声明中缺少初始化式

2.声明后不能再修改

    const ceshi1 = 100;
    ceshi1 = 200;
    console.log(ceshi1) //Uncaught TypeError: Assignment to constant variable. 常数变量赋值

3.如果声明的是复合类型数据,可以修改其属性

    const list = [];
    list[0] = 10;
    console.log(list);  // [10]
    const obj = { a: 100 };
    obj.name = 'apple';
    obj.a = 10000;
    console.log(obj);  // {a:10000,name:'apple'}

解构赋值

1.数组

      let [a, b, c] = [1, 2, 3];//从数组中提取值,按照对应的位置,对变量赋值
      console.log(a);//1
      console.log(b);//2
      console.log(c);//3

2.字符串

      const [a11, b11, c11, d11, e11] = "hello";
      console.log(a11);//h
      console.log(b11);//e
      console.log(c11);//l
      console.log(d11);//l
      console.log(e11);//o

3.对象

      let { foo9: foo91, bar22: bar2 } = { foo9: 'aaa', bar22: "bbb" };
      console.log(foo91);//aaa
      console.log(bar2);//bbb

模板字符串

  let cs = 'Hello World'
      console.log(`foo ${cs} bar`);//foo Hello World  bar
      function fn() {
        return "Hello World"
      }
      console.log(`foo ${fn()} bar`);//foo Hello World  bar

箭头函数

定义用的就是一个箭头, 箭头函数相当于匿名函数,并且简化了函数定义。

1.箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的 this 是词法作用域,由上下文确定。

this 总是指向词法作用域,也就是外层调用者 obj


    var obj = {
      birth: 1990,
      getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
      },
    };
    console.log(obj.getAge());

2.this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略:

    var obj2 = {
      birth: 1990,
      getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth // this.birth仍是1990
        return fn.call({ birth: 2000 }, year);
      }
    };
    console.log(obj2.getAge(2015));

扩展运算符

可以将一个数组转为逗号分隔的参数序列

1.赋值结构

let [head, ...tail] = [1, 2, 3, 4];
console.log(head);//1
console.log(tail);//[2,3,4]

2.push

let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
console.log(arr1);// [0, 1, 2, 3, 4, 5]

3.使用扩展运算符复制数组,复制后 a3 的内容不变

      let a3 = [1, 2, 3, 4];
      let a4 = [...a3];
      console.log(a4);//[1,2,3,4]
      a4 = [9]
      console.log(a4);//[9]
      console.log(a3);//[1,2,3,4]

4.es6 扩展运算符合并数组

const arr3 = ["a", "b"];
const arr4 = ["c"];
const arr5 = ["d", "e"];
console.log([...arr3, ...arr4, ...arr5]);//["a", "b", "c", "d", "e"]

闭包

闭包概念

闭包:有权访问另一个函数作用域中的变量的函数;一般情况就是在一个函数中包含另一个函数。

function person() {
        var name = "有鱼";
        function cat() {
          console.log(name);
        }
        return cat;
      }
      var per = person(); // per的值就是return后的结果,即cat函数
      per(); // 有鱼 per()就相当于cat(),而且变量name没有销毁,一直存在内存中,供函数cat调用

闭包原理

闭包的实现原理,其实是利用了作用域链的特性,我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。

闭包优缺点

优点

1.隐藏变量,避免全局污染
2.可以读取函数内部的变量

缺点

1.导致变量不会被垃圾回收机制回收,造成内存消耗
2.不恰当的使用闭包可能会造成内存泄漏的问题

案例

var a  = 10;
function Add3(){
    var a = 10;
    return function(){
        a++;
        return a;
    };
};
var cc =  Add3();
console.log(cc());
console.log(cc());
console.log(cc());
console.log(a);

promise

Promise 是一个构造函数,用来传递异步操作的消息,链式调用,避免层层嵌套的回调函数。

Promise 对象有三个状态:
1.进行中(pending)
2.成功(resolved)
3.失败(rejected)

创建 promise

 let promise = new Promise((resolve, reject) => {
        resolve("成功") / reject("失败");
      });

调用 promise

当调用 resolve()回调执行的是.then(res=>{})。当调用 reject()回调执行的是.catch(error=>{})。

      promise
        .then((res) => {
          console.log(res); //成功
        })
        .catch((error) => {
          console.log(error);//失败
        });

链式调用

创建
      function promise1(status) {
        return new Promise((resolve, reject) => {
          if (status) {
            resolve("参数");
            console.log("promise1成功");
          } else {
            reject("参数");
            console.log("promise1失败");
          }
        });
      }
      function promise2(status) {
        return new Promise((resolve, reject) => {
          if (status) {
            resolve("参数");
            console.log("promise2成功");
          } else {
            reject("参数");
            console.log("promise2失败");
          }
        });
      }
      调用
          promise1(1)
        .then((res) => {
          // 调用promise1
          console.log(res);
          return promise2(0);
        })
        .then((res) => {
          // 调用promise2,return就可以打印第二个参数
          console.log(res);
        })
        .catch((error) => {});

all

数组内有 promise 必须全部执行成功,才会执行 then 回调,只要有一个不成功就会执行 catch

 Promise.all([promise1(1), promise2(1)])
    .then((res) => {
        console.log("全部调用成功");
    })
    .catch((error) => {
         console.log("失败");
    });

race

当第一个 promise 返回 reject,那么所有的就失败;如果有一个返回 reject,就代表成功

 Promise.race([promise1(1), promise2(1)])
    .then((res) => {
        console.log("成功");
    })
    .catch((error) => {
         console.log("失败");
    });

Promise 优缺点

优点:
1.解决回调
2.链式调用
3.减少嵌套

缺点:
1.无法监测进行状态
2.新建立即执行且无法取消
3.内部错误无法抛出