前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES5面向对象基础

ES5面向对象基础

作者头像
kai666666
发布2020-10-17 23:31:52
6400
发布2020-10-17 23:31:52
举报
文章被收录于专栏:橙光笔记

面向对象的知识时JS中的一个比较重要的概念,我们今天学习一下ES5面向对象的基础内容。

一、 创建对象

1. 工厂模式

代码语言:javascript
复制
function createPerson(name){
    var o = new Object();
    o.name = name;
    o.sayName = function(){
        console.log(this.name);
    };    
    return o;
}

var person1 = createPerson("Orange");

缺点:无法辨别是一个对象。

2. JSON对象

代码语言:javascript
复制
var person1 = {
    name:"Orange",
    sayName:function (){
        console.log(this.name);
    }
};

优点:简单。 缺点:每次只能创建一个对象,代码无法复用。

3. 构造函数

代码语言:javascript
复制
function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name);
    };    
}

var person1 = new Person("Orange");

person1.sayName();   //"Orange"

优点:可以创建多个对象,可以辨别是对象。 下面我们主要讨论的也正是使用构造方法创建的对象。

二、 不使用new关键字会发生什么

不使用new的时候相当于时全局变量window调用该方法,this会绑定在全局变量上。由于没有返回值,结果是undefined。

代码语言:javascript
复制
function Person(name){
    this.name = name;// 不使用new时 非严格模式下绑定在全局变量window上了
}
var person1 = Person("Orange");// 方法的调用
console.log(person1);// undefined
三、 new一个对象的时候有返回值怎么办

如果返回的是一个对象,那么new出来的结果就是这个对象;如果返回的是非对象的,那么new返回的与没有return语句一样,是一个该类的实例对象。如果没有new的时候,就比如上面这种情况,那就是方法返回什么结果就是什么了。

代码语言:javascript
复制
function Person1(){
    this.name = "Person1";
    return {haha:"我是一个新的对象"};// 返回一个对象
}
function Person2(){
    this.name = "Person2";
    return 123;// 返回一个非对象
}
var person1 = new Person1();
var person2 = new Person2();
console.log(person1);// {haha: "我是一个新的对象"}
console.log(person2);// Person2 {name: "Person2"}

四、 成员方法

1. 给单个对象添加成员方法

代码语言:javascript
复制
function Person(){
}

var person1 = new Person();
person1.name = "Orange";
var person2 = new Person();
console.log(person1.name);// "Orange"
console.log(person2.name);// undefined

2. 给多个对象添加成员方法

代码语言:javascript
复制
function Person(name){
    this.name = name;//所有的对象公用的属性
    this.age = 20;//所有的对象公用的属性
}

var person1 = new Person("Orange");
var person2 = new Person("小明");
person1.age = 21;
console.log(person1.name);// "Orange"
console.log(person2.name);// "小明"
console.log(person1.age);// 21
console.log(person2.age);// 20

五、 私有变量

构造函数中var声明的变量是私有变量。

代码语言:javascript
复制
function Person(){
    var age = 21;//这里相当于私有变量
}

var person1 = new Person();
console.log(person1.age);// undefined

六、 静态方法

添加到构造函数上的方法是静态方法,添加到构造函数上的变量是静态变量。

代码语言:javascript
复制
function Person(name){
    this.name = name;
}

Person.age = 20;//静态变量
Person.name = "骗你的"; // 这条语句会忽略 因为name是一个特殊的属性 不能修改
Person.sayName = function (){//静态方法
    console.log("sayName:" + this.name);
};
var person = new Person("Orange");
console.log(person.name);// "Orange"
console.log(Person.name);// "Person" 这里是类的名称 哈哈
// console.log(person.name);// 这个会报错 静态属性属于类 而不是属于对象 
// person.sayName(); // 这个会报错 静态方法属于类 而不是属于对象
console.log(Person.age); // 20
Person.sayName();// sayName:Person

七、 原型

上面说过给多个对象添加成员方法,只要在构造函数中添加this.方法名 = 方法即可,但是这样会出现一个问题就是不同对象的方法是不同的,这样就会增大内存的开销。解决这个问题的办法就是把方法放在函数的外面,然后在函数内部去引用同一个函数。这样解决了这个问题,但是却失去了封装性。解决这个问题的最终办法就是——原型。

每一构造函数写完以后,引擎会加原型的委托,就比如上面的Person类(函数)定义完了以后,引擎会加:

代码语言:javascript
复制
Person.prototype = new Object();

从上面代码可以看出Person加了一个名叫prototype的静态变量,这个变量就是Person的原型。由于对象是无法访问静态变量的,所以浏览器给每一个对象又加了一个__proto__的属性也指向了这个原型。相当于引擎又执行了下面的代码:

代码语言:javascript
复制
person.__proto__ = Person.prototype;

我们这里总结一下:对象.__proto__属性构造函数.prototype属性 都指向了该类的原型。 下面我们把这剪不断理还乱的原型画一张图吧:

由上图可知,原型对象有一个constructor的属性指向了构造方法。也就是:

代码语言:javascript
复制
Person.prototype.constructor === Person;// true
person.__proto__.constructor === Person;// true

由上面Person.prototype = new Object();可知Person.prototype其实是Object的对象,既然是对象那么就有__proto__属性指向该对象的原型。也就是说:

代码语言:javascript
复制
Person.prototype.__proto__ === Object.prototype;// true

其实Object.prototype也是一个对象那么他的原型是什么呢?我们可以打印一下发现他的原型是null,上图也可以看出。

代码语言:javascript
复制
console.log(Object.prototype.__proto__);// null

说了这么一大堆终于知道了原型是什么了,那么还有一个更重要的东西就是原型链。 如果一个对象调用自己没有定义的属性,那么他就会从他们原型中查找,看有没有定义该属性,如果原型中没有就会去原型的原型去寻找,一直找到顶层的Object类的对象(最顶层的null不用找了,肯定没有),这条由原型连起来的链条叫做原型链。

那我们看一个东西,上面person.constructor是什么呢?其实就是Person函数。因为person对象没有constructor属性,所以去person的原型中找也就是person.__proto__而它里面找到了,指向的就是Person函数。

我们也可以用原型来定义对象的属性和方法。

代码语言:javascript
复制
function Person(){
}

Person.prototype.name = "Orange";
Person.prototype.sayName = function(){
    console.log(this.name);
};

var person1 = new Person();
var person2 = new Person();

person2.name = "小明";
person1.sayName();// "Orange"
person2.sayName();// "小明"

我们来看一下这个步骤,person1调用sayName的时候由于person1自己没有sayName这个方法,那么就是去它的原型去找也就是Person.prototype,发现有这个方法,那么就调用,而方法中this.name,由于自己并没有name这样一个属性,也会在原型中找,最后找到了是”Orange”。person2sayName跟之前的是一样的,但是person2name这个属性,所以就不需要去原型链中找了,该属性的值是”小明”。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 创建对象
  • 二、 不使用new关键字会发生什么
  • 四、 成员方法
  • 五、 私有变量
  • 六、 静态方法
  • 七、 原型
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档