美文网首页
JS面向对象编程

JS面向对象编程

作者: Beatrice7 | 来源:发表于2016-05-22 00:39 被阅读296次

学过C++等语言的话,你一定明白面向对象的两个基本概念:

  • 类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;
  • 实例:实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming、xiaohong等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。

所以,类和实例是大多数面向对象编程语言的基本概念。

BUT,JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。

创建对象

JavaScript的所有数据都可以看成对象(Object)。
三种创建对象的方法:

  1. 对象字面量
 var xiaoming = {
    name: '小明',
    hello: function () {
        console.log('Hello, ' + this.name + '!');
    }
};
  1. 构造函数
function Student(name) {
    this.name = name;
    this.hello = function() {
         console.log('Hello, ' + this.name + '!');
    }
}
var xiaoming = new Student("小明")
  1. Object.create()构造
    Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不是一个子函数,可以传一个null,第二个参数是对象的属性描述符,这个参数是可选的。
var Student = {
    name: 'Robot',
    hello: function () {
        console.log('Hello, ' + this.name + '!');
    }
};
var xiaoming = Object.create(Student);

其中,第二种构造函数,如果不写new,Student就是一个普通函数(也可以说是方法Function),它返回undefined。但是,如果写了new,它就变成了一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就是说,不需要在最后写return this;了。

\\proto\\属性与prototype属性

我们只看前两种方法,第一种是直接创建对象,第二种是通过方法(Function)来创建对象。
JavaScript对每个创建的对象都会设置一个__proto__属性,指向该对象的构造函数的原型对象。而如果是通过第二种构造函数的方法来创建的创建的对象还会多出一个prototype属性。
解释如下:

//构造函数
function Student(name) {
    this.name = name;
    this.hello = function() {
         console.log('Hello, ' + this.name + '!');
    }
}
var xiaoming = new Student("小明")
var xiaosha = new Student("小傻")

//对象字面量
var Student1 = {
 name: 'XXX',
 hello: function () {
     console.log('Hello, ' + this.name + '!');
 }
};
var xiaohong = {
    name: "xiaohong"
}
xiaohong.__proto__ = Student1;

在创建xiaohong的时候我们直接把xiaohong.\proto\ = Student1;为甚么这样写呢,因为它不是Function创建的对象,当然也就不具备prototype属性哈哈。但是上述代码仅用于演示目的。在编写JavaScript代码时,不要直接用obj.__proto__去改变一个对象的原型,并且,低版本的IE也无法使用__proto__

对象的原型链对象的原型链
img3img3
Img1Img1
说明几点:
  1. 由Img1可以看出,通过构造函数创建的对象除了__proto__属性还有prototype属性。事实上,只要是Function就会有该属性,也即普通函数也有prototype属性,原因是方法(Function)这个对象搞特殊,他还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象(这个被指向的对象我们后面细说)。
    2.在JS中,方法(Function)是对象,方法的原型(Function.prototype)也是对象啊

通过原型(prototype)来实现面向对象编程

function Foo(){
  y = 2;
}
typeof Foo.prototype; //"object"
var obj = new Foo();

上面这个函数Foo是作为一个构造器来使用,this指向一个对象,而这个对象的原型会指向构造器的prototype属性(Foo.prototype也是一个对象)

function Person(name, age){
this.name = name;
this.age = age;
}

正常直接调用Person函数的话,this指向全局对象(在浏览器中为window),不写return的话,返回undefined。如果用new调用的话。this会指向为一个原型为Person.prototype的空对象,通过this.name给这个空对象赋值,绑定的this指向这个新创建的对象(此时已经不空了),并默认返回this,也就是说,不需要在最后写return this了。

call、apply

call方法:
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。 如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
apply方法:
语法:apply([thisObj[,argArray]])

都知道这两个函数能改变函数执行的上下文,可是我总是搞不懂第一个参数到底传入的是什么。如果是this,那this又是什么。。。
所以今天测试一下,应该是懂了。

function Person(name, age){
    this.name = name;
    this.age = age;
}
function Stu(name, age, className){
    console.log(this) //Stu{}

    Person.call(this,name,age)
    console.log(this) //Stu{name: "Beatrice", age: 12}

    this.className = className;
    console.log(this) /Stu {name: "Beatrice", age: 12, className: 6}
}
var stu1 = new Stu("Beatrice", 12, 6);

最开始传入的是一个原型为Stu.prototype的空Stu{}对象。最后,我们把这个对象赋值给stu1。如何让Stu的实例能继承Person.prototype上的一些方法呢?

Stu.prototype = Object.create(Person.prototype);
Stu.prototype.constructor = Stu;

