bob体育官方平台
JavaScript—从数组的indexOf方法深入——Object的Property机制。

在JavaScript中,数组可以使用Array构造函数来创建,或使用[]快速创建,这也是首选的方法。数组是继承自Object的原型,并且他对typeof没有特殊的返回值,他只返回'object'。

在js中,可以说万物皆对象(object),一个数组也是一个对象(array)。

js中,可以说万物皆对象,一个数组也是一个对象。

 

很多对象都有很多很方便的方法 比如数组的push,concat,slice等等,但是如果一些对象,它没有实现这些方法,我们还是想使用这些功能。那该怎么办呢?

很多对象都有很多很方便的方法 比如数组的push,concat,slice等等,但是如果一些对象,它没有实现这些方法,我们还是想使用这些功能。那该怎么办呢?

bob体育官方平台,1、很多方法都提供了非常高效的实现, 我们可以仿照它们的实现。

 

比如IE8以下的浏览器不支持Array的indexOf方法,为了让数组支持indexOf,我们可以自己写一个方法,实现indexOf方法:

1、很多方法都提供了非常高效的实现, 我们可以仿照它们的实现。

(用IE浏览器调试 按F12,可以选择浏览器版本到IE5。)

 

var arr = [, , , ];if (Array.prototype.indexOf) {alert;} else {alert;}if (!Array.prototype.indexOf) {Array.prototype.indexOf = function {for (var i = ; i < this.length; i++) {if{return i;}}return -;}}alert;alert; 

比如IE8以下的浏览器不支持Array的indexOf方法,为了让数组支持indexOf,我们可以自己写一个方法,实现indexOf方法:

当然这个方法是很垃圾的。在这里具体的实现 我就不献丑了,提供一个百度上copy的版本:

bob体育app,(用IE浏览器调试 按F12,可以选择浏览器版本到IE5。)

有兴趣的话可以看看v8引擎是怎么实现的:

 

if (!Array.prototype.indexOf){Array.prototype.indexOf = function{var len = this.length >>> ;var from = Number || ;from = ? Math.ceil: Math.floorfrom += len;for {if (from in this &&this[from] === elt)return from;}return -;};} 
 1             var arr = [1, 2, 3, 5];
 2             if (Array.prototype.indexOf) {
 3                 alert("你的浏览器支持indexOf方法。");
 4             } else {
 5                 alert("你的浏览器不支持indexOf方法。");
 6             }
 7             if (!Array.prototype.indexOf) {
 8                 Array.prototype.indexOf = function(item) {
 9                     for (var i = 0; i < this.length; i++) {
10                         if(this[i]==item){
11                             return i;
12                         }
13                     }
14                     return -1;
15                 }
16             }
17             alert(arr.indexOf(2));
18             alert(arr.indexOf(8));

2、继承——call和apply方法

 

如果我们每有一个对象,那每个对象就要自己写一遍实现是不是很麻烦?

 当然这个方法是很垃圾的。在这里具体的实现 我就不献丑了,提供一个百度上copy的版本:

在高级语言中,我们可以用继承来解决问题,比如下面的java代码:

有兴趣的话可以看看v8引擎是怎么实现的:

public class MyList extends ArrayList{public void myAdd;System.out.println;}} 
 1 if (!Array.prototype.indexOf)
 2 {
 3   Array.prototype.indexOf = function(elt /*, from*/)
 4   {
 5     var len = this.length >>> 0;
 6     var from = Number(arguments[1]) || 0;
 7     from = (from < 0)
 8          ? Math.ceil(from)
 9          : Math.floor(from);
10     if (from < 0)
11       from += len;
12     for (; from < len; from++)
13     {
14       if (from in this &&
15           this[from] === elt)
16         return from;
17     }
18     return -1;
19   };
20 }

但是js中没有继承的概念啊,我们可以用call和apply来解决这样的问题。

 

上面的代码就可以改写为:

