Javascript中,伪数组该如何实现,Jquery中该特性使用的多吗?


1、为什么要通过prototype的形式实现呢
2、哪些情况下会返回伪数组

javascript数组 JavaScript

罪与罚与赎 9 years, 9 months ago

常见的有 arguments , DOM集合

arguments


 function f(){
    console.log(arguments);
    console.log(arguments.length);
    console.log(arguments instanceof Array);
}
f(1,2,3);

图片描述

DOM集合

会随着DOM节点的变化动态更新


 <ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var lis = document.getElementsByTagName('li');
     console.log(lis);
    var ul = document.getElementById('ul');
    ul.appendChild(document.createElement('li'));
    console.log(lis);
</script>

源源源源源源宝 answered 9 years, 9 months ago

你这问题都问得我不知道从哪里答起了。

伪数组

伪数组,就是像数组一样有 length 属性,也有 0 1 2 3 等属性的对象,看起来就像数组一样,但不是数组,比如


 var fakeArray = {
    length: 3,
    "0": "first",
    "1": "second",
    "2": "third"
};

for (var i = 0; i < fakeArray.length; i++) {
    console.log(fakeArray[i]);
}

常见的参数的参数 arguments ,DOM 对象列表(比如通过 document.getElementsByTags 得到的列表),jQuery 对象(比如 $("div") )。

伪数组是一个 Object,而真实的数组是一个 Array


 fakeArray instanceof Array === false;
Object.prototype.toString.call(fakeArray) === "[object Object]";

var arr = [1,2,3,4,6];
arr instanceof Array === true;
Object.prototype.toString.call(arr) === "[object Array]"

不过有个更简单的办法来判断,用 Array.isArray


 Array.isArray(fakeArray) === false;
Array.isArray(arr) === true;

至于什么情况下返回伪数组,完全看库的实现,一般就比如刚才说到的 arguments ,DOM对象列表和 jQuery 对象。如果是自己写的呢,多半是因为希望能通过 prototype 扩展一些方法,又不想直接去扩展 Array.prototype ,所以就只好模拟一个 Array,也就是伪数组了,比如 jQuery 就是这么干的。

prototype (原型)

然后这里就说到了 prototype 。javascript 的 OOP 特性是通过原型,也就是 prototype 来实现的。其它语言中,定义一个类的时候,会在类定义中定义一些实例方法或属性,这样所有这个类的实例对象都具有这些方法和属性。然而 javascript 中没有真正的“类”概念,是通过 function 来模拟构建函数,原型对象来定义实例方法和属性来实现的部分 OOP 特性。

简单的举例说说,比如定义一个 Person 类 function Person() {} ,它的实例 new Person() 其实是什么方法与没有的,那就通过为 Person 附加一个原型(或者修改其默认原型)来添加方法和属性


 // 代码①
function Person(name) {
    this._name = name;
}

Person.prototype.getName = function() {
    return this._name;
}

Person.prototype.walk = function() {
    console.log(`${this.getName()} is walking`);
}

var james = new Person("James");
james.walk();
var Jack = new Person("Jack");
jack.walk();

// [console]
// James is walking
// Jack is walking

但是,原型只是实现的一个方法,也可以直接在构建函数中给 this 赋值的方法来实现


 // 代码②
function Person(name) {
    this._name = name;
    this.getName = function() {
        return this._name;
    }
    this.walk = function() {
        console.log(`${this.getName()} is walking`);
    }
}

var james = new Person("James");
james.walk();
var jack = new Person("Jack");
jack.walk();

// [console]
// James is walking
// Jack is walking

看起来似乎实现是一样的,但实际呢,上面那个,生成再多实例对象,所使用的方法都是同一个,原型改了,大家都跟着改。而第2种方法,每个实例对象有自己独立的实现,改掉一个(也没法全部改啊),其它的不会跟着改。


 // 代码③,接 代码①
Person.prototype.walk = function() {
    console.log(`${this.getName()} is walking walking walking ...`);
}
james.walk();
jack.walk();
// [console]
// james is walking walking walking ...
// jack is waling walking walking ...

至于第 2 段代码,只能改每个对象的 walk 方法了,改了的会变,没改的不会变。

留个题

接③,如果有如下代码,会是什么样的结果?


 james.walk = function() {
    console.log(`${this.getName()} walking ... done");
}

james.walk();
jack.walk();

delete james.walk;
james.walk();

love鸡毛 answered 9 years, 9 months ago

Your Answer