zoukankan      html  css  js  c++  java
  • 认识JavaScript的原型

    本来打算也写一个JavaScript学习笔记的系列,不过由于笔者不太想买大部头的js数据,和网上的资料也不少,所以js系列就打算写到了算了了。

    要理解JavaScript就要理解其原型,首先我们先区分一下JavaScript中的两种不同方式创建的函数;

    直接定义得到的函数

    1 function foo1(){}
    2 console.log(foo1.prototype);
    3 console.log(foo1.__proto__);
    4 
    5 var foo2 = function() {}
    6 console.log(foo2.prototype);
    7 console.log(foo2.__proto__);

    这里有两个属性prototype和__proto__,我们来看他们分别指向什么。

    1. prototype:指向函数原型;
    2. __proto__:指向一个匿名的空方法;

    我们在看看foo1.prototype包含的属性:

    1. constructor(指向函数本身)
    2. __proto__(指向父级对象的prototype),可以看下面的验证代码:
    1 function foo(){}
    2 console.log(foo.prototype.__proto__ === Object.prototype);//true

    可以看见,原型对象的__proto__指向其父级对象的prototype;

    通过new关键字创建得到的对象

    1 function foo(){}
    2 var a = new foo();
    3 console.log(a.prototype);//undefined
    4 console.log(a.__proto__);//Object

    通过输出我们可以发现,通过new得到的对象,prototype属性是空的,而__proto__则被赋予了一个对象,看下面的代码:

    1 function foo(){}
    2 var a = new foo();
    3 console.log(a.__proto__ === foo.prototype);//true

    js将foo的原型属性赋予了用new关键字创建的a对象;

    我们看看使用new关键字js为我们做了什么操作;

    比如下面的代码:

    var a = new foo();

    可以理解为调用了下面的代码:

    1 var a={};//也就是说,初始化一个对象a;
    2 a.__proto__=foo.prototype;//赋值原型链;
    3 foo.call(a);//也就是说构造a,也可以称之为初始化a;

    原型继承

    我们再来看看js的原型继承,js中的继承是通过原型链来体现的,简单的说,当我们调用一个属性时(方法在js中也是以属性的形式存在的),会先查找自身是否有该属性,如果没有则查找原型上是否存在该属性,如果还是没有,则查找原型上的__proto__(即父类的原型)里是否有该属性,如果没有则一致搜索到最顶级(即Object的原型),找到则返回该属性的值,找不到则返回undefined。

    我们看下下面的代码:

     1 var foo = function(){
     2     var a = 0;
     3     this.a = 1;
     4 };
     5 foo.prototype.a = 2;
     6 foo.prototype.b = "b";
     7 console.log(foo.a);//undefined
     8 foo.a = 4;
     9 foo.c = 5;
    10 console.log(foo.a);//4
    11 
    12 var obj = new foo();
    13 console.log(obj.a);//1
    14 console.log(obj.b);//b
    15 console.log(obj.c);//undefined

    我们分析一下:

    1. 函数中的var a = 0;是一个作用域在该函数中的临时变量,函数外部是不能访问的;
    2. 函数中的this.a = 1;定义的变量只能在使用new关键字创建的对象中才能访问到;
    3. 直接在foo上面赋值的a,也只能使用foo.a可以访问到,使用new关键字创建的对象不能访问到;
    4. 如果没有在函数内部使用this.b = 1;来创建的属性,会去其原型对象prototype上寻找,找到则返回了1,相反,a在函数内部指定了,则可以访问到;
    5. 在foo上直接定义的c,使用new创建的对象不能访问到;

    如果按面向对象的思维来看,可以这么理解:

     1 //创建类 Foo,按一般的规则类名首字母大写
     2 var Foo = function(){
     3     this.a = 1;//创建一个公开的属性a
     4 };
     5 //创建一个公开的方法 add
     6 Foo.prototype.add = function(a, b){
     7     return a + b;
     8 }
     9 //创建一个静态变量 num
    10 Foo.num = 100;
    11 //创建一个静态方法 subtract
    12 Foo.subtract = function(a, b){
    13     return a - b;
    14 }
    15 
    16 //调用静态属性及方法
    17 console.log(Foo.subtract(Foo.num, 11));//89
    18 //调用对象属性及方法
    19 var obj = new Foo();
    20 console.log(obj.add(obj.a, Foo.num));//101

    实现类继承

    目前我们知道了使用js来模拟编写一个类的方法,即如何封装我们知道了,但是面向对象编程还有两个重要的特性:继承和多态;

    但是由于js是没有类型的概念的,所以多态这个特性我们可以忽略,那么js如何使用原型来实现类继承的效果呢?

    实际上,有很多方法可以实现类继承的效果,或者复杂,或者简单,接下来的两篇文章,我会介绍两种js实现类继承的方法:

    1. TypeScript的实现方式,由微软维护的js的超集,实现了静态语言的大部分特性,学习TypeScript编译出的JavaScript的实现方式,微软都这么实现了,咱们就照搬就行了;
    2. Cocos2dx-js的实现方式,作为一款成熟的游戏框架,cocos的实现不同于微软的ts的实现,但也一种值得学习的类实现的方式;

    以上方式大家可以二选一,当然也可以使用别的方法;

    最后说一下,最新的js标准ES6中,已经支持class关键字来定义类了,不过在ES6尚未普及的这几年,为了兼容更多的用户还是乖乖使用老的方式吧;

  • 相关阅读:
    linux 查看磁盘空间大小
    Linux上运行Python文件
    linux 删除多个文件
    python3.6安装pycrypto,pycrytodome和crypto(转)
    Fiddler显示服务器IP的方法(转)
    sublime text3支持Vue语法高亮显示步骤(转)
    Python执行select的SQL后的结果
    Python连接MySQL数据库
    Vue工程启动流程
    Python之线程 2
  • 原文地址:https://www.cnblogs.com/hammerc/p/5345020.html
Copyright © 2011-2022 走看看