JavaScript(15):对象和prototype继承



一、JavaScript 对象定义

所有 JavaScript 值,除了原始值,都是对象。

JavaScript 原始值

原始值指的是没有属性或方法的值。原始数据类型指的是拥有原始值的数据。

JavaScript 定义了 5 种原始数据类型:

  • string
  • number
  • boolean
  • null
  • undefined

原始值是一成不变的(它们是硬编码的,因此不能改变)。

假设 x = 3.14,您能够改变 x 的值。但是您无法改变 3.14 的值。

JavaScript 对象

JavaScript 变量能够包含单个的值:

var person = "Bill Gates";

对象也是变量,但是对象能够包含很多值。值按照名称 : 值对的形式编写(名称和值以冒号分隔)。

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};

JavaScript 对象是命名值的集合。

JavaScript 对象是被称为属性和方法的命名值的容器。

二、创建 JavaScript 对象

通过 JavaScript,您能够定义和创建自己的对象。

有不同的方法来创建对象:

  • 定义和创建单个对象,使用对象文字。
  • 定义和创建单个对象,通过关键词 new。
  • 定义对象构造器,然后创建构造类型的对象。

在 ECMAScript 5 中,也可以通过函数 Object.create() 来创建对象。

1、使用对象字面量

这是创建对象最简答的方法。

使用对象文字,您可以在一条语句中定义和创建对象。

对象文字指的是花括号 {} 中的名称:值对(比如 age:62)。

下面的例子创建带有四个属性的新的 JavaScript 对象:

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};

空格和折行不重要。对象定义可横跨多行:

var person = {
    firstName:"Bill",
    lastName:"Gates",
    age:62,
    eyeColor:"blue"
};

2、使用 JavaScript 关键词 new

下面的例子也创建了带有四个属性的新的 JavaScript 对象:

var person = new Object();
person.firstName = "Bill";
person.lastName = "Gates";
person.age = 50;
person.eyeColor = "blue";

上面的两个例子结果是一样的。无需使用 new Object()。

出于简易性、可读性和执行速度的考虑,请使用第一种创建方法(对象文字方法)。

注意:对象是易变的:它们通过引用来寻址,而非值。

如果 person 是一个对象,下面的语句不会创建 person 的副本:

var x = person;  // 这不会创建 person 的副本。

对象 x 并非 person 的副本。它就是 person。x 和 person 是同一个对象。

对 x 的任何改变都将改变 person,因为 x 和 person 是相同的对象。

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"}
 
var x = person;
x.age = 10;           // 这将同时改变 both x.age 和 person.age

注释:JavaScript 变量不是易变的。只有 JavaScript 对象如此。

3、使用JavaScript函数定义一个类型

function Aclass()
{
    this.Property = 1;
    this.Method = function()
    {
        alert(1);
    }
}
var obj = new Aclass();
alert(obj.Property);
obj.Method();

这个例子演示了通常的在JavaScript中定义一个类型的方法

三、JavaScript 对象属性

属性指的是与 JavaScript 对象相关的值。

属性是任何 JavaScript 对象最重要的部分。

JavaScript 对象是无序属性的集合。

属性通常可以被修改、添加和删除,但是某些属性是只读的。

1、访问 JavaScript 属性

访问对象属性的语法是:

bjectName.property           // person.age

或者:

objectName["property"]       // person["age"]

表达式必须计算为属性名。

person.firstname + " is " + person.age + " years old.";
person["firstname"] + " is " + person["age"] + " years old.";

2、JavaScript for...in 循环

JavaScript for...in 语句遍历对象的属性。

for...in 循环中的代码块会为每个属性执行一次。

循环对象的属性:

var person = {fname:"Bill", lname:"Gates", age:62}; 

for (x in person) {
    txt += person[x];
}

3、为实例对象添加或改变属性

为已有的对象添加新属性很简单:

myFather.nationality = "English";

新属性被添加到 myFather。不是 myMother,也不是任何其他 person 对象。

您不能使用预留词作为属性名(或方法名)。请使用 JavaScript 命名规则。

4、删除属性

delete 关键词从对象中删除属性:

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};
delete person.age;   // 或 delete person["age"];

delete 关键词会同时删除属性的值和属性本身。

