AI智能
改变未来

原生JS–关于面对对象,这篇解析得通俗易懂


1、引言

初学者在学习面对对象时可能总是会被绕晕,也理解不了面对对象中各种名词,但是了解这些概念在面对对象编程中极为重要,也意味着你能否学懂面对对象编程。下面我会利用已知探索未知去讲解面对对象,帮助大家理解。

2、创建对象

  • 不知道大家是否还记得,在创建数组时,有两种创建方式。一种是字面量创建,即
    let arr = [2, 3, 4];

    ,另一种是构造函数创建,通过关键字

    new

    来创建,即

    let arr = new Array(2, 3, 4);

  • 这里的
    Array

    是一种内置构造函数。通过

    new

    执行构造函数,创建数组(数组也是对象)。

  • new

    执行方式:执行函数,凡是用new执行的函数,都叫构造函数。

  • 也就是说我们可以自己创建自定义构造函数。这里我们先说一下
    new

    的原理:

  • new的原理:
    1、创建了一个新对象
    2、修改了函数中的this指向,指向第1步创建的新对象
    3、检测原函数中是否主动返回对象,如果没有,那么返回第1~3步创建的对象
    4、并将新对象中的__proto__指向了该构造函数的prototype

先不用理解,继续向下看?

  • 创建自定义构造函数:
function Fn() { // 行业规范,构造函数的函数名采用大驼峰式console.log(this);}Fn(); // 普通执行:this指向就是windowlet f1 = new Fn(); // new执行:this的指向是new执行后构造函数的同名对象(new的原理第2点)console.log(f1); // f1是new执行的返回值,函数同名对象 Fn{}(new的原理第1、4点)let f2 = new Fn();console.log(f1 == f2); // false 每次new执行创建的都是新对象,两两不相等
  • 1、每次
    new

    的执行都会创建一个新对象,即上述代码中的

    f1、f2

    ,且这些对象两两不相等。

  • 2、通过
    new

    的执行修改了函数中

    this

    的指向,指向执行时创建的新对象,即指向上述代码中的

    f1、f2
  • 3、如果构造函数不主动返回对象,那它的返回值就是每次执行时创建的新对象
  • 4、(不急,这点需要结合原型)

循序渐进,来看看下面这段代码,看懂后我们再进行原型的介绍。

function Fn(n) {// this指向对象,给new出来的对象添加属性this.name = n; // admin}let f1 = new Fn(\"admin\"); // new执行时传参console.log(f1); // Fn{name:\"admin)

3、原型

  • 创建一个自定义构造函数Fn
function Fn(n) {this.name = n;this.show = function() {console.log(this.name);}}// 通过new创建一个对象let f1 = new Fn(\"admin\");console.log(f1); // Fn {name: \"admin\", show: ƒ}f1.show(); // admin// 通过new再创建一个对象let f2 = new Fn(\"root\");console.log(f2); // Fn {name: \"root\", show: ƒ}f2.show(); // root// 这两个对象不相等,且具有相同功能的show函数也不等console.log(f1 == f2); // falseconsole.log(f1.show == f2.show); // false 两个对象的show方法不相等,与下面做对比?
  • 与数组的构造函数式创建来对比
let arr1 = new Array(2, 3, 4);let arr2 = new Array(4, 5, 6);console.log(arr1 == arr2); // false// push是数组的方法之一console.log(arr1.push == arr2.push); // true 数组的方法是相等的,与上面做对比?
  • 也就是说,到这一步我们的自定义构造函数并未创建成功,我们的需求是让
    console.log(f1.show == f2.show)

    的结果为

    true

  • 先卖个关子,给一个已知条件:内置构造函数创建的对象的方法,都被绑定在了自己的构造函数的原型对象
    (prototype)

    身上。

  • 比如数组的
    push

    方法,就被绑定在了数组的构造函数的原型对象身上

    Array.prototype.push
  • 先来看看这个
    prototype

    是个啥

console.log(Array.prototype); // 一个伪数组,包含了数组所有的方法
  • 继续使用数组来举例,我瞎编一个
    sayHello

    的方法,在

    arr1

    身上肯定没有

    sayHello

    这个方法,如果想通过

    arr1

    来执行

    sayHello

    方法

// 接上面代码// arr1.sayHello(); // 如果直接通过arr1来执行这个方法,报错,必须先绑定在arr1身上arr1.sayHello = function() {console.log(\"hello\")}arr1.sayHello(); // hello
  • 如果我想让
    arr2

    也执行

    sayHello

    方法,也必须要再绑定再

    arr2

    身上,如果我想让

    arr3、arr4..

    等执行这个方法,就得一个一个绑定,很耗性能。

  • 但是,如果将这个方法绑定在数组的构造函数的原型身上,如下
Array.prototype.sayHello = function() {console.log(\"hello\");}// 比如我想让arr2来执行sayhello(在上面的案例中,arr2未绑定此方法)arr2.sayHello(); // hello
  • 执行成功了,就算创建无数个数组,它们都能执行
    sayHello

    这个方法,这个叫做\”继承\”。

  • prototype的原理:
    在对象自身拥有一个内置属性:proto,每当在构造函数的原型对象上如(Array.prototype)绑定一个方法时,都相当于在每个实例身上的__proto__这个属性里绑定了这个方法。
    * 这就是new原理的第4点。
  • 这个

    __proto__

    可以在浏览器上看到(注意

    proto

    左右是两个下划线),原型身上的属性或方法可以在这里找到

  • 由于一个实例至少会有两个

    __proto__

    (一个是自身的构造函数的,另一个是顶层原型对象的),所以原型也称为原型链

  • 现在回到需求,如果把

    show

    方法绑定给自定义构造函数

    Fn

    的原型对象

function Fn(n) {this.name = n;// 不在构造函数内部设置show方法// this.show = function() {//     console.log(this.name);// }}// 把show方法绑定给Fn的prototypeFn.prototype.show = function() {console.log(this.name);}// 通过new创建一个对象var f1 = new Fn(\"admin\");console.log(f1); // Fn {name: \"admin\", show: ƒ}f1.show(); // admin,就算f1自身没有绑定show方法,仍能执行// 通过new再创建一个对象var f2 = new Fn(\"root\");console.log(f2); // Fn {name: \"root\", show: ƒ}f2.show(); // rootconsole.log(f1 == f2); // falseconsole.log(f1.show == f2.show); // true,相等了
  • 相等了,也就是说我们的自定义构造函数创建成功了

至此,面对对象的基础使用就已经结束,下面总结面对对象的语法、代码及概念

4、总结

  • 语法
  • 面对对象的语法:
    1、属性写在构造函数内部的this身上
    2、方法写在构造函数的原型(prototype)上
    3、原型身上的方法在被实例执行时,其内部的this依然指向实例
  • 代码
function Fn(n) {this.name = n;}Fn.prototype.show = function() {console.log(this.name);}let f = new Fn(\"参数\");f.show();
  • 概念1、实例:上述所有通过
    new

    执行创建的对象,都称为实例

  • 2、原型:构造函数的prototype(显式原型)是当前构造函数身上的一个属性,自身是对象类型
  • 专门作为将来的实例的__proto__的指向
  • 所有添加给prototype的属性和方法,都能被将来的实例使用
  • 实例的__proto__(隐式原型)
      所有对象都具有的默认属性,自身是对象类型
    • 指向了:构造自身的构造函数的原型prototype
    • 当实例身上没有某个方法或属性时,默认查找__proto__的方法或属性
  • 赞(0) 打赏
    未经允许不得转载:爱站程序员基地 » 原生JS–关于面对对象,这篇解析得通俗易懂