JavaScript基础精简版2(面向对象编程,Object)

90 阅读5分钟

面向对象编程

JavaScript 对象体系,不是基于“类”的,而是基于构造函数constructor和原型链prototype的。

Vehicle就是构造函数。第一个字母大写以区分普通函数。内部使用了this关键字,代表了所要生成的对象 实例。必须使用new命令生成对象。

var Vehicle = function (p) {
  this.price = p;
};

var v = new Vehicle(500);

new

使用new命令时,它后面的函数依次执行下面的步骤。

  1. 创建一个空对象,作为将要返回的对象实例。
  2. 将这个空对象的原型,指向构造函数的prototype属性。
  3. 将这个空对象赋值给函数内部的this关键字。
  4. 开始执行构造函数内部的代码。

如果当前函数是new命令调用,new.target指向当前函数,否则为undefined

function f() {
  console.log(new.target === f);
}
f() // false
new f() // true

Object.create()传入一个现有的对象,生成新的实例对象。

this

this的指向:

function f() {
  return '姓名:'+ this.name;
}
var A = {
  name: '张三',
  describe: f
};
var B = {
  name: '李四',
  describe: f
};
A.describe() // "姓名:张三"
B.describe() // "姓名:李四"

this设计目的就是在函数体内部,指代函数当前的运行环境。

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

this的主要使用场合。

  • 全局环境使用this,它指的就是顶层对象window
  • 构造函数中的this,指的是实例对象。
  • 对象的方法里面包含thisthis的指向就是方法运行时所在的对象。

callapplybind这三个方法,来切换/固定this的指向

var n = 123;
var obj = { n: 456 };

function a() {
  console.log(this.n);
}

a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456

applycall相似, 区别是apple传参用数组

function f(x, y){
  console.log(x + y);
}

f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2

bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};

var obj = {
  count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101

继承

prototype所有属性和方法,都能被实例对象共享。
原型链:所有对象都有自己的原型对象(prototype),最终都可以上溯到Object.prototype(即null)。
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。

function P() {}
var p = new P();

p.constructor === P // true
p.constructor === P.prototype.constructor // true
p.hasOwnProperty('constructor') // false

instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例。

继承

// 第一步,子类继承父类的实例
function Rectangle() {
  Shape.call(this); // 调用父类构造函数
}
// 另一种写法
function Rectangle() {
  this.base = Shape;
  this.base();
}

// 第二步,子类继承父类的原型
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;


var rect = new Rectangle();

rect instanceof Rectangle  // true
rect instanceof Shape  // true

对象方法

  • Object.getPrototypeOf方法返回参数对象的原型
  • Object.setPrototypeOf方法为参数对象设置原型,返回该参数对象
  • 实例对象的isPrototypeOf方法,用来判断该对象是否为参数对象的原型。
  • 实例对象的__proto__属性(前后各两个下划线),返回该对象的原型。即prototype
  • Object.getOwnPropertyNames返回一个参数对象本身的所有非继承属性的键名的数组。
  • 对象实例的hasOwnProperty用于判断某个属性定义在对象自身,还是定义在原型链上。
  • infor...in
  • Object.getOwnPropertyDescriptors对象拷贝。

Object

Object对象本身的方法

Object.print = function (o) { console.log(o) };

实例方法就是定义在Object原型对象Object.prototype上的方法。

Object.prototype.print = function () {
  console.log(this);
};

var obj = new Object();
obj.print() // Object

象属性模型的相关方法

  • Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
  • Object.defineProperty():通过描述对象,定义某个属性。
  • Object.defineProperties():通过描述对象,定义多个属性。

控制对象状态的方法

  • Object.preventExtensions():防止对象扩展。
  • Object.isExtensible():判断对象是否可扩展。
  • Object.seal():禁止对象配置。
  • Object.isSealed():判断一个对象是否可配置。
  • Object.freeze():冻结一个对象。
  • Object.isFrozen():判断一个对象是否被冻结。

原型链相关方法

  • Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
  • Object.getPrototypeOf():获取对象的Prototype对象。

实例对象的方法

  • Object.prototype.valueOf():返回当前对象对应的值。
  • Object.prototype.toString():返回当前对象对应的字符串形式。
  • Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。
  • Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。
  • Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。
  • Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。

属性描述对象:JS内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。每个属性都有属性描述对象(元信息)。
属性描述对象提供6个元属性。

{
  value: 123,// 该属性的属性值,默认为`undefined`writable: false,//是否可改变
  enumerable: true,//是否可遍历,默认`true`。如`false` Object.keys()会跳过该属性。
  configurable: false,//可配置性 可写性。 默认为`true`
  get: undefined,// 取值函数(getter)
  set: undefined//存值函数(setter)
}

Object.getOwnPropertyDescriptor()获取自身属性描述对象:

var obj = { p: 'a' };

Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

Object.getOwnPropertyNames返回对象自身的全部属性的属性名。

元属性

value属性是目标属性的值。

var obj = {};
obj.p = 123;

Object.getOwnPropertyDescriptor(obj, 'p').value
// 123

Object.defineProperty(obj, 'p', { value: 246 });
obj.p // 246

configurablefalse时,writableenumerableconfigurable都不能被修改了 value属性的情况比较特殊。 下面这样实现,属性pconfigurableenumerable都为true

var obj = {
  get p() {
    return 'getter';
  },
  set p(value) {
    console.log('setter: ' + value);
  }
};

JavaScript 提供了三种冻结方法,最弱的一种是Object.preventExtensions,其次是Object.seal,最强的是Object.freeze。防止对象被改变。然后可以通过 isFrozen isSealed检查。

Object.preventExtensions方法可以使得一个对象无法再添加新的属性。