删除完成后,属性在被添加回来之前是无法使用的。

delete 操作符被设计用于对象属性。它对变量或函数没有影响。

delete 操作符不应被用于预定义的 JavaScript 对象属性。这样做会使应用程序崩溃。

四、JavaScript 对象方法

JavaScript 方法是能够在对象上执行的动作。

JavaScript 方法是包含函数定义的属性。

1、this 关键词

在 JavaScript 中,被称为 this 的事物,指的是拥有该 JavaScript 代码的对象。

this 的值,在函数中使用时,是“拥有”该函数的对象。

请注意 this 并非变量。它是关键词。您无法改变 this 的值。

2、访问对象方法

请使用如下语法创建对象方法:

methodName : function() { 代码行 }

请通过如下语法来访问对象方法:

objectName.methodName()

您通常会把 fullName() 描述为 person 对象的方法,把 fullName 描述为属性。

fullName 属性在被通过 () 调用后会以函数形式执行。

此例访问 person 对象的 fullName() 方法

name = person.fullName();

如果您访问 fullName 属性时没有使用 (),则将返回函数定义

name = person.fullName;

3、为实例对象添加或改变方法

为已有的对象添加新方法很简单,新方法被添加到 myFather。不是 myMother,也不是任何其他 person 对象。

myFather.name = function () {
    return this.firstName + " " + this.lastName;
};

改变实例对象的已有属性和方法。

function Aclass()
{
    this.Property = 1;
    this.Method = function()
    {
        alert(1);
    }
}
var obj = new Aclass();
obj.Property = 2;
obj.Method = function()
{
    alert(2);
}
alert(obj.Property);
obj.Method();

五、JavaScript 访问器(Getter 和 Setter)

ECMAScript 5 (2009) 引入了 Getter 和 Setter。

Getter 和 Setter 允许您定义对象访问器(被计算的属性)。

1、JavaScript Getter(get 关键词)

本例使用 lang 属性来获取 language 属性的值。

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "en",
  get lang() {
    return this.language;
  }
};

// 使用 getter 来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.lang;

2、JavaScript Setter(set 关键词)

本例使用 lang 属性来设置 language 属性的值。

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "",
  set lang(lang) {
    this.language = lang;
  }
};

// 使用 setter 来设置对象属性:
person.lang = "en";

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.language;

3、为什么使用 Getter 和 Setter?

  • 它提供了更简洁的语法
  • 它允许属性和方法的语法相同
  • 它可以确保更好的数据质量
  • 有利于后台工作

一个计数器实例

var obj = {
  counter : 0,
  get reset() {
    this.counter = 0;
  },
  get increment() {
    this.counter++;
  },
  get decrement() {
    this.counter--;
  },
  set add(value) {
    this.counter += value;
  },
  set subtract(value) {
    this.counter -= value;
  }
};

// 操作计数器:
obj.reset;
obj.add = 5;
obj.subtract = 1;
obj.increment;
obj.decrement;
Object.defineProperty()

4、Object.defineProperty() 方法也可用于添加 Getter 和 Setter:

// 定义对象
var obj = {counter : 0};

// 定义 setters
Object.defineProperty(obj, "reset", {
  get : function () {this.counter = 0;}
});
Object.defineProperty(obj, "increment", {
  get : function () {this.counter++;}
});
Object.defineProperty(obj, "decrement", {
  get : function () {this.counter--;}
});
Object.defineProperty(obj, "add", {
  set : function (value) {this.counter += value;}
});
Object.defineProperty(obj, "subtract", {
  set : function (value) {this.counter -= value;}
});

// 操作计数器:
obj.reset;
obj.add = 5;
obj.subtract = 1;
obj.increment;
obj.decrement;

六、JavaScript 对象构造器(构造函数)

创建一种“对象类型”的方法,是使用对象构造器函数

在上面的例子中,函数 Person() 就是对象构造器函数

通过 new 关键词调用构造器函数可以创建相同类型的对象:

var myFather = new Person("Bill", "Gates", 62, "blue");
var myMother = new Person("Steve", "Jobs", 56, "green");

1、为构造函数添加属性

如需向构造器添加一个新属性,您必须添加到构造器函数:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.nationality = "English";
}

