• JS简记-委托


    js中不存在“类”,js除基本类型外,其余都是对象。如果试图在js身上使用“类”思维来编程,会使程序变得异常复杂,且晦涩难懂。由于对象的存在,在js中更适合使用“委托”方式来实现类的“继承”(其实此时已不能称为继承)。

    先来看“类”的思想:

     1 function Hello(){
     2 }
     3 Hello.prototype.helloWorld = function() {
     4     console.log("hello ");
     5 }
     6 function World(){
     7 }
     8 World.prototype = Object.create(Hello.prototype);//继承Hello
     9 World.prototype.helloWorld = function(){
    10     Hello.prototype.helloWorld.call(this);//伪多态
    11     console.log("world !");
    12 }
    13 var helloWorld = new World();//实例化World
    14 helloWorld.helloWorld();
    15 console.log(helloWorld instanceof World);//true
    16 console.log(helloWorld instanceof Hello);//true
    17 console.log(World.prototype.isPrototypeOf(helloWorld));//true
    18 console.log(Hello.prototype.isPrototypeOf(helloWorld));//true

    再来看“委托”的思想:

     1 var Hello = {
     2     hello(){
     3         console.log("hello ");
     4     }
     5 };
     6 var World = Object.create(Hello);//World关联到Hello
     7 World.world = function(){
     8     this.hello();
     9     console.log("world !");
    10 }
    11 var helloWorld = Object.create(World);//产生一个关联到World的新对象,可以在新对象上做进一步操作,比如生成新属性
    12 helloWorld.world();//hello world !
    13 console.log(World.isPrototypeOf(helloWorld));//true
    14 console.log(Hello.isPrototypeOf(World));//true

    使用“委托”后,不再需要伪多态,同时由于省去了晦涩的prototype(prototype的存在就是为了提供“原型继承”机制),使得代码更加简洁。而且,在原型链的判断上也更加清楚。

    ES6引入了全新的class关键字,使得js看上去拥有了“类”的能力,但其实则是语法糖。

     1 class Animal{
     2     constructor(variety) {
     3         this.variety = variety;
     4     }
     5     variety(){
     6         return this.variety;
     7     }
     8 }
     9 class Dog extends Animal{
    10     constructor(variety){
    11         super(variety);
    12     }
    13     roar(){
    14         console.log(super.variety() + ": " + "wang wang");//这里也可以不需要super,直接调用variety()
    15     }
    16 }
    17 var dog = new Dog("dog");
    18 dog.roar();//dog: wang wang

    下面就是dog对象的内部结构,可以看到其还是使用了原型链。

     再来看一下Dog“类”,其和function的结构类似(都有arguments、caller、length、name),且原型链上都有Function.prototype。最关键的是Dog.prototype.__proto__其实就是Animal.prototype,这很好理解了。

    通过上面观察,发现class关键字并不神奇,真正神奇的是super关键字。查阅资料发现,class中的每一个方法,js引擎内部都维护着一个叫做[[HomeObject]]的引用,该引用指向方法的宿主对象,通过该对象就可以产生super语义,其内部机制如下:

    1. 首先根据被调用方法的[[HomeObject]]属性值(即当前方法的归属对象),通过Object.getPrototypeOf()获取原型;
    2. 获取到原型后,检索同名方法;
    3. 绑定this指向并执行方法函数。

    比如,针对Dog类的roar方法,js引擎就维护着一个[[HomeObject]](可以看成是roar方法内部的一个属性,但是无法获取):

    super关键字与this关键字不同,this在运行时动态确定,super在声明时确定,也就是说[[HomeObject]]在声明一个类时就已被赋值了(这很好理解):

     1 class Animal{
     2     constructor(variety) {
     3         this.variety = variety;
     4     }
     5     variety(){
     6         return this.variety;
     7     }
     8 }
     9 class Dog extends Animal{
    10     constructor(variety){
    11         super(variety);
    12     }
    13     roar(){
    14         console.log(super.variety() + ": " + "wang wang");//这里也可以不需要super,直接调用variety()
    15     }
    16 }
    17 var dog = new Dog("dog");
    18 dog.roar();//dog: wang wang
    19 var roar = dog.roar;
    20 var variety = "dog2";
    21 roar.call(window);//es6默认采取“use strict”,输出dog2: wang wang

    虽然class关键字使js有了“类”的模样,但其仍然有很多限制,比如class中无法直接定义类属性(java中的static字段),如果有需求,还是需要通过prototype来定义(注意属性屏蔽)。

  • 相关阅读:
    在centOS上安装oracle出现java.lang.NoClassDefFoundError问题及解决方法
    centos6.5下安装oracle11g
    配置单点登录
    CentOS 环境变量编辑、保存、立即生效的方法
    python如何调用C语言程序
    python生成exe可执行程序
    python的encode()和decode()函数
    python 获取时间
    python修改字符串的值
    python enumerate()函数
  • 原文地址:https://www.cnblogs.com/holoyong/p/9005631.html
Copyright © 2020-2023  润新知