JavaScript:对象学习

JavaScript有数组,但是没有字典这种结构,对象从形式上看就是一种字典结构。并且对象的key统一为String类型,(用其他类型也不会出错,只是内部会调用toString接口自动转),value可以是简单的值,对象,函数,数组等。
可以简单理解为对象就是字典的键值对,跟JSON互转非常方便。个人非常认同这种简单的处理方式。
当然,有map这种类似字典的结构,至少名字不叫字典,并且目前更愿意用数组的map()方法。
一切都是对象,比如数组、函数本身都是对象。数字,布尔量等等也都是对象。

对象创建

JavaScript没有类的概念,而是采用原型链的方式来定义类。平时使用的时候直接调用构造函数创建类。并且也没有析构函数的概念。delete也只是删除对象的属性,而不是回收对象。对象的回收由GC统一负责,不需要操心
使用对象
Javascript 创建对象方法的总结
JavaScript prototype
JavaScript 对象

直接{}初始化

大多数时候,对象就是一些键值对的组合,比如MVC设计模式中的M,只有属性,没有方法,并且字段名都确定。那么最简单的方式就是直接定义变量,给初始化值。对象定义和初始化一并完成了。对象{}可以嵌套,跟JSON很相似:

var myCar = {
    color: "red", 
    wheels: 4, 
    engine: {
        cylinders: 4, 
        size: 2.2
    }
};
console.dir(myCar);

构造函数

如果Model在好几个地方用,那么直接初始化的方法就不大合适,一不小心属性名字就写的不一样了。可以定义一个构造函数,然后用的地方调用这个构造函数创建对象,可以保证大家的属性名字是一样的,只是对象的名字和属性值不一样。
这里包括定义构造函数和定义变量并初始化两个步骤

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var myCar = new Car("Eagle", "Talon TSi", 1993);
console.dir(myCar);

动态添加属性

一开始只知道要用一个对象,但是字段一个都不知道。等到用的时候才知道字段的名字和值。这种场景,可以通过直接添加属性的方式创建对象。这种形式使用起来最方便。

person = {};  // person = new Object();
person.firstname="John";
person.lastname="Doe";
person.age=50;
person.eyecolor="blue";
console.dir(person);

添加方法

  • 属性的keyString,值是对象(数字也是对象);函数的key也是String,值是函数,也是对象;所以函数成员和普通的数据成员没有本质区别。
  • 不过从面向对象设计的概念来说,数据是私有的,每个对象一份copy,大家互不影响,是合理的。而函数只是定义了做事的方法,并没有实际工作,不需要每个对象持有一份copy,只要大家共享一份就可以了。这样省内存啊。
  • 除了函数以外,有些数据成员也希望多个对象共享一份数据。行为相当于静态变量。
    希望共享的成员,(函数或者数据都一样),就添加到对象的prototype
function Person(name,age,job) {
    this.name=name;
    this.age=age;
    this.job=job;
}

Person.prototype = {
    friends:["Jams","Martin"],
    sayFriends:function() {
        alert(this.friends);
    }
};

var person1 = new Person("kevin",31,"SE");
var person2 = new Person("Tom",30,"SE");
person1.friends.push("Joe");
person1.sayFriends(); // Jams,Martin,Joe
person2.sayFriends(); // 也是Jams,Martin,Joe;因为属性friends在prototype定义,所有Person对象共享
console.dir(person1);
console.dir(person2);

如果要把prototype部分的定义放到构造函数中,要注意保护只做一次。因为构造函数会被多次调用,但是定义prototype只要1次就可以了。推荐还是这种将prototype拿到构造函数外面定义的方式。

访问对象

  • 访问属性一般用点语法:objectName.propertyName
  • 访问方法一般用点语法:objectName.methodName()
  • 访问属性也可以用[]。一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。例如:
// 同时创建四个变量,用逗号分隔
var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object();

myObj.type              = "Dot syntax";
myObj["date created"]   = "String with space";
myObj[str]              = "String value";
myObj[rand]             = "Random Number";
myObj[obj]              = "Object";
myObj[""]               = "Even an empty string";

console.dir(myObj);

原型对象(prototypical object)

  • JavaScript是基于原型的语言:只有对象,没有类。
  • 原型对象可以作为一个模板,新对象可以从中获得原始的属性。只是简单的copy,没有继承的功能。通过“原型链”,可以实现类似继承的效果。
  • 通过原型继承来的属性是所有对象共享的,这点要注意。对象特有的变量要用this关键字写在构造函数中
  • 特殊的 __proto__属性是在构建对象时设置的;设置为构造器的 prototype 属性的值。
    所以表达式 var a = new Foo() 将创建一个对象a,其中 a.__proto__ == Foo.prototype
  • 对象先找本地自己的构造函数中用this表示的变量,找到了就返回了,不去管原型链中是否有相同名字的属性。效果相当于子类覆盖父类的属性
  • 当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部 – 也就是 Object.prototype – 但是仍然没有找到指定的属性,就会返回 undefined
  • hasOwnPropertyObject.prototype的一个方法,它可是个好东西,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnPropertyJavaScript中唯一一个处理属性但是不查找原型链的函数。
// 修改 Object.prototype
Object.prototype.bar = 1;

var foo = {moo: 2};
for(var i in foo) {
    console.log(i); // 输出两个属性:bar 和 moo
}

for(var i in foo) {
    if (foo.hasOwnProperty(i)) {
        console.log(i);   // 只输出 moo
    }
}      

参考文章

javaScript原型链理解
这个文章讲得比较清楚,特别是那张图要好好理解。

对象模型的细节

深入理解JavaScript系列(5):强大的原型和原型链

彻底理解javascript中的原型链

    原文作者:老章888
    原文地址: https://www.jianshu.com/p/3e57cd7e0073
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