进阶教程 1. 闭包、this、和面向对象

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战javascript

1、 闭包

闭包定义:

  • 解释:函数执行时造成一个私有做用域,保护里面的变量不受外界干扰,这种保护机制成为闭包。
  • 市面理解:造成一个不销毁的私有做用域(私有栈内存)才是闭包

闭包应用:

1. 柯里化函数

柯里化函数思想:把多参数的函数变成单参数的函数java

function fn(a, b, c) {
   return a + b + c;
}

function fn1(a) {
   return function (b) { // 这种在函数中return 函数的作法是市面中认为的闭包
      return function (c) {
         return a + b + c;
      }
   }
}
fn1(1)(2)(3);
复制代码

2. 利用闭包机制隔离全局命名空间

(function () {
   // 自执行函数执行也是闭包
   let a = 100; // a是一个私有变量,不会影响全局做用域中的变量命名
})();

复制代码

3. 惰性封装

var utils = (function () {
   var version = '1.0.1';
   function sum(a, b) {
      return a + b
   }
   function minus(a, b) {
      return a - b;
   }
   return {
      sum: sum,
      minus: minus
   }
})();
复制代码

4. 利用闭包的不销毁做用域保存数据:累加计数、选项卡闭包版本

2、 this 关键字

this是JS的关键字,表明当前代码执行的环境对象。通常在函数中使用,而且是在函数执行时,根据函数的不一样执行方式肯定不一样的值。目前阶段有如下状况:数组

1. 事件函数中的this是绑定该事件的元素;

let box = document.getElementById('box');
box.onclick = function () {
   console.log(this); // box 元素对象
};
复制代码

2. 自执行函数中的this是window

(function () {
   console.log(this);
})();

复制代码

3. setTimeout/setInterval() 定时器回调函数中的this指向window

setTimeout(function () {
   console.log(this);
}, 0); // 定时器写0也不会马上执行,也须要等待其余同步代码执行完才会执行;

复制代码

4.方法调用时,看方法前面是否有点 . 若是有点前面是谁,this就是谁,若是没方法中的this就是window

var num = 13;
var obj = {
   num: 12,
   fn: function () {
      console.log(this.num);
   }
};
obj.fn(); // 12
obj['fn'](); // 12 obj['fn'] 等效于 obj.fn 因此,this仍然指向obj

var fn = obj.fn;
fn(); // 13;window.num

复制代码

6. 箭头函数中的this指向函数定义时所在做用域中的this

箭头函数:

ES6新增的语法:省略function关键字,在形参入口后增长 => 箭头,后面紧跟函数体;浏览器

let f = (a, b) => {
   return a + b;
   console.log(this)
};
f();

复制代码

箭头函数的简化语法:

1. 只有一个形参时,能够省略 形参入口的小括号
let f2 = a => {
   var x = 10;
   x += a;
   return x;
};
复制代码

2. 若是函数只有一行代码,或者只有return 指定返回值,能够省略函数体的花括号和return关键字

let transfer = (a, b) => a + b;
// 等效于:
let transfer = function (a, b) {
   return a + b;
}

复制代码

7. 全局做用域中的this是window

console.log(this);markdown

8. this在运行时不能够赋值

this = {};  // 报错
复制代码

3、 ++i 和 i++

++i和i++都是给i累加1,可是加的时机不一样闭包

  • ++i 是先累加自身,而后再取累加后的值和其余值运算
  • i++ 是先取当前值和其余值运算,再累加自身
var i = 0;
console.log(++i); // 1
console.log(i++); // 0

复制代码
var a = 12; // 13 14
var b = 13; // 14 15

console.log(++a + a++ + b++ + ++b + a + b); // 13 + 13 + 13 + 15 + 14 + 15 = 83
复制代码

4、 面向对象

4.1 面向过程

面向过程:以过程为核心,研究如今要解决的问题,既不考虑之前,也不考虑未来,这段代码就解决如今的问题。若是之后再有相同的功能,就再写一遍相同的代码;函数

4.2 面向对象

面向对象:是一种对现实世界的理解和抽象的方法。面向对象关心如今的功能能分分类解决,如今解决过的问题,咱们过往有没有相似的代码能够复用,咱们如今的写的代码能不能给未来用。工具

4.3 面向对象的研究范畴

  • 对象:万事万物都是对象,每一个对象都具有各自的属性和功能;post

  • 类:抽象事物的特性和特色,把对象分红不一样的类型,例如老师类、学员类,类是一个是描述一群事物的共同特色的抽象概念;ui

  • 实例:类中的一个具体的个体。这个个体既然属于类,那么这个个体必定具备这个类的全部的特性和功能。

    1. 例如:人类就是一个类,人类最显著的特色是能够制造并使用工具。人类的属性有语言、智慧、吃饭、睡觉.... 每一个人都是人类的一个实例,每一个人都有这个类型中的全部的特性和属性。
  • ? 那么js的面向对象体如今哪里呢?

咱们强调数据类型,其中强调的就是类型。例如数组类、普通对象类,这是由于数组类和对象的属性和方法不一样。 例如数组是有序的键值对,还能够push,pop、splice等,而对象是无序的键值对之和,并且对象不能够pop 而 var ary = [1, 2] 是数组的一个实例,因此ary有全部数组的特性 而 var obj = {name: 1} 是对象的一个实例;

4.4 JS中的内置类:

  • Object
  • Array
  • Date
  • RegExp
  • Function

这些内置类都是函数数据类型的

console.log(typeof Array); // function
console.log(typeof Object); // function
复制代码

面向对象的研究范畴

对于面向对象要求咱们掌握 封装、类的继承和多态

5、 单例模式

5.1 普通单例

在过往咱们面向过程时,描述一个同窗:

var name = '张三';
var age = 18;
var sex = 'boy';

复制代码

描述另外一个同窗:

var name = '李四';
var age = 19;
var sex = 'girl';
复制代码

这样作有一个问题,由于变量只能表明一个值,全局变量后面的会覆盖前面的。致使前面的数据丢失。 为了解决这个问题,咱们如今在描述一个事物,咱们可使用一个对象,由于对象是用来描述一个事物的,而对象的属性就是定性描述这个对象的特征,而属性值是定量的描述事物的这个特征。

var stu1 = {
   name: 'zhangsan',
   age: 18,
   sex: 'boy'
};

var stu2 = {
   name: '李四',
   age: 19,
   sex: 'girl'
};

复制代码

像上面这样,把描述一个事物的属性放到一个对象内这种封装方式称为单例模式。 单例模式的优势是解决了全局变量互相覆盖的问题,这样stu1的name和stu2的name没有关系,由于stu1和stu2是两个不一样的对象,此时stu1和stu2表明的对象叫作单例,而stu1和stu2这两个变量名称为命名空间;

5.2 高级单例

高级单例:高级单例模式再也不是直接将一个对象赋值给命名空间,而是先执行一个自执行函数,在函数执行结束时返回一个对象;

var person = (function () {
   function eat(food) {
      console.log(`I like eating ${food}`)
   }
   function hobby(h) {
      console.log(`I like playing ${h}`)
   }
   var account = '$10000000';
   var name = '王老五';
   var age = 40;
   return {
      name: name,
      age: age,
      eat: eat,
      hobby: hobby
   }
})();

复制代码
  • 这样写,有一个优点,咱们能够在自执行函数的做用域中声明变量和函数,这个做用域不会销毁,咱们能够在最后返回对象里面选择导出哪些变量和方法给外界使用,不导出的,外界拿不到;

单例模式虽然好用,可是有一个问题,有一个对象,咱们就须要写一个这个对象,很繁琐。

6、 工厂模式

如何批量生产对象?

function reg(name, age, sex) {
   var obj = {}; // 原材料
   obj.name = name; // 加工
   obj.age = age; // 加工
   obj.sex = sex; // 加工
   return obj; // 出厂
}

let s1 = reg('阿三', 19, 'boy');
let s2 = reg('李四', 18, 'girl');

console.log(s1 === s2); // false

复制代码
  • 工厂模式:像上面这样,把实现相同供的函数封装成一个函数,当咱们须要建立一个实例的时候,咱们就执行这个函数便可,而且每一个对象都是单例;
  • 优点:高内聚,低耦合 提升了代码的复用度

工厂模式虽然解决了批量生产的问题,可是咱们说面向对象还要有类的概念,可是这种方式生产的对象都是同一类,没有分类。

  • 思考?内置的类型都有类型的概念?

js有两种建立数据的方式,一种是字面量,另外一种是实例的方式,例如:

var obj = new Object();
obj.name = '李四';
obj.age = 19;
obj.sex = 'girl';
console.log(obj);

复制代码

// ? 为何js能够经过new 操做符来生成实例?并且是有类型的?咱们的能够不能够呢?

var obj2 = new reg('li', 13, 'g'); console.log(obj2); // 一样获取了一个实例对象,可是没有发现类型

7. 构造函数模式

前面的工厂模式已经能够批量生产了,可是仍是没有咱们所说的面向对象中类型的概念。为了有类型的概念,咱们须要构造函数模式。

构造函数:构造函数也是一个函数,可是调用方式有别于工厂函数:

  1. 调用方式不一样,构造函数只能经过new操做符调用;
  2. 工厂函数内须要手动建立对象实例,而构造函数模式不须要手动建立对象,在构造函数被new执行时,构造函数中的this自动和实例绑定,因此咱们全部的加工都发生在this上;
  3. 工厂函数须要手动返回对象实例,而构造函数在被new操做符调用时不须要手动返回实例;

7、构造函数模式:

经过new调用一个函数,此时这个函数再也不是普通函数,而是成为一个类,函数名称为类名,而经过new调用,自动返回这个类的一个实例。在构造函数中,咱们须要抽象这个类型的属性和功能;

function Teacher(name, age, subject, from) {
   this.name = name;
   this.mission = '传道受业解惑';
   this.age = age;
   this.subject = subject;
   this.from = from;
   this.teach = function () {
      console.log(`${name} 老师教 ${subject} 学科`);
   }
} // Teacher是一个类,这里类型抽象了老师的属性,一个老师有的属性有姓名,年龄,教授学科,哪一个学校的老师,以及老师会讲课的功能。

// 建立一个实例:
let mrMa = new Teacher('马宾', 18, 'js', '江外琉璃');
console.log(mrMa);

let mrJiang = new Teacher('陆辉', 19, 'Architect-FE师', '江外琉璃');
console.log(mrJiang);
console.log(typeof mrJiang); // object
console.log(typeof mrMa); // object

复制代码
  • 经过浏览器控制台查看,这两个实例(对象)的前面出现了 Teacher,此时说明mrMa和mrJiang都属于Teacher类的实例。

instanceof 运算符

  • 如何检测当前对象是不是当前类型的实例:

instanceof 运算符:检测对象是不是某个类型的实例,若是是true,不然返回false

console.log(mrJiang instanceof Teacher);
console.log(mrMa instanceof Teacher);
console.log([] instanceof Teacher);

console.log([] instanceof Object); //
console.log(mrJiang instanceof Object);
console.log(mrMa instanceof Object);

复制代码
  • 可是由于Object是基类,全部实例都是对象数据类型的,因此用instanceof检测是不是Object的实例,都会返回true;
相关文章
相关标签/搜索