前端基础进阶(九):详解面向对象、构造函数

来源:http://www.sh-fengwen.com 作者: 营养排行 人气:91 发布时间:2019-12-15
摘要:前端基础进阶(9):详解面向对象、构造函数、原型与原型链 2017/04/02 · JavaScript· 1 评论 ·原型,原型链,构造函数,面向对象 原文出处: 波同学    . 如果要我总结一下学习前端以来我

前端基础进阶(9):详解面向对象、构造函数、原型与原型链

2017/04/02 · JavaScript · 1 评论 · 原型, 原型链, 构造函数, 面向对象

原文出处: 波同学   

图片 1

.

如果要我总结一下学习前端以来我遇到了哪些瓶颈,那么面向对象一定是第一个毫不犹豫想到的。尽管我现在对于面向对象有了一些的了解,但是当初的那种似懂非懂的痛苦,依然历历在目。

为了帮助大家能够更加直观的学习和了解面向对象,我会用尽量简单易懂的描述来展示面向对象的相关知识。并且也准备了一些实用的例子帮助大家更加快速的掌握面向对象的真谛。

  • jQuery的面向对象实现
  • 封装拖拽
  • 简易版运动框架封装

这可能会花一点时间,但是却值得期待。所以如果有兴趣的朋友可以来简书和公众号关注我。

而这篇文章主要来聊一聊关于面向对象的一些重要的基本功。

由于某些原因,文章已经删除,打算迁移到别处,目前正在寻找更合适的平台。

一、对象的定义

在ECMAScript-262中,对象被定义为“无序属性的集合,其属性可以包含基本值,对象或者函数”

也就是说,在JavaScript中,对象无非就是由一些列无序的key-value对组成。其中value可以是基本值,对象或者函数。

// 这里的person就是一个对象 var person = { name: 'Tom', age: 18, getName: function() {}, parent: {} }

1
2
3
4
5
6
7
// 这里的person就是一个对象
var person = {
    name: 'Tom',
    age: 18,
    getName: function() {},
    parent: {}
}

创建对象

我们可以通过new的方式创建一个对象。

var obj = new Object();

1
var obj = new Object();

也可以通过对象字面量的形式创建一个简单的对象。

var obj = {};

1
var obj = {};

当我们想要给我们创建的简单对象添加方法时,可以这样表示。

// 可以这样 var person = {}; person.name = "TOM"; person.getName = function() { return this.name; } // 也可以这样 var person = { name: "TOM", getName: function() { return this.name; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 可以这样
var person = {};
person.name = "TOM";
person.getName = function() {
    return this.name;
}
 
// 也可以这样
var person = {
    name: "TOM",
    getName: function() {
        return this.name;
    }
}

访问对象的属性和方法

假如我们有一个简单的对象如下:

var person = { name: 'TOM', age: '20', getName: function() { return this.name } }

1
2
3
4
5
6
7
var person = {
    name: 'TOM',
    age: '20',
    getName: function() {
        return this.name
    }
}

当我们想要访问他的name属性时,可以用如下两种方式访问。

person.name // 或者 person['name']

1
2
3
4
person.name
 
// 或者
person['name']

如果我们想要访问的属性名是一个变量时,常常会使用第二种方式。例如我们要同时访问person的name与age,可以这样写:

['name', 'age'].forEach(function(item) { console.log(person[item]); })

1
2
3
['name', 'age'].forEach(function(item) {
    console.log(person[item]);
})

这种方式一定要重视,记住它以后在我们处理复杂数据的时候会有很大的帮助。

请大家关注我的新公众号ar_indus,随后我会在公众号里推送新的博客地址。

二、工厂模式

使用上面的方式创建对象很简单,但是在很多时候并不能满足我们的需求。就以person对象为例。假如我们在实际开发中,不仅仅需要一个名字叫做TOM的person对象,同时还需要另外一个名为Jake的person对象,虽然他们有很多相似之处,但是我们不得不重复写两次。