Object.create()创建一个空对象,并且对象的原型指向它的参数。这里就创建了一个原型指向Person.prototype的空对象。因为Stu.prototype会作为所有new Stu()实例的原型,为了继承Person.prototype上的一些方法,我们就把这个创建出来的空对象赋值给Stu.prototype,这样实例继承Stu.prototype,也就相当于实例继承这个原型为Person.prototype的空对象了。
那你也许会问,为什么不直接赋值Stu.prototype = Person.prototype,而是要通过Object.create呢?
如果直接赋值,Stu有一些自己的方法,当我们想增加Stu自己的方法的时候,也会加在Person上面,这显然不是我们想要的。所以我们搞一个中间的桥梁,也就是这个空对象。
这时,这个创建出的空对象的prototype == Person.prototype == Student.prototype。每一个prototype属性下面自带一个constructor属性,这个属性是指向自身的(所以这是个无限循环了呵呵)。所以prototype属性里面的constructor当然也都一致的,都是Person了。为了保证一致性,所以我们这里把Stu的constructor重新设置为指向自身。

内置构造器的prototype属性

字面量创建的对象var object= {};的原型是Object.prototype
ES5中使用defineProperty()函数来对原型添加属性,而不是直接Object.prototype.x = 1这种形式来添加。
obj.hasOwnProperty()方法,只查找对象obj的方法,而不继续向上查找。

instanceof

[1,2] instanceof Array === true
new Object() instanceof Array === false

在instanceof左侧是对象,右侧是构造器(函数),instanceof用于判断右边这个构造器的prototype属性是否在左侧这个对象的原型链上。

实现继承的方式

    function Person(){

    }
    function Student(){

    }
    Student.prototype = Person.prototype; //1 这是错的!!
    Student.prototype = new Person(); //2  有点小问题,当构造函数要传入参数的时候
    Student.prototype = Object.create(Person.prototype);  //3 这个方法较好,但要ES5
    Student.prototype.constructor = Student;
    //对于1,2,3步骤有一个比较好的方法,自己封装一个Object.create()方法
    if(!Object.create){  //4.
        Object.create = function(proto){
            function F(){}
            F.prototype = proto;
            return new F;
        }
    }
  1. 错的,因为子类有自己的方法,修改Student不能同时也把Person改掉
  2. 调用构造函数方法,也能将Student。prototype指向一个原型为Person.prototype的对象,但是这个方法当构造函数要传入参数的时候会有问题,因为我们还没有实例化呢,你参数要传入什么呢?对吧~
  3. 较为理想,Student的原型是个空的对象,这样修改就不会改到Person,But ES5采用。所以我们自己封装了一个4.
  4. 在ES5之前,模拟一个Object.create(),原理是模拟一个空函数,并且把这个空函数的prototype属性赋值为proto这个我们想作为原型的对象,用return new F这样呢就创建出一个空对象,这个对象的原型指向proto这个参数。

题目描述:
请给Array本地对象增加一个原型方法,它用于删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

Array.prototype.distinct = function() {
    var ret = [];
    for (var i = 0; i < this.length; i++)
    {
        console.log(this);
        for (var j = i+1; j < this.length;) {   
            if (this[i] === this[j]) {              
                var tmp = this.splice(j, 1);
                //console.log(tmp)
                ret.push(tmp[0]);
            } else {
                j++;
            }
        }
     }
     return ret;
}
//for test
console.info(['a','b','c','d','b','a','e'].distinct())

相关文章

  • javascript面向对象编程

    javascript面向对象编程一(封装) 通俗易懂绝对干货 JS面向对象编程

  • js面向对象

    js面向对象(第五周) 什么是面向对象 面向对象是一种编程思想,是在面向过程编程(结构化编程)之后出现的,面向对象...

  • ES6中的类的总结

    js常用的编程模式有面向过程编程和面向对象编程(1)面向过程编程“面向过程”(Procedure Oriented...

  • 浅谈JS中的面向对象

    浅谈JS中的面向对象 本文主要说说本人在JS中对面向对象的理解。 计算机编程语言主要分为面向过程式编程和面向对象式...

  • js高级 第一章

    JS面向对象编程 一、什么是面向对象思想(编程思想角度)? 现有的两种程序思想:面向过程和面向对象 1.面向过程...

  • 面试题的总结与解答

    1,js中this指向的理解 在js面向对象编程里我们避免不了使用this,所以理解this指向对于在面向对象编程...

  • JS面向对象

    JS面向对象入门 1、面向对象语言概念面向对象语言主要包括 类、对象、封装、多肽。2、面向对象的编程思想面向过程思...

  • JS高级3-语言特性

    一、 JS面向对象编程 1、 面向对象介绍 什么是对象? Everything is object (万物皆对象)...

  • RYF javascript笔记3

    4. 面向对象编程 4.1面向对象编程概述 4.1.1简介 4.1.1.1构造函数 js没有“类”,而改用构造函数...

  • WEB 八

    JS 面向对象编程 利用JS面向对象编程写一个贪吃蛇小游戏 思路:地图->蛇->让蛇运动->用键盘控制蛇运动->食...

网友评论

      本文标题:JS面向对象编程

      本文链接:https://www.haomeiwen.com/subject/gikwkttx.html