• js面向对象


    JavaScript 中的每个对象都是 Object 对象的实例且继承它所有的属性和方法。

    自定义对象

    JavaScript是一种基于原型的语言,它没类的声明语句,比如C+ +或Java中用的。这有时会对习惯使用有类申明语句语言的程序员产生困扰。相反,JavaScript可用方法作类。定义一个类跟定义一个函数一样简单。在下面的例子中,我们定义了一个新类Person。

    function Person() { } 
    // 或
    var Person = function(){ }

    对象(类的实例)

    我们使用 new obj 创建对象 obj 的新实例, 将结果(obj 类型)赋值给一个变量方便稍后调用。

    在下面的示例中,我们定义了一个名为Person的类,然后我们创建了两个Person的实例(person1 and person2).

    function Person() { }
    var person1 = new Person();
    var person2 = new Person();
    注意:有一种新增的创建未初始化实例的实例化方法,请参考 Object.create 。

    构造器

    在实例化时构造器被调用 (也就是对象实例被创建时)。构造器是对象中的一个方法。 在JavaScript,中函数就可以作为构造器使用,因此不需要特别地定义一个构造器方法. 每个声明的函数都可以在实例化后被调用执行

    构造器常用于给对象的属性赋值或者为调用函数做准备。 在本文的后面描述了类中方法既可以在定义时添加,也可以在使用前添加。

    在下面的示例中, Person类实例化时构造器调用一个 alert函数。

    function Person() {
      alert('Person instantiated');
    }
    
    var person1 = new Person();
    var person2 = new Person();

    属性 (对象属性)

    属性就是 类中包含的变量;每一个对象实例有若干个属性. 为了正确的继承,属性应该被定义在类的原型属性 (函数)中。

    可以使用 关键字 this调用类中的属性, this是对当前对象的引用。 从外部存取(读/写)其属性的语法是: InstanceName.Property; 这与C++,Java或者许多其他语言中的语法是一样的 (在类中语法 this.Property 常用于set和get属性值)

    在下面的示例中,我们为定义Person类定义了一个属性 firstName 并在实例化时赋初值。

    function Person(firstName) {
      this.firstName = firstName;
      alert('Person instantiated');
    }
    
    var person1 = new Person('Alice');
    var person2 = new Person('Bob');
    
    // Show the firstName properties of the objects
    alert('person1 is ' + person1.firstName); // alerts "person1 is Alice"
    alert('person2 is ' + person2.firstName); // alerts "person2 is Bob"

    方法(对象属性)

    方法与属性很相似, 不同的是:一个是函数,另一个可以被定义为函数。 调用方法很像存取一个属性,  不同的是add () 在方法名后面很可能带着参数. 为定义一个方法, 需要将一个函数赋值给类的 prototype 属性; 这个赋值给函数的名称就是用来给对象在外部调用它使用的。

    在下面的示例中,我们给Person类定义了方法 sayHello(),并调用了它.

    function Person(firstName) {
      this.firstName = firstName;
    }
    
    Person.prototype.sayHello = function() {
      alert("Hello, I'm " + this.firstName);
    };
    
    var person1 = new Person("Alice");
    var person2 = new Person("Bob");
    
    // call the Person sayHello method.
    person1.sayHello(); // alerts "Hello, I'm Alice"
    person2.sayHello(); // alerts "Hello, I'm Bob"

    在JavaScript中方法通常是一个绑定到对象中的普通函数, 这意味着方法可以在其所在context之外被调用。 思考下面示例中的代码:

    function Person(firstName) {
      this.firstName = firstName;
    }
    
    Person.prototype.sayHello = function() {
      alert("Hello, I'm " + this.firstName);
    };
    
    var person1 = new Person("Alice");
    var person2 = new Person("Bob");
    var helloFunction = person1.sayHello;
    
    person1.sayHello();                                 // alerts "Hello, I'm Alice"
    person2.sayHello();                                 // alerts "Hello, I'm Bob"
    helloFunction();                                    // alerts "Hello, I'm undefined" (or fails
                                                        // with a TypeError in strict mode)
    console.log(helloFunction === person1.sayHello);          // logs true
    console.log(helloFunction === Person.prototype.sayHello); // logs true
    helloFunction.call(person1);                        // logs "Hello, I'm Alice"

    如上例所示, 所有指向sayHello函数的引用 ,包括 person1Person.prototype, 和 helloFunction 等, 均引用了相同的函数.

    在调用函数的过程中,this的值取决于我们怎么样调用函数.  在通常情况下,我们通过一个表达式person1.sayHello()来调用函数:即从一个对象的属性中得到所调用的函数。此时this被设置为我们取得函数的对象(即person1)。这就是为什么person1.sayHello() 使用了姓名“Alice”而person2.sayHello()使用了姓名“bob”的原因。 

    然而我们使用不同的调用方法时, this的值也就不同了。当从变量 helloFunction()中调用的时候, this就被设置成了全局对象 (在浏览器中即window)。由于该对象 (非常可能地) 没有firstName 属性, 我们得到的结果便是"Hello, I'm undefined". (这是松散模式下的结果, 在 严格模式中,结果将不同(此时会产生一个error)。 但是为了避免混淆,我们在这里不涉及细节) 。另外,我们可以像上例末尾那样,使用Function#call (或者Function#apply)显式的设置this的值。

    更多有关信息请参考 Function#call and Function#apply

    继承

    创建一个或多个类的专门版本类方式称为继承(Javascript只支持单继承)。 创建的专门版本的类通常叫做子类,另外的类通常叫做父类。 在Javascript中,继承通过赋予子类一个父类的实例并专门化子类来实现。在现代浏览器中你可以使用 Object.create 实现继承.

    JavaScript 并不检测子类的 prototype.constructor (见 Object.prototype), 所以我们必须手动申明它.

    在下面的例子中, 我们定义了 Student类作为 Person类的子类. 之后我们重定义了sayHello() 方法并添加了 sayGoodBye() 方法.

    // 定义Person构造器
    function Person(firstName) {
      this.firstName = firstName;
    }
    
    // 在Person.prototype中加入方法
    Person.prototype.walk = function(){
      alert("I am walking!");
    };
    Person.prototype.sayHello = function(){
      alert("Hello, I'm " + this.firstName);
    };
    
    // 定义Student构造器
    function Student(firstName, subject) {
      // 调用父类构造器, 确保(使用Function#call)"this" 在调用过程中设置正确
      Person.call(this, firstName);
    
      // 初始化Student类特有属性
      this.subject = subject;
    };
    
    // 建立一个由Person.prototype继承而来的Student.prototype对象.
    // 注意: 常见的错误是使用 "new Person()"来建立Student.prototype.
    // 这样做的错误之处有很多, 最重要的一点是我们在实例化时
    // 不能赋予Person类任何的FirstName参数
    // 调用Person的正确位置如下,我们从Student中来调用它
    Student.prototype = Object.create(Person.prototype); // See note below
    
    // 设置"constructor" 属性指向Student
    Student.prototype.constructor = Student;
    
    // 更换"sayHello" 方法
    Student.prototype.sayHello = function(){
      console.log("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + ".");
    };
    
    // 加入"sayGoodBye" 方法
    Student.prototype.sayGoodBye = function(){
      console.log("Goodbye!");
    };
    
    // 测试实例:
    var student1 = new Student("Janet", "Applied Physics");
    student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
    student1.walk();       // "I am walking!"
    student1.sayGoodBye(); // "Goodbye!"
    
    // Check that instanceof works correctly
    console.log(student1 instanceof Person);  // true 
    console.log(student1 instanceof Student); // true

    对于“Student.prototype = Object.create(Person.prototype);”这一行,在不支持 Object.create方法的老JavaScript引擎中,可以使用一个"polyfill"(又名"shim",查看文章链接),或者使用一个function来获得相同的返回值,就像下面:

    function createObject(proto) {
        function ctor() { }
        ctor.prototype = proto;
        return new ctor();
    }
    
    // Usage:
    Student.prototype = createObject(Person.prototype);
    更多相关信息请参考 Object.create,连接中还有一个老JavaScript引擎的兼容方案(shim)。

    封装

    在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做封装,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。

    抽象

    抽象是允许模拟工作问题中通用部分的一种机制。这可以通过继承(具体化)或组合来实现。
    JavaScript通过继承实现具体化,通过让类的实例是其他对象的属性值来实现组合。

    JavaScript Function 类继承自Object类(这是典型的具体化) 。Function.prototype的属性是一个Object实例(这是典型的组合)。

    var foo = function(){};
    console.log( 'foo is a Function: ' + (foo instanceof Function) );                  // logs "foo is a Function: true"
    console.log( 'foo.prototype is an Object: ' + (foo.prototype instanceof Object) ); // logs "foo.prototype is an Object: true"

    多态

    就像所有定义在原型属性内部的方法和属性一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。

  • 相关阅读:
    C# 面向对象系列笔记(三)
    C# 面向对象系列笔记(二)
    分享一下: C# 面向对象系列笔记(一) ,希望对大家有所帮助
    新人报到
    VUE+ELEMENT-UI的后台项目封装组件--查询form的封装
    vue+element-ui的后台项目封装组件--面包屑的封装
    数组对象循环格式化时间撮的转换
    VUE+ELEMENT-UI的后台项目封装组件--table的封装
    css的样式问题
    vue项目兼容es6语法跟IE浏览器
  • 原文地址:https://www.cnblogs.com/zhangyu0217----/p/7070552.html
Copyright © 2020-2023  润新知