zoukankan      html  css  js  c++  java
  • JavaScript原型学习笔记

    原型对象

    任何一个对象都有一个prototype的属性,在js中可以把它记为:__proto____proto__相当于指针,每当你去定义一个prototype的时候,相当于把该实例的__proto__指向一个结构体,那么这个被指向结构体就称为该实例的原型。

    对象是属性的集合,并带有一个单一的原型对象。原型可以是一个对象或空值。

    如图:下面的例子foo对象有俩个显性的x、y属性并且有一个隐形的prototype属性。

    var foo = {
        x:10,
        y:20
    }
    

    原型链

    原型对象也是一个简单的对象,也拥有自己的原型。如果有一个非空引用原型的原型对象,这是所谓的原型链。

    原型链是一个对象的有限链,它用来实现继承和共享。ECMAScript 实现继承的方式主要是依靠原型链。

    显然,对于一个好的设计模式,我们可以重用类似的功能/代码,而不需要在每一个对象中重复。因此,下面的代码中,a对象存储b、c这两个对象的共同部分。而b、c只储存他们自己的附加属性或方法。

    var a = {
      x: 10,
      calculate: function (z) {
        return this.x + this.y + z;
      }
    };
    
    var b = {
      y: 20,
      __proto__: a
    };
    
    var c = {
      y: 30,
      __proto__: a
    };
    
    // call the inherited method
    b.calculate(30); // 60
    c.calculate(40); // 80
    

    我们可以看到,b和c有访问定义在a对象的calculate方法的入口,这是通过原型链实现的。

    • 属性查找规则:当查找一个对象的属性时,如果一个属性或一个方法在对象本身内没有找到(即对象没有这样一个自己的属性),JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部 - 也就是 Object.prototype - 但是仍然没有找到指定的属性,就会返回 undefined

    • hasOwnProperty是Object.prototype的一个方法,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

    • 注意:在使用继承方法时,this的值被设置为原始对象,而不是在该方法被发现的(原型)对象中。例如,在上面的例子中,this.y是取自于b和c,而不是从a,但是,this.x是取自于a,这是通过原型链机制获取的。

    • 事实上,所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。大家要记住,所有函数的默认原型都是Object 的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。object.prototype本身也有__proto__,这是一个链的最后一环,被设置为null。所以,我们说上面例子展示的原型链中还应该包括另外一个继承层
      次。

    构造函数和原型

    每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

    构造函数能做另一个有用的事情-它会自动设置一个新创建的对象的原型对象。这个原型对象存储在constructorfunction.prototype属性中。

    // a constructor function
    function Foo(y) {
      // which may create objects
      // by specified pattern: they have after
      // creation own "y" property
      this.y = y;
    }
    
    // also "Foo.prototype" stores reference
    // to the prototype of newly created objects,
    // so we may use it to define shared/inherited
    // properties or methods, so the same as in
    // previous example we have:
    
    // inherited property "x"
    Foo.prototype.x = 10;
    
    // and inherited method "calculate"
    Foo.prototype.calculate = function (z) {
      return this.x + this.y + z;
    };
    
    // now create our "b" and "c"
    // objects using "pattern" Foo
    var b = new Foo(20);
    var c = new Foo(30);
    
    // call the inherited method
    b.calculate(30); // 60
    c.calculate(40); // 80
    
    // let's show that we reference
    // properties we expect
    
    console.log(
    
      b.__proto__ === Foo.prototype, // true
      c.__proto__ === Foo.prototype, // true
    
      // also "Foo.prototype" automatically creates
      // a special property "constructor", which is a
      // reference to the constructor function itself;
      // instances "b" and "c" may found it via
      // delegation and use to check their constructor
    
      b.constructor === Foo, // true
      c.constructor === Foo, // true
      Foo.prototype.constructor === Foo, // true
    
      b.calculate === b.__proto__.calculate, // true
      b.__proto__.calculate === Foo.prototype.calculate // true
    
    );
    

    构造函数Foo也有自己的__proto__,它指向function.prototype。foo.prototype是Foo指向B和C原型的显式属性。

    原型使用方式

    1. 对象字面量
    var Calculator = function (decimalDigits, tax) {
        this.decimalDigits = decimalDigits;
        this.tax = tax;
    };
    Calculator.prototype = {
        add: function (x, y) {
            return x + y;
        },
        subtract: function (x, y) {
            return x - y;
        }
    };
    //alert((new Calculator()).add(1, 3));
    
    1. 自执行函数
    var Calculator = function (decimalDigits, tax) {
        this.decimalDigits = decimalDigits;
        this.tax = tax;
    };
    Calculator.prototype = function () {
        add = function (x, y) {
            return x + y;
        },
        subtract = function (x, y) {
            return x - y;
        }
        return {
            add: add,
            //subtract: subtract
        }
    } ();
    alert((new Calculator()).add(11, 3)); //14
    //alert((new Calculator()).subtract(11, 3)); //not a function
    

    这种方法的好处就是可以封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果。

    如果觉得本文不错的话,帮忙点击下面的推荐哦,谢谢!

    我的博客:http://bigdots.github.iohttp://www.cnblogs.com/yzg1/

    参考文章:《ECMA-262》《JavaScript探秘:强大的原型和原型链》

  • 相关阅读:
    消息中间件与kafka(二)
    维度建模基本概念(二)
    阿里开源canal
    ETL-kettle报错--org.gjt.mm.mysql.Driver
    消息中间件与rabbitmq(一)
    python装饰器--这个很pythonic
    Swift开发小技巧--识别选中照片中的二维码
    Swift开发小技巧--扫描二维码,二维码的描边与锁定,设置扫描范围,二维码的生成(高清,无码,你懂得!)
    Swift开发小技巧--自定义转场动画
    Swift基础--通知,代理和block的使用抉择以及Swift中的代理
  • 原文地址:https://www.cnblogs.com/yzg1/p/5279611.html
Copyright © 2011-2022 走看看