var perTom = { name: 'TOM', age: 20, getName: function() { return this.name } }; var perJake = { name: 'Jake', age: 22, getName: function() { return this.name } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var perTom = {
    name: 'TOM',
    age: 20,
    getName: function() {
        return this.name
    }
};
 
var perJake = {
    name: 'Jake',
    age: 22,
    getName: function() {
        return this.name
    }
}

很显然这并不是合理的方式,当相似对象太多时,大家都会崩溃掉。

我们可以使用工厂模式的方式解决这个问题。顾名思义,工厂模式就是我们提供一个模子,然后通过这个模子复制出我们需要的对象。我们需要多少个,就复制多少个。

var createPerson = function(name, age) { // 声明一个中间对象,该对象就是工厂模式的模子 var o = new Object(); // 依次添加我们需要的属性与方法 o.name = name; o.age = age; o.getName = function() { return this.name; } return o; } // 创建两个实例 var perTom = createPerson('TOM', 20); var PerJake = createPerson('Jake', 22);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var createPerson = function(name, age) {
 
    // 声明一个中间对象,该对象就是工厂模式的模子
    var o = new Object();
 
    // 依次添加我们需要的属性与方法
    o.name = name;
    o.age = age;
    o.getName = function() {
        return this.name;
    }
 
    return o;
}
 
// 创建两个实例
var perTom = createPerson('TOM', 20);
var PerJake = createPerson('Jake', 22);

相信上面的代码并不难理解,也不用把工厂模式看得太过高大上。很显然,工厂模式帮助我们解决了重复代码上的麻烦,让我们可以写很少的代码,就能够创建很多个person对象。但是这里还有两个麻烦,需要我们注意。

第一个麻烦就是这样处理,我们没有办法识别对象实例的类型。使用instanceof可以识别对象的类型,如下例子:

var obj = {}; var foo = function() {} console.log(obj instanceof Object); // true console.log(foo instanceof Function); // true

1
2
3
4
5
var obj = {};
var foo = function() {}
 
console.log(obj instanceof Object);  // true
console.log(foo instanceof Function); // true

因此在工厂模式的基础上,我们需要使用构造函数的方式来解决这个麻烦。

后续计划的《react进阶系列》文章也会在新公众号中推送。

三、构造函数

在JavaScript中,new关键字可以让一个函数变得与众不同。通过下面的例子,我们来一探new关键字的神奇之处。

function demo() { console.log(this); } demo(); // window new demo(); // demo

1
2
3
4
5
6
function demo() {
    console.log(this);
}
 
demo();  // window
new demo();  // demo

为了能够直观的感受他们不同,建议大家动手实践观察一下。很显然,使用new之后,函数内部发生了一些变化,让this指向改变。那么new关键字到底做了什么事情呢。嗯,其实我之前在文章里用文字大概表达了一下new到底干了什么,但是一些同学好奇心很足,总期望用代码实现一下,我就大概以我的理解来表达一下吧。

// 先一本正经的创建一个构造函数,其实该函数与普通函数并无区别 var Person = function(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; } } // 将构造函数以参数形式传入 function New(func) { // 声明一个中间对象,该对象为最终返回的实例 var res = {}; if (func.prototype !== null) { // 将实例的原型指向构造函数的原型 res.__proto__ = func.prototype; } // ret为构造函数执行的结果,这里通过apply,将构造函数内部的this指向修改为指向res,即为实例对象 var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); // 当我们在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象 if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return ret; } // 如果没有明确指定返回对象,则默认返回res,这个res就是实例对象 return res; } // 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res var p1 = New(Person, 'tom', 20); console.log(p1.getName()); // 当然,这里也可以判断出实例的类型了 console.log(p1 instanceof Person); // true

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
31
32
33
34
35
36
37
38
// 先一本正经的创建一个构造函数,其实该函数与普通函数并无区别
var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        return this.name;
    }
}
 
// 将构造函数以参数形式传入
function New(func) {
 
    // 声明一个中间对象,该对象为最终返回的实例
    var res = {};
    if (func.prototype !== null) {
 
        // 将实例的原型指向构造函数的原型
        res.__proto__ = func.prototype;
    }
 
    // ret为构造函数执行的结果,这里通过apply,将构造函数内部的this指向修改为指向res,即为实例对象
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
 
    // 当我们在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
 
    // 如果没有明确指定返回对象,则默认返回res,这个res就是实例对象
    return res;
}
 
// 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res
var p1 = New(Person, 'tom', 20);
console.log(p1.getName());
 
// 当然,这里也可以判断出实例的类型了
console.log(p1 instanceof Person); // true

JavaScript内部再通过其他的一些特殊处理,将var p1 = New(Person, 'tom', 20); 等效于var p1 = new Person('tom', 20);。就是我们认识的new关键字了。具体怎么处理的,我也不知道,别刨根问底了,一直回答下去太难 – -!

老实讲,你可能很难在其他地方看到有如此明确的告诉你new关键字到底对构造函数干了什么的文章了。理解了这段代码,你对JavaScript的理解又比别人深刻了一分,所以,一本正经厚颜无耻求个赞可好?

当然,很多朋友由于对于前面几篇文章的知识理解不够到位,会对new的实现表示非常困惑。但是老实讲,如果你读了我的前面几篇文章,一定会对这里new的实现有似曾相识的感觉。而且我这里已经尽力做了详细的注解,剩下的只能靠你自己了。

但是只要你花点时间,理解了他的原理,那么困扰了无数人的构造函数中this到底指向谁就变得非常简单了。

所以,为了能够判断实例与对象的关系,我们就使用构造函数来搞定。

var Person = function(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; } } var p1 = new Person('Ness', 20); console.log(p1.getName()); // Ness console.log(p1 instanceof Person); // true

1
2
3
4
5
6
7
8
9
10
11
12
var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        return this.name;
    }
}
 
var p1 = new Person('Ness', 20);
console.log(p1.getName());  // Ness
 
console.log(p1 instanceof Person); // true

关于构造函数,如果你暂时不能够理解new的具体实现,就先记住下面这几个结论吧。

  • 与普通函数相比,构造函数并没有任何特别的地方,首字母大写只是我们约定的小规定,用于区分普通函数;
  • new关键字让构造函数具有了与普通函数不同的许多特点,而new的过程中,执行了如下过程:
    1. 声明一个中间对象;
    2. 将该中间对象的原型指向构造函数的原型;
    3. 将构造函数的this,指向该中间对象;
    4. 返回该中间对象,即返回实例对象。

公众号二维码

本文由美高梅游戏平台网站发布于 营养排行,转载请注明出处:前端基础进阶(九):详解面向对象、构造函数

关键词:

上一篇:JavaScript 创建对象的七种方式

下一篇:没有了

最火资讯