JavaScript学习笔记之对象及继承

对象属性

  ES5中有两种属性,数据属性和访问器属性。
  数据属性包括[[writable]](能否修改属性的值)、[[value]]等等;
  访问器属性包括[[Configurable]](能否通过delete删除属性、能否修改属性的特性)、[[Enumerable]](能否通过for-in循环返回属性)、[[Get]]、[Set]]
  要修改属性则使用Object.defineProperty(),这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中描述符对象的属性必须是:configurable、enumerable、writable和value。如下面的代码

      
1
2
3
4
5
6
7
8
9
      
var person = {};
Object.defineProperty(person, "name", {
configurable: false,
value: "Nicholas"
});
alert(person.name); //"Nicholas"
delete person.name;
alert(person.name); //"Nicholas"

  也可以使用Object.defineProperties()定义多个属性

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      
var book = {};
Object.defineProperties(book,{
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if(newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});

创建对象

工厂模式

      
1
2
3
4
5
6
7
8
9
10
11
12
      
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

  抽象了出案件具体对象的过程,每次调用函数会返回一个对象

构造函数模式

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
      
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
alert(person1.constructor == Person);//true
alert(person1 instanceof Object);//true
alert(person1 instanceof Person);//true

  构造函数没有显性地创建对象;直接将属性和方法赋给了this对象;没有return语句。
  创建实例的步骤是这样的:创建一个新对象;将构造函数的作用于赋给新对象(this指向这个新对象);执行构造函数中的代码;返回新对象。
  我们也可以将构造函数当做函数:

      
1
2
3
4
5
6
7
      
Person("Greg", 27, "Doctor");
window.sayName(); //"Greg"
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName();

  而构造函数的主要问题就是,每个方法都要在每个实例上重新创建一遍,不同实例上的同名函数是不相等的。

原型对象

  原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。即不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
看下面的代码

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
      
function Person(){}
Person.prototype = {
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function(){
alert(this.name);
}
};
var Person1 = new Person();
var Person2 = new Person();
alert(person1.hasOwnProperty("name"));//false
alert("name" in Person1);//true
person1.name = "Greg";
alert(person1.name);//"Greg" ——来自实例
alert(hasPrototypeProperty(person, "name"));//false
alert(person1.hasOwnProperty("name"));//true
alert("name" in Person1);//true
alert(person2.name);//"Nicholas" ——来自原型
alert(person2.hasOwnProperty("name"));//false
alert("name" in Person1);//true
delete person1.name;
alert(person1.name);//"Nicholas" ——来自原型
alert(person1.hasOwnProperty("name"));//false
alert("name" in Person1);//true

  当然原型对象也有缺点:所有实例在默认情况下都取得相同的属性值,即共享性。这个问题尤其对于包含引用类型值的属性来说更为突出。
  所以,组合使用构造函数模式与原型模式是更好的选择。即在构造函数中定义实例属性,而所有实例共享的属性在原型中定义。

什么是原型链

  JavaScript主要是依靠原型链实现继承。
  什么是原型链?我们来看看构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。看下面的代码

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subProperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

  instance.getSuperValue()调用时会经历三个步骤:

  • 搜索实例;
  • 搜索SubType.prototype;
  • 搜索SuperType.prototype,最后一步才找到方法。

  而所有函数的默认原型都是Object的实例,所以完整的原型链如下图:

  即instance.__proto__(instance的原型)指向SubType.prototype,SubType.prototype.__proto__指向SuperType.prototype,而SuperType.prototype.__proto__指向Object.prototype,最后Object.prototype.__proto__指向null。
  果然对象搞到头还是空啊!(开个玩笑==)

原型链的问题

  原型链可以用来实现继承,但它也存在一些问题。
  最主要的问题就是在创建原型对象中提及的,包含引用类型值的原型属性会被所有实例共享。

借用构造函数

  鉴于上面的问题,我们可以通过使用apply()和call()在新创建的对象上执行构造函数。

      
1
2
3
4
5
6
7
8
9
10
11
12
13
      
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
SuperType.call(this);//继承SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

  实际上,我们在新创建的SubType实例的环境下调用了SuperType构造函数。这样,SubType的每个实例就都会有自己的colors属性的副本了。

  此外,还有组合继承,原型式继承,寄生式继承等。脑袋内存有限,这里不再作探究。
本文主要参考《JavaScript高级程序设计(第3版)》。

参考

《JavaScript高级程序设计(第3版)》

友情链接

前端重点知识整理(JavaScript)四:对象及继承

JavaScript学习笔记之对象及继承相关推荐

  1. JavaScript学习笔记:对象

    JavaScript学习笔记:对象 1.声明对象 (1)字面量对象 <!DOCTYPE html> <html lang="en"> <head> ...

  2. JavaScript学习笔记——BOM_window对象

    javascript浏览器对象模型-windwo对象 BOM Browser Object Model window对象 是BOM中所有对象的核心. 一.属性 1.(位置类型-获得浏览器的位置) IE ...

  3. Java学习笔记类对象多态继承(下)

    面向对象(下) 1.类的继承 一.什么是继承,有什么用? 继承:在现实世界当中也是存在的,例如:父亲很有钱,几子不用努力也很有钱 继承的作用: 基本作用:子类继承父类,代码可以得到复用.(这个不是重要 ...

  4. JavaScript学习笔记-JSON对象

    JSON 是一种用来序列化对象.数组.数值.字符串.布尔值和 null 的语法.它基于 JavaScript 语法,但是又有区别:一些 JavaScript 值不是 JSON,而某些 JSON 不是 ...

  5. JavaScript 学习笔记— —Date对象

    一.获取时间 function toTwo(n){return n<10 ? '0'+n :''+n;}function getTime(){var objDate=new Date(); // ...

  6. JavaScript学习笔记(四)---闭包、递归、柯里化函数、继承、深浅拷贝、设计模式

    JavaScript学习笔记(四)---闭包.递归.柯里化函数.继承.深浅拷贝.设计模式 1. 匿名函数的使用场景 2.自运行 3.闭包 3.1前提: 3.2闭包 4.函数对象的三种定义方式 5.th ...

  7. JavaScript学习笔记05【高级——DOM对象】

    w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...

  8. JavaScript学习笔记04【高级——DOM和事件的简单学习、BOM对象】

    w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...

  9. JavaScript学习笔记02【基础——对象(Function、Array、Date、Math)】

    w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...

最新文章

  1. 读取串口数据_自定义串口通信的相关问题整理
  2. websocket 群/单聊 基础
  3. php访问nfs目录,PHP NFS的实现代码
  4. eeprom的wp 引脚_EEPROM
  5. BZOJ2154: Crash的数字表格 BZOJ2693: jzptab
  6. Oracle:使用ASM自动存储管理, 严重推荐
  7. (五)官方Neo4j 3.3.9 Java API例子
  8. 机器学习算法之 logistic、Softmax 回归
  9. Python缓存类实例
  10. 如何在一周内上线50个用户增长策略
  11. list接口中的常用方法例子
  12. 题解 LGOJ P4168 【[Violet]蒲公英】
  13. ide循环执行用例 selenium_Selenium Web自动化Page Object设计模式——循环执行测试用例...
  14. WPF中TextBlock文本换行与行间距
  15. 设计模式-第三篇之工厂方法和抽象工厂
  16. OC 内存管理之手动内存管理MRC
  17. python 字典排序成绩_原来python中dict()的高级用法可以这样实现!真是让我长了见识...
  18. vue---EleElement UI 表格导出功能
  19. linux谷歌浏览器总是崩溃,Ubuntu 18.04谷歌浏览器Chrome卡死的原因及解决
  20. Word文档里面如何给内容进行注释添加

热门文章

  1. 腾讯NLP算法岗实习面经
  2. 走进智慧社区感受触手可及的幸福
  3. 假设检验中错误的类型
  4. excel背景色怎么变成黑色了?
  5. Django blog项目《二十五》:项目优化《1》使用celery异步任务和定时任务
  6. 2023-5-8分享免费代理ip
  7. 俄罗斯科学家量子计算机,俄罗斯科学家提出颠覆性量子物理观点:整个宇宙都是量子-虎嗅网...
  8. elgamal签名java_ElGamal算法的数字签名
  9. 软件工程——增量模型
  10. c++输入密码进行隐藏并输出*,防止窥屏