十五、JavaScript面向对象

一、面向对象概念
  • 关注对象的形式进行开发,面对JavaScript中对象数据类型

  • 面向对象,是一种编程思想、语法、方法、代码编写的方式

  • 面向对象

    • 关注注重对象的操作

      • 可以设定属性/键名

      • 可以设定属性值/键值

      • 可以设定函数

    • 可以将需要执行的程序内容,都定义给对象

    • 调用对象的函数,来执行程序

  • 有JavaScript提供好的内置对象,或者别人写的第三方插件

  • 也可以自己自定义构造函数,创造一个工具

二、工厂模式创建对象

工厂模式:

  • 以固定的模式,生成对象

  • 输入参数数据,就给我们创建一个响应的对象出来

 1 function createObj(n, a, s) {
 2   // 创建对象
 3   const obj = {};
 4   // 给对象添加属性和属性值
 5   obj.name = n;
 6   obj.age = a;
 7   obj.sex = s;
 8   // 给对象添加函数方法
 9   obj.fun = function () {
10     console.log(this.name, this.age, this.sex);
11   }
12   // 返回这个对象
13   return obj;
14 }
15 
16 const obj1 = createObj('张三', 18, '男');
17 console.log(obj1);
三、构造函数创造对象

构造函数:本质还是一个函数,是一个专门生成对象的函数,生成的这个对象,有属性属性值,还有函数方法

  • 定义函数时,还是按照原始方法定义函数

  • 调用函数时,必须使用 new 来配合调用函数

 1 function CreateObj(n, a, s) {
 2   console.log(this);
 3 
 4   this.name = n;
 5   this.age = a;
 6   this.sex = s;
 7   this.fun = function () {
 8     console.log(this);
 9     // console.log(this.name,this.age,this.sex);
10   }
11 }
12 const obj1 = new CreateObj('张三', 18, '男');
  • new 关键词会自动创建一个对象,并且会自动返回这个对象

  • 与 new 一起使用的函数,不用再定义创建对象和返回值对象

  • 所谓的构造函数,本质上就还是一个函数

  • 为了区分构造函数和普通函数,JavaScript约定俗成

    • 构造函数,函数名称 大驼峰命名法

    • 普通函数,函数名称 小驼峰命名法

  • this指向

    • 使用 function 定义的函数,this指向,看的是调用之前写的内容

    • 构造函数的 this,指向的都是通过构造函数,创建的对象

  • 构造函数的返回值,一定是一个对象,通过构造函数生成的对象,称为实例化对象

  • 定义构造函数程序时,不要定义对象,不要定义return

四、原型

prototype:原型

  • 每一个函数天生就具有的自带的属性,叫做prototype

  • 以对象的形式,存储公共的内容

  • 构造函数也是函数,也有 prototype

  • 实例化对象,可以直接指向调用构造函数 prototype 空间中的内容

 1 // 通过公共空间 prototype 定义函数方法
 2 function CreateObj(name,age){
 3   this.name = name;
 4   this.age = age;
 5 }
 6 
 7 CreateObj.prototype.fun = function(){
 8   console.log(this.name,this.age);
 9 }
10 
11 const obj1 = new CreateObj('张三' , 18);
12 const obj2 = new CreateObj('李四' , 20);
  • __proto__: 是每个 对象 都天生就具有的属性

  • prototype:是每个 函数 都天生就具有的属性,是 对象

  • 实例化对象,也是对象,只不过是通过构造函数生成的实例化对象

  • 此时实例化对象 __proto__ 指向的地址就是构造函数 prototype 内存地址

  • 通过 __proto__ 调用的就是构造函数 prototype 中的存储的内容

  • 数据的调用和执行

    • 实例化对象在调用属性和函数方法时,优先调用实例化对象本身的属性和函数方法(也就是说实例化对象中有name属性,prototype中也有name属性,优先调用实例化对象本身的name属性)

    • 如果调用实例化对象本身没有的属性,会去 __proto__ 也就是构造函数prototype中找是否有这个属性

      • 如果有,就调用这个属性

      • 如果都没有这个属性,执行结果是undefined

    • 如果想直接调用 __proto__ 也就是 构造函数 prototype 中定义的属性,可以使用语法,实例化对象.__proto__.属性

  • 实际项目中,prototype中只写函数方法,不要写属性

五、原型链
  • prototype:原型对象

    • 每一个函数,天生都具有 prototype

  • __proto__:原型属性

    • 每一个对象,天生都具有 __proto__

  • JavaScript中每一种数据类型本质上都是对象类型,每一种数据类型实际上都有__proto__属性

  • 每一个数据类型 / 数据,都可以通过 __proto__ 找到生成这个数据类型的 构造函数的prototype

  • 构造函数,本身也有 __proto__ 可以再找这个构造函数的父级构造函数

  • 最终找到的都是 JavaScript中 顶级构造函数Object(),这个过程就是所谓的原型链

六、精确检验数据类型的方法

1、Object.prototype.toString

精确检验数据类型的方法存储在 Object() 顶级中的方法

 1 // Object.prototype.toString.call( 要检查的数据 )
 2 
 3 console.log(Object.prototype.toString.call(true)); // [object Boolean]
 4 console.log(Object.prototype.toString.call(100)); // [object Number]
 5 console.log(Object.prototype.toString.call(100.123));// [object Number]
 6 console.log(Object.prototype.toString.call(1e3)); // [object Number]
 7 console.log(Object.prototype.toString.call(NaN)); // [object Number]
 8 console.log(Object.prototype.toString.call('sting')); // [object String]
 9 console.log(Object.prototype.toString.call(undefined));  // [object Undefined]
10 console.log(Object.prototype.toString.call(null)); // [object Null]
11 console.log(Object.prototype.toString.call([])); // [object Array]
12 console.log(Object.prototype.toString.call({})); // [object Object]
13 console.log(Object.prototype.toString.call(function () { })); // [object Function]
14 console.log(Object.prototype.toString.call(new Date())); // [object Date]
15 console.log(Object.prototype.toString.call(/^\d$/)); // [object RegExp]

判断数据是否是某个具体的数据类型时,判断的字符串也必须有 [ ]

1 console.log(Object.prototype.toString.call(true) === '[object Boolean]');

2、instanceof

  • instanceof用来判断A是否为B的实例

  • instanceof检测的是原型,内部机制是通过判断对象的原型链中是否有类型的原型

1 {} instanceof Object; //true
2 [] instanceof Array;  //true
3 [] instanceof Object; //true
4 "123" instanceof String; //false
5 new String(123) instanceof String; //true

3、constructor

  • 当一个函数F被定义时,JS引擎会为F添加prototype原型

  • 然后在prototype上添加一个constructor属性,并让其指向F的引用

  • F利用原型对象的constructor属性引用了自身

  • 当F作为构造函数创建对象时,原型上的constructor属性被遗传到了新创建的对象上

  • 从原型链角度讲,构造函数F就是新对象的类型

1 ''.constructor == String // true
2 new Number(1).constructor == Number // true
3 true.constructor == Bollean // true
4 new Function().constructor == Function //true
5 new Date().constructor == Date // true
6 new Error().constructor == Error // true
7 [].constructor == Array // true
8 document.constructor == HTMLDoucment // true
9 window.constructor == window //true