JavaScript
大约 3 分钟
JavaScript
目录
对象和类
基于类 vs 基于对象
对于C++程序员,JavaScript最难的就是它的对象模型
- 基于对象的面向对象语言(object-based):JavaScript
- 基于 类 的面向对象语言:C++、C#、Java、Simula、Smalltalk
基于对象的面向对象语言,一些具体体现
- 对象本质上是一个属性集,属性随时可以被添加、删除、修改
- 对于C++和Java开发者来说,一个普遍的错误就是在访问对象属性时忘记使用this关键字
- typeof 与 instanceof
var shape = new Shape(10,20);
中,如果在shape变量使用typeof操作符
,则数据类型是Object而不是Shape- 如果想确定Shape构造函数是否创建了对象,可以使用
instanceof操作符
:shape instanceof Shape;
返回true
- 允许任何函数作为构造函数,构造函数也可以作为普通函数得到调用
- ECMAScript中,函数被看作一等公民(Python也是,C/C++或Java不是)
- 对象实例与备份
- JavaScript
- 创建对象时每个实例都保存属性集(包括数据和函数的全部属性)的一个备份
- 但应用中对于里面的一些像函数的属性,往往只需要保存一次而不是保存在每个实例中
- 这时可以用
原型法
来达到这个目的:Shape.prototype.manhattanPos = function(){...}
- 原型(prototype)的使用详见 “原型与原型链” 一章
- C++(函数不是一等公民)
- 类的函数实现(.cpp)整个程序只保存一份
- 类的头文件(.h)保存在每个调用的cpp文件中
- 头文件定义的成员变量数据保存在每个实例中
- 头文件定义的静态成员变量整个程序只保存一份(枚举也是)
- 注意项
- 这种区别,与函数在JavaScript中是【一等公民】而在C++中不是有关(C++中函数与数据被 “分别对待”)
- js中原型法对只读属性(包括成员函数)有用,然而不能给共享变量赋新值,取而代之的是可以创建一个新的同名变量以覆盖原型中的原有属性
- JavaScript
- 继承
- 基于类中可以使用类继承
- ECMAScript基于对象中可以使用原型链达到类似的效果
- 可以使用instanceof操作遍历原型链,以判断哪个构造函数被调用了
举例(配合上面的具体体现来看)
function Shape(x, y){ // 构造函数
this.x = x
this.y = y
this.manhattanPos = function(){
return Math.abs(this.x) + Math.abs(this.y)
}
this.translate = function(dx, dy) {
this.x += dx
this.y += dy
}
}
var shape = new Shape(10, 20)
shape.translate(100, 100);
print(shape.x + "," + shape.y + "(" + shape.manhattanPos() + ")")
对象与类
(无需定义类可直接创建对象,JS中几乎“所有事物”都是对象)
var person=new Object()
person.firstname="Bill"
var person2 = {
firstName:"Bill"
}
JavaScript
有点令人困惑,因为它是动态的,并且本身不提供一个class
实现
Class
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
而函数的原型链又类似于类继承一样的东西
上面这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型的
ES6:
class Person {
constructor(name, age) { // 构造器
this.name = name
this,age = age;
}
}
class Student extends Person { } // 继承