这样对象属性就可以拥有默认值。

2、为构造函数添加方法

必须在构造器函数内部向一个对象添加方法:

function Person(firstName, lastName, age, eyeColor) {
    this.firstName = firstName;  
    this.lastName = lastName;
    this.age = age;
    this.eyeColor = eyeColor;
    this.changeName = function (name) {
        this.lastName = name;
    };
}

changeName() 函数把 name 赋值给 person 的 lastName 属性。

myMother.changeName("Jobs");

通过用 myMother 替代 this,JavaScript 可以获知目前处理的哪个 person。

3、内建 JavaScript 构造函数

JavaScript 提供用于原始对象的构造器:

var x1 = new Object();    // 一个新的 Object 对象
var x2 = new String();    // 一个新的 String 对象
var x3 = new Number();    // 一个新的 Number 对象
var x4 = new Boolean();   // 一个新的 Boolean 对象
var x5 = new Array();     // 一个新的 Array 对象
var x6 = new RegExp();    // 一个新的 RegExp 对象
var x7 = new Function();  // 一个新的 Function 对象
var x8 = new Date();      // 一个新的 Date 对象

Math() 对象不再此列。Math 是全局对象。new 关键词不可用于 Math。

正如以上所见,JavaScript 提供原始数据类型字符串、数字和布尔的对象版本。但是并无理由创建复杂的对象。原始值快得多!

  • 请使用对象字面量 {} 代替 new Object()。
  • 请使用字符串字面量 "" 代替 new String()。
  • 请使用数值字面量代替 Number()。
  • 请使用布尔字面量代替 new Boolean()。
  • 请使用数组字面量 [] 代替 new Array()。
  • 请使用模式字面量代替 new RexExp()。
  • 请使用函数表达式 () {} 代替 new Function()。
var x1 = {};            // 新对象
var x2 = "";            // 新的原始字符串
var x3 = 0;             // 新的原始数值
var x4 = false;         // 新的原始逻辑值
var x5 = [];            // 新的数组对象
var x6 = /()/           // 新的正则表达式对象
var x7 = function(){};  // 新的函数对象

七、JavaScript 对象原型:prototype

构造函数创建的属性是实例私有的,原型创建的属性和方法是实例共享的。

1、在外部使用prototype为类型增加动态属性和方法

可以在外部使用prototype为自定义的类型添加属性和方法。 但是在外部不能通过prototype改变已有的自定义类型的属性或方法

function Aclass()
{
    this.Property = 1;
    this.Method = function()
    {
        alert(1);
    }
}

Aclass.prototype.Property2 = 2;
Aclass.prototype.Method2 = function()
{
    alert(2);
}
var obj = new Aclass();
alert(obj.Property2);
obj.Method2();

2、类型的继承(原型链)

所有 JavaScript 对象都从原型继承属性和方法。

日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。Person 对象继承自 Person.prototype。Object.prototype 位于原型继承链的顶端,日期对象、数组对象和 Person 对象都继承自 Object.prototype。

这个例子说明了一个类型如何从另一个类型继承。

function AClass()
{
    this.Property = 1;
    this.Method = function()
    {
        alert(1);
    }
}
function AClass2()
{
    this.Property2 = 2;
    this.Method2 = function()
    {
        alert(2);
    }
}
AClass2.prototype = new AClass();
var obj = new AClass2();
alert(obj.Property);
obj.Method();
alert(obj.Property2);
obj.Method2();

3、子类如何重写父类的属性或方法

这个例子说明了子类如何重写父类的属性或方法。

function AClass()
 {
     this.Property = 1;
     this.Method = function()
     {
         alert(1);
     }
 }
 function AClass2()
 {
     this.Property2 = 2;
     this.Method2 = function()
     {
         alert(2);
     }
 }
 AClass2.prototype = new AClass();
 AClass2.prototype.Property = 3;
 AClass2.prototype.Method = function()
 {
     alert(4);
 }
 var obj = new AClass2();
 alert(obj.Property);
 obj.Method();

4、原型式继承

这种方法并没有使用严格意义的构造函数,而是借助原型可以基于已有的对象创建新对象,同时还不用创建自定义类型来达到这个目的。

