JS中面向对象的概念

面向对象OOP是一种组织代码结构、实现功能过程的思维方式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。

举例:

一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。对象是单个实物的抽象,对象还是一个容器,封装了属性(property)和方法(method)。属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是那一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。

面向对象的实现思路:

把某个功能看成一个整体(对象),通过调用对象的某个方法来启动功能。在用的时候不去考虑这个对象内部的实现细节,在去实现这个对象细节的时候不用管谁在调用。面向对象的方法在前端页面中一般用来将重复的东西抽象化,便于复用和节省内存。

面向对象的三个要点

封装:就是将类内部的机制隐藏起来,让外界无法访问,从而达到保护数据的目的。封闭一部分让外界无法访问,开放一部分,通过开放部分间接访问私有部分。可以用闭包来实现JS面向对象之私有属性封装。
继承:为了提高代码的复用性,可以用继承,将一个子类继承一个父类,这样子类就可以继承父类的属性和方法,而不需要重新写一个类中的属性和方法。JavaScript的继承方式是通过原型链来完成的。
多态:多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得不同的结果。

JS构造函数

用传统的面向对象思维,构造实例的过程近似理解为:JS中object(对象)是某一个class(类)的实例,class可以理解成模具,object就是用模具制造出来的实物。
JS中没有类的概念,只有构造函数(函数)、属性的概念。很多语言中是由类(class)构造出实例对象,但JS中的对象不基于类而构建,而是基于构造函数和原型链来构建的。比如:var ccc={name:"penny"}这种写法是可行的,JS中本质上是通过new Object()这个构造函数来创建。对象是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成对象的函数。它提供模板,描述对象的基本结构。一个构造函数,可以生成多个对象,这些对象都有相同的结构。
通过类构建好比是上帝造人类,先定义好人的各属性当作模板,再创建人类
不依赖类构建(函数式编程)好比是人进化成人类,在进化过程中不断给人添加各种属性形成人类。

构造函数的两个特征:
[1]函数内部使用了this,指向所要生成的对象实例。
[2]必须用new命令调用生成对象实例

构造函数new Function()

new运算符接受一个函数及其参数作为构造器,根据传入参数来创建相同类型但值不同的实例对象。new命令的作用,就是执行构造函数,返回一个实例对象。
new Function()的三个步骤:
1.创建类的实例。将一个空对象的__proto__指向构造函数的prototype属性,这个对象就是要返回的实例对象。
2.初始化实例。将参数传入构造函数并执行构造函数,因为构造函数内部的this指向的是由构造函数生成的实例。针对this的操作都会发生在这个空对象上,所以通过this,实例可继承构造函数的属性和方法。
3.返回实例。
构造函数之所以叫“构造函数”,就是因为构造函数操作一个空对象(即this指向的实例对象),将其“构造”为需要的样子。

普通函数用new调用时,因为普通函数内部没有this,所以使用new命令执行后返回的是一个空对象。new运算符接受一个函数及其参数作为构造器,根据传入参数来创建相同类型但值不同的实例对象。new命令的作用,就是执行构造函数,返回一个实例对象。
new Function()的三个步骤:
1.创建类的实例。将一个空对象的__proto__指向构造函数的prototype属性,这个对象就是要返回的实例对象。
2.初始化实例。将参数传入构造函数并执行构造函数,因为构造函数内部的this指向的是由构造函数生成的实例。针对this的操作都会发生在这个空对象上,所以通过this,实例可继承构造函数的属性和方法。
3.返回实例。
构造函数之所以叫“构造函数”,就是因为构造函数操作一个空对象(即this指向的实例对象),将其“构造”为需要的样子。普通函数用new调用时,因为普通函数内部没有this,所以使用new命令执行后返回的是一个空对象。

this

this总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象。随着函数使用场景的不同,this的值会发生变化可近似理解成this指向的是函数当前的运行环境。但是有一个总的原则,this指向的是,调用函数的那个对象。

函数调用时的this
函数直接调用时是在全局作用域下调用的,浏览器中的全局作用域是window,this指向window

function fn1(){
    console.log(this); //指向window
}
fn1();

