Javascript中,伪数组该如何实现,Jquery中该特性使用的多吗?
1、为什么要通过prototype的形式实现呢
2、哪些情况下会返回伪数组
Answers
常见的有
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>
你这问题都问得我不知道从哪里答起了。
伪数组
伪数组,就是像数组一样有
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();