##转载

对象

我们知道javascript并不是面向对象的语言,我们可以把javascript理解成基于对象的语言。在javascript当中所有的变量都是对象,除了null和undefined。

一、对象的使用和属性

前面说到所有变量都是对象,那我们尝试调用对象的toString方法来验证一下。

[1,2,3,4].toString();    //"1,2,3,4"
true.toString();    //"true"
' '.toString();        //" "
2.14.toString();    //"2.14"
2.toString();    //SyntaxError

为什么最后一项会出错呢?因为javascript的解释器尝试把“点操作符”解释为前面浮点数字中的一部分,所以就出错了。

访问属性

访问对象的属性有两种方式,点操作符和中括号操作符

var foo = {name: 'xiao'}
foo.name; // xiao
foo['name']; // xiao

var get = 'name';
foo[get]; // xiao

foo.1234; // 出错:SyntaxError
foo['1234']; // 有效

从例子当中的最后两行我们可以看到js的对象属性并不是有效的的变量。我们并不推荐这么做,但是对js来说依旧有效。

删除属性

设置属性的值为null或undefined并不能真正的删除属性,而是移除了属性和值得关联关系;删除属性的唯一操作就是使用delete关键字。

var user = {
    name:'xiaoxiao',
    sex:'男',
    age:22,
    address:'CQ'
}

user.sex = null;
user.age = undefined;
delete user.address;

for(var i in user){
    if(user.hasOwnProperty(i)){
        console.log(i+"="+user[i]);
    }
}

在浏览器控制信息为:

name=xiaoxiao
sex=null
age=undefined

所以只能通过delete的方式对象的属性。

二、原型

在说原型之前,我们先来把对象的属性和方法,原型属性和方法,静态属性和方法的概念了解一下。

function A(){
    var a1 = "a1";    //对象的私有属性

    this.b1 = "b2";        //对象的属性
    this.b2 = function(){    //对象的方法
        alert("b2");
    }
}

A.c1 = "c1";    //静态属性
A.c2 = function(){    //静态方法
    alert("c2");
}

A.prototype.d1 = "d1";    //原型属性
A.prototype.d2 = function(){    //原型方法
    alert("d2");
}

var obj = new A();
console.log(obj);

在开发者工具下面我们看到:

  1. 对象的方法和属性都在对象下
  2. 对象的原型方法和原型属性在__proto__下
  3. 对象的静态方法和属性在__proto__下的constructor里面

有了上面的基础我们在来理解原型方面的东西。

JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。

由于 JavaScript 是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的。

原型继承的本质实际上是在复制已经存在的对象。

function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

// 设置Bar的prototype属性为Foo的实例对象
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

// 修正Bar.prototype.constructor为Bar本身
Bar.prototype.constructor = Bar;

var test = new Bar() // 创建Bar的一个新实例

// 原型链
test [Bar的实例]
    Bar.prototype [Foo的实例] 
        { foo: 'Hello World' }
        Foo.prototype
            {method: ...};
            Object.prototype
                {toString: ... /* etc. */};

上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此, 它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。 需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是 重复使用它原型上的那个实例;因此,所有的 Bar 实例都会共享相同的 value 属性。

在查找一个对象的属性的时候,javascript会在原型链上向上遍历,直到找到指定名称的值,当查找到原型链的顶端,也就是Object.prototype时已就位找到,则返回undefined。

应用

比如我们为数组Array添加一个删除的重复元素的方法,我们可以这么写:

Array.prototype.delRep = function(){
    //...
}

三、hasOwnPrototype和in的区别

hasOwnPrototype和in都可以用来判断对象是否具有这个属性,但hasOwnPrototype是用来判断该属性是不是定义在自身上。

// 修改Object.prototype
Object.prototype.bar = 1; 
var foo = {goo: undefined};

'bar' in foo;    // true
'goo' in foo;    //true

foo.hasOwnProperty('bar');    // false,bar为原型上定义的属性,不属于foo本身自定义的属性,所以返回false
foo.hasOwnProperty('goo');    // true

参考资料:

ECMAScript 6入门: http://es6.ruanyifeng.com/

js的Prototype属性 解释及常用方法: http://blog.sina.com.cn/s/blog_7045cb9e0100rtoh.html

前端开发必须知道的JS(一) 原型和继承:http://www.cnblogs.com/ljchow/archive/2010/06/08/1753526.html