2、继承——call和apply方法

var myObject = function(){}myObject.prototype.add = function(){Array.prototype.push.call;//输出argumentsfor(var i=;i这里可以看到:虽然用高级语言的继承方式实现了myAdd方法,但是现在myAdd方法只能传一个参数,如果要传多个参数,则需要再写一个public void myAdd方法,甚至是public void myAdd方法。而JS用一个方法就可以搞定,用arguments对象表示输入的所有参数,这是高级语言难以做到的。(ps,其实在java中可以写public void myAdd,这个是不定参数,用法上public void myAddcall和apply方法用于改变函数内this指针的指向,call只有两个参数,而apply通常是知道参数个数之后才使用的,下面以例子说明:var Obj = function{this.name = name;}Obj.prototype.getName = function(){return this.name;}var obj1 =new Obj;var obj2 = {name:'andy'};var name = obj1.getName.call; 

如果我们每有一个对象,那每个对象就要自己写一遍实现是不是很麻烦?

参考是:

在高级语言中,我们可以用继承来解决问题,比如下面的java代码:

apply(object,arg1,arg2,....)call(object,[arg1,arg2,....])

 1 public class MyList<E> extends ArrayList<E>
 2 {
 3     
 4     public void myAdd(E e){
 5          super.add(e);
 6          System.out.println("Add:"+e);
 7 
 8     }
 9 
10 }

call后面只能跟一个“数组”,包括了所有的参数。而apply则是一颗语法糖,如果知道参数的个数,用apply将很方便。

但是js中没有继承的概念啊,我们可以用call和apply来解决这样的问题。

上面的object也可以是null或者undefined,这样,这个object就是global object,例如,还是接着上例:

上面的代码就可以改写为:

var name = 'goo';alert(obj1.getName.call; (在严格模式下,由于全局对象是null,故会抛出异常:Uncaught TypeError: Cannot read property 'name' of null)
 1             var myObject = function(){
 2                 
 3                 
 4             }
 5             myObject.prototype.add = function(){
 6                 Array.prototype.push.call(this,arguments);
 7                 //输出arguments
 8                 for(var i=0;i<arguments.length;i++){
 9                     console.log("Add:"+arguments[i]);
10                 }
11                 
12             }
13             var obj = new myObject();
14             obj.add(1,2,3);

3、Object.defineProperty

 

微软:将属性添加到对象,或修改现有属性的特性。

这里可以看到:虽然用高级语言的继承方式实现了myAdd方法,但是现在myAdd方法只能传一个参数,如果要传多个参数,则需要再写一个public void myAdd(E[] e)方法,甚至是public void myAdd(List<E> e)方法。而JS用一个方法就可以搞定,用arguments对象表示输入的所有参数,这是高级语言难以做到的。

getter、setter,

(ps,其实在java中可以写public void myAdd(E... e),这个是不定参数,用法上public void myAdd(E[] e)是一样的)

其实js中对于对象的属性也有getter和setter函数,不过个人觉得js中的getter和setter更像C#一些。

 

例如下面的代码就定义了一个getter/setter:

call和apply方法用于改变函数内this指针的指向,call只有两个参数,而apply通常是知道参数个数之后才使用的,下面以例子说明:

function myobj(){}Object.defineProperty(myobj.prototype,'length',{get:function(){return this.length_; //这里不能是length。},set:function{return this.length_=value;}}); 
            var Obj = function(name){
                this.name = name;
            }

            Obj.prototype.getName = function(){
                return this.name;
            }
            var obj1 =new Obj("zou");
            var obj2 = {name:'andy'};
            var name = obj1.getName.call(obj2);
            alert(name);

注释的地方不能是length,否则会无限递归。

参考是:

也可以去掉set,让length变量只读。

apply(object,arg1,arg2,....)

Object.defineProperty(myobj.prototype,'length',{get:function(){return this.length_; //这里不能是length。}, /*set:function{return this.length_=value;}*/});myobj.length = 3; 

call(object,[arg1,arg2,....])

这个代码会抛出异常:Uncaught TypeError: Cannot set property length of # which has only a getter。

call后面只能跟一个“数组”,包括了所有的参数。而apply则是一颗语法糖,如果知道参数的个数,用apply将很方便。

要让对象的属性只读,还可以用writable:false,

上面的object也可以是null或者undefined,这样,这个object就是global object(window),例如,还是接着上例:

Object.defineProperty(myobj.prototype,'length',{writable:false});
var name = 'goo';
alert(obj1.getName.call(null));

writable:false不能与get set共存,否则会抛出Type Error。

(在严格模式下,由于全局对象是null,故会抛出异常:Uncaught TypeError: Cannot read property 'name' of null)

configurable:是否能用delete语句删除,但是configurable属性好像在严格模式下才有效,这样的代码在非严格模式下仍然能执行:

 

Object.defineProperty(myobj.prototype,'length',{configurable:false});var obj = new myobj();delete obj.length; 

 3、Object.defineProperty

value:指定该对象的固定值。value:10,表示这个对象初始值为10.

(注意:不要在IE8以下使用该类特性)

在非严格模式下,这样的代码不会报错,严格模式下会报错:

 

Object.defineProperty(myobj.prototype,'length',{writable:false,value:'10'});var obj = new myobj();obj.length = 100; 

微软:将属性添加到对象,或修改现有属性的特性。

可以用getOwnPropertyDescriptor来获取并修改这些值,比如说,现在我的length属性是只读的。

getter、setter,

运行这样的代码,结果却报错了:

其实js中对于对象的属性也有getter和setter函数,不过个人觉得js中的getter和setter更像C#一些。

Object.defineProperty(myobj.prototype,'length',{value:,writable:false,});var descriptor = Object.getOwnPropertyDescriptor(myobj.prototype, "length");descriptor.writable = true;Object.defineProperty(myobj.prototype,'length',descriptor); Uncaught TypeError: Cannot redefine property: length

例如下面的代码就定义了一个getter/setter:

这是因为configurable的默认值是false,在调用了defineProperty之后,configurable就具有false属性,这样就不能逆转了。以后就不能改了。

            function myobj(){

            }
            Object.defineProperty(myobj.prototype,'length',{
                get:function(){
                    return this.length_; //这里不能是length。
                },
                set:function(value){
                    return this.length_=value;
                }

            });

所以必须使用 configurable:true,这个对象属性才是可以修改的,完整的代码如下:

注释的地方不能是length,否则会无限递归。

Object.defineProperty(myobj.prototype,'length',{value:,writable:false,configurable:true});var descriptor = Object.getOwnPropertyDescriptor(myobj.prototype, "length");descriptor.writable = true;Object.defineProperty(myobj.prototype,'length',descriptor);myobj.prototype.length = ;var obj = new myobj; 

 

可以加上一句descriptor.configurable = false;

也可以去掉set,让length变量只读。

表示这个属性我修改了,以后你们都不能再修改了

            Object.defineProperty(myobj.prototype,'length',{
                get:function(){
                    return this.length_; //这里不能是length。
                }, 
                /*set:function(value){
                    return this.length_=value;
                }*/

            });
            myobj.length = 3;

这个特性在很多时候也有用,数组Array的push pop等方法,如果使用call、apply,要求对象的length可变。如果对象的length属性只读,那么调用call、apply时,会抛出异常。

这个代码会抛出异常:Uncaught TypeError: Cannot set property length of #<myobj> which has only a getter。

就比如DOMTokenList对象,它的length就是不可以变的。我拿到了一个DOM对象DOMTokenList,

 

但是它的configurable是true,我们可以修改让它的length属性可以变啊:

要让对象的属性只读,还可以用writable:false,

返回顶部