以下代码是封装在object函数当中的,在使用的时候直接使用object()

function object (o)//这个o相当于父对象实例
{
        function F(){}//这个F相当子对象
        F.prototype=o;//继承
        return new F();//实例化传出
}

var box = { //字面量对象
    name: 'Lee',
    arr: ['哥哥', '妹妹', '姐姐']
};

var box1 = object (box); //传递
alert(box1.name);

box1.arr.push('父母');
var box2 = obj(box); //传递
alert(box2.name);

但是ECMAscript5定义了Object.create()方法,可以直接使用,他有俩个参数,下面来一个例子:

var person = {
    name: "Tom",
    age: 23,
    job: "web前端工程师"
};

var anotherPerson = Object.create(person, {
    name: {
        value: "Mike"
    }
});
alert(anotherPerson.name);

在上面这个例子中,create的第二参数是一个对象,其中的属性如果和person重名,则会覆盖person的属性。

5、借用构造函数实现继承

function SuperType() {
    this.colors = ["red", "blue", "green"];
}

function SubType() {
    SuperType.call(this) //或者apply()
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);
var instance2 = new SubType();
alert(instance2.colors);

借用构造函数也可以通过子对象向父对象传递参数

function SuperType(name) {
    this.name = name
}

function SubType() {
    SuperType.call(this, "Tom") //或者apply()
}
var instance1 = new SubType();
alert(instance1.name);

八、JavaScript ES5 对象方法

1、新的对象方法

Object.defineProperty(object, property, descriptor)

// 添加或更改多个对象属性
Object.defineProperties(object, descriptors)

// 访问属性
Object.getOwnPropertyDescriptor(object, property)

// 以数组返回所有属性
Object.getOwnPropertyNames(object)

// 以数组返回所有可枚举的属性
Object.keys(object)

// 访问原型
Object.getPrototypeOf(object)

// 阻止向对象添加属性
Object.preventExtensions(object)

// 如果可将属性添加到对象,则返回 true
Object.isExtensible(object)

// 防止更改对象属性(而不是值)
Object.seal(object)

// 如果对象被密封,则返回 true
Object.isSealed(object)

// 防止对对象进行任何更改
Object.freeze(object)

// 如果对象被冻结,则返回 true
Object.isFrozen(object)

1、添加或更改属性值

Object.defineProperty(object, property, {value : value})

更改属性值:

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "EN" 
};

// 更改属性
Object.defineProperty(person, "language", {value : "ZH"});

向对象添加新属性:

// 创建对象
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "EN"
};

// 添加属性
Object.defineProperty(person, "year", {value:"2008"});

ES5 允许更改以下属性元数据:

writable : true      // 属性值可修改
enumerable : true    // 属性可枚举
configurable : true  // 属性可重新配置
writable : false     // 属性值不可修改
enumerable : false   // 属性不可枚举
configurable : false // 属性不可重新配置

ES5 允许更改 getter 和 setter:

// 定义 getter
get: function() { return language }
// 定义 setter
set: function(value) { language = value }

此例使语言为只读:

Object.defineProperty(person, "language", {writable:false});

此例使语言不可枚举:

Object.defineProperty(person, "language", {enumerable:false});

添加 Getter 和 Setter

Object.defineProperty() 方法也可以用于添加 Getter 和 Setter:

// 创建对象
var person = {firstName:"Bill", lastName:"Gates"};

// 定义 getter
Object.defineProperty(person, "fullName", {
  get : function () {return this.firstName + " " + this.lastName;}
});

2、列出所有属性

此例列出对象的所有属性:

var person = {
  firstName: "Bill",
  lastName : "Gates"
  language : "EN" 
};

Object.defineProperty(person, "language", {enumerable:false});
Object.getOwnPropertyNames(person);  // 返回属性数组

3、列出可枚举的属性

此例只列出对象的所有可枚举属性:

var person = {
  firstName: "Bill",
  lastName : "Gates"
  language : "EN" 
};

Object.defineProperty(person, "language", {enumerable:false});
Object.keys(person);  // 返回可枚举属性的数组

posted on 2019-03-19 16:52  springsnow  阅读(249)  评论(0编辑  收藏  举报

导航