JavaScript 对象(三)

来源:互联网 发布:写私密日记的软件 编辑:程序博客网 时间:2024/05/17 23:04

一:原型

1、原型的定义: 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过改构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。

  2、利用原型特点和概念,可以提取共有属性。将一类对象的共有属性提取出来,放到该类对象的原型中,从而不需要每次用new操作符时都重新定义一遍该共有属性。

  如下,定义一个Person构造函数,而属于Person多构造对象共有的属性方法,则定义到Person的原型中

Person.prototype = {        eat: function (food) {           console.log('I have eated ' + food);        },        sleep: function () {          console.log("I am sleeping");        }      }      // 人的构造函数      function Person (name, age) {        this.name = name;        this.age = age;      }      var person1 = new Person('lyl', 18);      console.log(person1.name); //lyl      person1.eat('apple'); //I have eated apple

3、如何查看原型:
之前是不允许我们查看构造函数的原型的,但后来提供了一个可查看构造函数原型的接口:隐士属性proto(其实我们能够访问原型的属性,或者说继承原型,靠的就是proto属性连接着构造函数和原型,可以说没有proto属性的存在,就无法实现原型的继承)

(1)、首先我们先说明一下proto这个接口是存放到哪里的

 看过以上对象创建过程的都应该知道在用new创建一个对象时,内部会隐士自动创建一个this的对象,进过一系列处理后再隐士将this对象返回。而proto就对于隐士创建的this对象中,如下代码:

// 原型    Person.prototype = {      say: function () {        console.log("I am saying ");      },      play: function () {        console.log("I am playing");      }    }    // 构造函数    function Person (name) {      // var this = Object.create(Person.prototype);      // p.s.在隐士创建的this对象中存在一个属性,即__proto__,该属性存储了Person.prototype      this.name = name;      // return this;    }    // 对象的创建    var person1 = new Person('lyl');    // 打印原型    console.log(person1.__proto__);

(2)、如何查看原型:直接通过new操作符创建的对象访问proto属性即可,如上代码演示

4、如何查看对象的构造函数,我们通过属性constructor来查看:

contructor属性位于构造函数的原型中,其中存储的是构造函数信息,所以在不知道原型的情况下,由原型继承原理,我们可以用实例对象来直接访问constructor,即获取创建该实例的构造函数

 function Person () {           this.name = 'myName';           this.age = 18;       }       var person = new Person();       console.log(person.constructor); // function Perso(){...}

二:原型链:

1、定义:顾名思义,原型链就是将一个个原型串连起来,形成一条原型继承的链子。

2、原型链的构成:

 如下代码例子, Child继承Parent, Parent继承GrandParent, 而GrandParent没有自定义原型,所以默认为原型链的最顶端new Object();

(为什么Object为最顶端,因为Object.prototype为null,为null是没有原型的)

//    原型链: Child -> new Parent() -> new GrandParent() -> new Object();       function GrandParent() {           this.name = 'GrandParent';           this.a = 3;       }       Parent.prototype = new GrandParent();       function Parent() {           this.name = 'parent';           this.b = 2;       }       Child.prototype = new Parent();       function Child() {           this.name = 'child';           this.c = 1;       }       var child = new Child();       console.log(child); // Child {name: "child", c: 1}       console.log(child.a); // 3       console.log(child.b); //2       console.log(child.c); //1

3、原型链的增删改查:

 使用如上的原型链说明, Child -> new Parent() -> new GrandParent() -> new Object(), 实例对象为child

(1)、增:

为child实例对象添加属性,总是添加为其自己本身的属性,为对原型和原型链是没有影响的。(再具体说即对和其相同构造函数构造的实例对象无法造成影响,以下说法同此)

(2)、删:

 使用delete操作符只能删除child实例对象自己本身的属性,而无法删除由原型继承而来的属性

(3)、改:

分两种情况:

若修改的属性为继承自原型的,且值类型为原始值,则仅仅修改的是该实例对象的属性,对原型无法造成影响。

若修改的属性为继承自原型的,属性值类型为引用值,则对引用值的修改又分两种情况:

第一种是直接对该修改的属性赋值 => 此情况仅仅修改的是实例对象的该属性,无法对原型造成影响。

第二种是对该修改的属性添加内容或去除内容,而不是对其重新赋值 => 此情况会对原型造成影响。如下例子:

Person.prototype = {            has: [1, 2, 3]        }        function Person () {            this.name = 'lyl';        }        var person1 = new Person();        var person2 = new Person();        person1.has.push(4);        // person1 和 person2都改变了,因为person1的修改影响到了原型,进而影响到了另一个实例对象        console.log(person1.has); //[1, 2, 3, 4]        console.log(person2.has); // [1, 2, 3, 4]

4)、查:

查询过程如下,首先看构造函数中是否有要查询的属性,若有,则直接返回,若没有,则看其原型有没有要查询的属性,若没有,则再看原型的原型上是否有要查询的属性,以此顺序在原型链上查询,若一直到原型链顶端后仍没有要查询的属性,则返回undefined

p.s.理解了在原型链上的增删改查后,自然就能理解在原型上的增删改查了,只要把在原型上的增删改查当成只有一个原型的很短的原型链即可。

4、绝大多数对象最终都会继承自Object.prototype

为什么事绝大多数呢?因为null,和undefined是没有原型的,上文有详细提到
十一、this基本介绍:

  1、函数预编译过程 this —> window
  2、全局作用域里 this —> window

  3、obj.func(); func()里面的this指向obj), 可以这样理解,谁调用func,则this就指向谁

  4、call/apply 可以改变函数运行时this指向,

    (1)、call用法:

      func.call(要改变后的this, arg1, arg2, … );

    (2)、apply用法:

      func.apply(要改变后的this, [arg1, arg2, arg2]);

    (3)、apply和call共同点:都是改变this指向

        apply和call不同点:传参形式不同,call是将参数一个个传进来,而apply是将所有参数存进一个数组中,然后将该数组传

复制代码// demo1    function demo1() {        console.log(this);    }    // demo1() <==> this.demo1(); <==> window.demo1()    demo1(); // window// demo2    var demo2 = {        retThis: function () {            console.log(this);        }    }    demo2.retThis(); // demo2 = {...}// call / apply改变this    demo1.call(demo2);  // demo2 = {}    demo2.retThis.call(window); // window
原创粉丝点击