JavaScript 对象操作、继承与模块化实现

发布于:2025-07-21 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. Object 对象相关方法


Object.getPrototypeOf():返回参数对象的原型,是获取原型对象的标准方法。

var F = function () {};
var f = new F();
Object.getPrototypeOf(f) === F.prototype; // true

Object.setPrototypeOf():为参数对象设置原型,返回该参数对象。可用于模拟new命令。


var a = {};
var b = {x: 1};
Object.setPrototypeOf(a, b);
Object.getPrototypeOf(a) === b; // true

Object.create():以指定对象为原型,返回一个新的实例对象。还可接受第二个参数,用于添加实例自身的属性。


var A = { print: function () { console.log('hello'); } };
var B = Object.create(A);
B.print(); // hello

Object.prototype.isPrototypeOf():判断该对象是否为参数对象的原型,只要实例对象处在参数对象的原型链上,就返回true。


var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isPrototypeOf(o3); // true

Object.prototype.__proto__:返回对象的原型,该属性可读写,但不建议使用,推荐用Object.getPrototypeOf()和Object.setPrototypeOf()。


var obj = {};
var p = {};
obj.__proto__ = p;
Object.getPrototypeOf(obj) === p; // true

Object.getOwnPropertyNames():返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。


Object.getOwnPropertyNames(Date); 

Object.prototype.hasOwnProperty():判断某个属性定义在对象自身,还是定义在原型链上。


Date.hasOwnProperty('length'); // true

in运算符:返回一个布尔值,表示一个对象是否具有某个属性,不区分该属性是对象自身的还是继承的。


'length' in Date; // true

for...in循环:用于遍历对象的所有可遍历属性(包括自身和继承的)。


var o1 = { p1: 123 };
var o2 = Object.create(o1, { p2: { value: "abc", enumerable: true } });
for (p in o2) { console.info(p); }


2. 对象的继承


原型对象概述
构造函数的缺点:同一个构造函数的多个实例之间,无法共享属性,造成系统资源浪费。


function Cat(name, color) {
  this.name = name;
  this.color = color;
  this.miaomiao = function () { console.log('喵喵'); };
}
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');
cat1.meow === cat2.meow; // false

prototype属性的作用:原型对象的所有属性和方法,都能被实例对象共享。


function Animal(name) { this.name = name; }
Animal.prototype.color = 'white';
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color; // 'white'

原型链:所有对象都有自己的原型对象,形成一个 “原型链”,最终都可以上溯到Object.prototype,其原型是null。


Object.getPrototypeOf(Object.prototype); // null

constructor属性:prototype对象的constructor属性默认指向prototype对象所在的构造函数,可用于得知实例对象的构造函数。修改原型对象时,一般要同时修改constructor属性。


function P() {}
P.prototype.constructor === P; // true


instanceof运算符
返回一个布尔值,表示对象是否为某个构造函数的实例,其实质是检查右边构造函数的原型对象是否在左边对象的原型链上。

var v = new Vehicle();
v instanceof Vehicle; // true


构造函数的继承
分两步实现:

在子类的构造函数中,调用父类的构造函数。


function Sub(value) {
  Super.call(this);
  this.prop = value;
}

让子类的原型指向父类的原型。


Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;


多重继承
JavaScript 不提供多重继承功能,但可通过变通方法实现,如 Mixin 模式。


function M1() { this.hello = 'hello'; }
function M2() { this.world = 'world'; }
function S() {
  M1.call(this);
  M2.call(this);
}
S.prototype = Object.create(M1.prototype);
Object.assign(S.prototype, M2.prototype);
S.prototype.constructor = S;


3. 模块化编程
基本的实现方法
把模块写成一个对象,所有的模块成员都放到这个对象里面,但会暴露所有模块成员。


var module1 = new Object({
  _count : 0,
  m1 : function (){ /*...*/ },
  m2 : function (){ /*...*/ }
});


封装私有变量
构造函数的写法:将私有变量封装在构造函数中,但会导致构造函数与实例对象一体,耗费内存。


function StringBuilder() {
  var buffer = [];
  this.add = function (str) { buffer.push(str); };
  this.toString = function () { return buffer.join(''); };
}

立即执行函数的写法:将相关的属性和方法封装在一个函数作用域里面,可达到不暴露私有成员的目的。


var module1 = (function () {
  var _count = 0;
  var m1 = function () { /*...*/ };
  var m2 = function () { /*...*/ };
  return { m1 : m1, m2 : m2 };
})();


模块的放大模式和宽放大模式


放大模式:为模块添加新方法。


var module1 = (function (mod){
  mod.m3 = function () { /*...*/ };
  return mod;
})(module1);

宽放大模式:适用于无法确定模块加载顺序的情况。


var module1 = (function (mod) { /*...*/ })(window.module1 || {});

输入全局变量
为保证模块的独立性,显式地将其他变量输入模块。

javascript
var module1 = (function ($, YAHOO) { /*...*/ })(jQuery, YAHOO);


网站公告

今日签到

点亮在社区的每一天
去签到