嵌套函数调用时的this
函数嵌套产生的内部函数的this不指向其父函数,仍然是指向全局变量。

function fn0(){
    function fn(){
        console.log(this); //这里的this在调用fn0时依然指向全局window
    }
    fn();
}
fn0();

setTimeout、setInterval中的this
延时函数执行时是在全局作用域下执行,所以this依然指向window

构造函数调用时内部的this
调用构造函数时,构造函数内的this指向的是构造函数创建的实例对象。

对象的方法中的this
函数可以作为一个对象的属性,此时该函数被称为该对象的方法。当函数作为一个对象的方法调用时,这个函数内部的this指向调用该函数的对象。

var obj1 = {
    name: 'Byron',
    fn : function(){
        console.log(this);
    }
};
obj1.fn(); //调用后this指向obj1

嵌套对象调用时this指向最近那一层的对象,嵌套函数调用时this指向window而不指向最近那层函数

var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};
a.b.m() // undefined

DOM对象事件绑定,事件处理函数的this
在事件处理程序中this代表事件源DOM对象。低版本IE的bug会指向window

document.addEventListener('click', function(e){
    console.log(this); //指向DOM对象
    var _document = this;
    setTimeout(function(){
        console.log(this); //指向window
        console.log(_document);
    }, 200);
}, false);

原型链

“原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性(同名属性会优先读取自身属性),如果找不到,就通过__proto__到它的原型去找,如果还是找不到,就通过原型的__proto__到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回null。
__proto__属性是浏览器的内部属性,应尽量避免使用,建议使用
Object.getPrototype(obj)来获取对象的原型对象
Object.setPrototypeOf(obj1,obj2)修改对象的原型对象。
获取一个对象的原型对象有三种方法:
obj.__proto__ 不靠普,ES6规范仅浏览器部署,其他环境没有部署
obj.constructor.prototype 不靠普,obj.constructor.prototype手动改变后如果不修正constructor会导致obj.constructor.prototype指向不准确
Object.getPrototypeOf(obj) 推荐使用

原型链的特性
【1】任何对象上都有__proto__这个属性,指向创建该对象的构造函数的prototype属性(原型对象)。
【2】用面向对象开发时,把要生成的实例对象的特有属性放到构造函数内,把共有的方法放到构造函数的prototype里面。只要修改构造函数的原型对象prototype,所有构造函数生成的实例对象上继承来自原型对象prototype的方法或者属性都会改变。
【3】原型链:任何对象都是由一个更高级的构造函数创建来的。比如对象是由object函数创建来。prototype是函数的属性,__proto__隐式原型是对象(object)的属性。由于JS中函数也是对象,所以函数上也有__proto__属性。对象的__proto__指向这个对象的构造函数的prototype
【4】任何函数都有prototype属性即原型对象,原型对象默认有constructor属性,指向原型对象prototype所在的构造函数,即表示这个原型对象属于哪个构造函数(类型,js无类型的概念)。constructor属性定义在prototype对象上面,可以被所有实例对象继承。修改原型对象时,一般要同时校正constructor属性的指向,建议用给原型对象添加方法的形式修改原型对象,而不是完全覆盖原型对象。

C.prototype.method1 = function (...) {
     ...
 };

instanceof
instanceof 判断一个对象(不能判断原始类型值)是不是某个构造函数(类)的实例,返回布尔值,通过检查原型链来实现判断。instanceof对整个原型链上的对象都有效,因此同一个实例对象,可能会对多个构造函数都返回true。

var d = new Date();
d instanceof Date // true
d instanceof Object // true
//instanceof可以用来判断值的类型
var x = [1, 2, 3];
var y = {};
x instanceof Array // true
y instanceof Object // true

原型图示例

function People (name){
  this.name = name;
  this.sayName = function(){
    console.log('my name is:' + this.name);
  }
}

People.prototype.walk = function(){
  console.log(this.name + ' is walking');  
}

var p1 = new People('饥人谷');
var p2 = new People('前端');
图片转载自知乎
图片描述

x868086
89 声望5 粉丝