JavaScript面向对象简介(2)

电脑杂谈  发布时间:2020-07-19 17:10:36  来源:网络整理

如上例所示,对sayHello函数的所有引用(包括person1,Person.prototype和helloFunction)都引用同一函数.

在调用函数的过程中,其值取决于我们如何调用函数. 在正常情况下,我们通过表达式person1.sayHello()调用函数: 即从对象的属性中获取被调用的函数. 这时,将其设置为我们获得的功能的对象(即person1). 这就是为什么person1.sayHello()使用名称“ Alice”而person2.sayHello()使用名称“ bob”的原因.

oop面向对象编程_java面向接口编程_oop面向对象编程

但是,当我们使用不同的调用方法时,此方法的值也不同. 从变量helloFunction()调用时,将其设置为全局对象(即浏览器中的窗口). 由于对象(很有可能)没有firstName属性,因此我们得到的结果是“你好,我不确定”. (这是松散模式下的结果,结果会有所不同(这时会产生错误). 但是为了避免混淆,在此不再赘述). 另外,我们可以使用Function#call(或Function#apply)显式设置this的值,如上例末所示.

有关更多信息,请参阅和

创建一个或多个类的特殊版本的方法称为继承(Javascript仅支持单一继承). 创建的类的特殊版本通常称为子类,其他类通常称为父类. 在Javascript中,继承是通过为子类提供父类的实例并专门化子类来实现的. 在现代浏览器中,您可以使用实现继承.

JavaScript无法检测到子类的prototype.constructor(请参见),因此我们必须手动对其进行声明.

在下面的示例中,我们将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);”行,在不支持方法的旧JavaScript引擎中,可以使用“ polyfill”(也称为“ shim”),请参见文章链接),或使用函数来获取相同的返回值,如下所示:

function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}
// Usage:
Student.prototype = createObject(Person.prototype);

有关更多信息,请参考链接,其中还有旧JavaScript引擎的兼容方案(填充程序).

在前面的示例中,尽管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"

与原型属性中定义的所有方法和属性一样,不同的类可以使用相同的名称来定义方法;方法对它们所在的类起作用. 只有当两个类都不具有父子关系时(在继承链中,一个类不会从其他类继承),这才成立.

本文显示的面向对象编程技术不是实现它的唯一方法. JavaScript中的面向对象的实现非常灵活.

类似地,本文中显示的技术没有使用任何语言技巧,也没有模仿其他语言中对象理论的实现.

JavaScript中还有其他更高级的面向对象技术,但这不在本文讨论范围之内.

维基百科. 面向对象程序设计,Wikipedia. “封装(面向对象的程序设计)”


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-286113-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...