原生方法系列(查缺补漏 不断更新)

Function.call   Function.apply

将其他对象的方法"借用"在自己身上用(this)    Function.call 和Function.apply的行为非常相似  只不过是Function.call接受的参数列表 Function.apply接受的是参数数组

    var friend = {
         food:0,
            eat:function(amount,money) {
                this.food = amount;
                console.log(money);
            }
        }//friend对象有一个eat方法  设置自己的food属性 并且输出相应的money
        var me = {
            food:0,
            isHungry:function() {
                return this.food < 100;
            }
        }  //me只有一个根据food值判断是否饥饿的方法 me很懒 想使用朋友的eat方法(可以理解为喂我吃) 通过this的绑定eat方法中的this指向了我 所以我不在饥饿了

        console.log(me.isHungry());
        friend.eat.call(me,100,"120");  //call 接受参数列表
        console.log(me.isHungry());
        friend.eat.apply(me,[100,"120"]); //apply 接受参数数组
        console.log(me.isHungry()); 

 生成对象的三种方法

对象字面量 

  

    var dog = {
            name:"ha",
            say:function() {
                return "wang";
            }
        }
    dog.age = 9;
    console.log(dog.age) //9

其实可以理解为对象字面量是Object.create()的一种快捷调用  

        var dog = Object.create(Object.prototype,{
            name:{
                value:"sss"
            },
            say:{
                value:function() {
                    return "wang";
                }
            }
        });

        console.log(dog.say()); //wang  //会在下面介绍Object.create()


这种方式是创建简单的一次性对象的最佳选择  

new Object()    

        var dog = new Object({
            name:"haha",
            say:function() {
                return "wang";
            }
        });

        console.log(dog.say());//wang 

通过原生对象的构造函数进行对象的创建     注意原生对象的构造函数是属于全局命名空间的 也就是通过winow.Object能获取到这个构造函数(有可能被修改了)

Object.create(args1,args2)   第一个参数是提供原型的对象  第二个参数是提供可选属性的对象   Object.create() 提供了new操作符的优点

        var person = {
            getOld:function() {
                this.age = this.age + 10;
                return this.age;
            }
        }
          var haha = Object.create(person,{
              age:{
                  value:10,
                  writable:true
              }
          });
          console.log(haha.getOld());  //20

第二个参数可选属性对象相应的属性配置需要配置 否则 默认为false  就是不可修改 不可以枚举 

window.getComputedStyle(元素,伪类)  第二个参数不是必须的   使用这个方法可以获得当前元素所有使用的最终的CSS属性值  返回一个样式声明对象  它是一个只读的对象 

对比 element.style   element.style 也能获得一个元素的样式声明对象  但是element.style只能获取元素style属相里面设置的css属性  但是element.style 是可以读写的

在老版本的IE上是不支持window.getComputedStyle()这个方法的 可以使用element.currentStyle  它同样是一个只读的对象  我在IE11 上window.getComputedStye()  element.currentStyle 都支持     

2016 3 13  发现在chrome中并不支持element.currentStyle  也就是这玩意还是个IE搞特殊化的东西

要获取我们获得的样式声明对象obj(无论是通过window.getComputedStyle() 或者 element.currentStyle获取的)   可以通过 obj.attrName 或者   obj['attrName']  这样的方式获取  

但是在不同的浏览器下同样的属性  attrName 的定义又有可能不同    通用的方法是  使用getPropertyValue('attrName')     (不支持驼峰  获取background-color   getPropertyValue('background-color'))

element.getBoundingClientRect()   返回一个对象  里面包含六个属性 元素的width height   元素的上下左右相对于浏览器窗口的距离      仔细理解上下左右相对于浏览器窗口的位置

我们可以通过这个方法获取元素的当前的位置   通过以下这样的方式

      var interval = setInterval(function(){
        var rectObj = b.getBoundingClientRect();
        var x = rectObj.left + document.documentElement.scrollLeft;
        var y = rectObj.top + document.documentElement.scrollTop;
     //  当前元素距离窗口的位置  + 当前滚动条的位置  
        console.log('当前x坐标' + x  + ' 当前的y坐标 ' + y);



      },3000);  //这样拖动滚动条也能得到正确的元素的位置
2016 3 13 这里的top left bottom right 是没有单位的

element.getClientRects()    该方法返回一个TextRectangle集合 也就是TextRectangleList对象  每一个TextRectangle包含 top right bottom left width height 6个属性  TextRectangl是针对文本区域的一个描述    也就是该方法只能在inline的文本元素上使用  (这里的top right bottom left 也是相对于浏览器窗口的位置)

      <div id="test">
         <span   id="b">sdadasda  dadasd  sadadad
        </span>
      </div>

对于上面的页面结构  在页面上是这样显示的(由于空格的作用 和 外层div 的限制  文本形成了 3行 )

形成了3个文本区域  也就是3个TextRectangle对象   这三个TextRectangle对象形成了一个TextRectangleList集合

      var span = document.getElementById('b');
      var list = span.getClientRects();
      var length = list.length;
      console.log(length);//3

通过length我们就可以判断文字是否换行 并且换了几行  在结合鼠标的位置 就可以判断鼠标停留在哪行了

      var span = document.getElementById('b');
      var list = span.getClientRects();
      var length = list.length;
      console.log(length);

      span.onclick = function(event) {
        var i;
        var mouseY = event.clientY;
        var mouseX = event.clientX;
        for(i = 0;i < length;i++) {
          if( mouseY >= list[i].top  && mouseY <= list[i].bottom && mouseX >= list[i].left && mouseX < list[i].right) 
          {
            console.log(i);
          }

          
        }
      }   // 上面的例子就可以通过判断测试出鼠标点击的是哪行  

element.addEventListener(event,handler,useCapture) 

event  必须   需要监听的时间    例如 click 

handler  必须  监听时间发生后的处理函数  

useCapture 可选  布尔值  指定事件是在捕获或者冒泡阶段执行     true 捕获阶段执行    false 冒泡阶段执行  默认false

我们可以为一个事件添加多个处理程序

        var btn = document.getElementById('btn');
        function a() {
            console.log('a');
        }

        function b() {
            console.log('b');
        }
        btn.addEventListener('click',a);
        btn.addEventListener('click',b);

上面的例子中我们为click事件添加了两个事件处理程序  当点击页面中的btn的时候 两个事件监听程序都进行了处理 并且是按照绑定的先后顺序进行事件的处理的

element.removeEventListener(event,hadler)  例如上面的例子  我们可以通过下面的语句移除事件监听程序

btn.removeEventListener('click',a);

**通过匿名函数绑定的事件无法移除**    (因为我们再次传入的handler并不是同一个函数)

有时候我们不想定义函数的声明   也就是想要通过匿名函数的方式去绑定事件处理程序 

        var btn = document.getElementById('btn');
        
        var handler = function () {
            console.log(1);
        }
        btn.addEventListener('click',handler);
        btn.removeEventListener('click',handler);   //也就是两个handler要指向同一个函数

关于添加事件监听的跨浏览实现  请参考我的另一篇blog   js事件小记  

下面这种情况也许不大常见 我们想移除上面绑定的事件处理程序怎么操作呢

        var btn = document.getElementById('btn');
        function a() {
            console.log(1);
        }
        function b() {
            console.log(2);
        }
        btn.addEventListener('click',a);
        btn.addEventListener('click',b);
        btn.addEventListener('click',function test() {
            console.log(3);//加断点
        })        

在这个例子我们在click事件上绑定了有函数声明的函数 和 有名的匿名函数  (我的理解是外界无法取到它的引用  而且我们使用匿名函数的时候 也最好给它一个名字   这样在控制台调试的时候通过堆栈的调用能查看我们调用的函数)  上面的例子中我在标注出加了断点  

可以看出它调用了test函数   回归正题    对于这种情况 我们要移除绑定的事件监听程序呢(里面还有一个万恶的匿名函数)   首先是可以通过一个一个的removeEventListener()来进行的(对于匿名函数没有办法)  我们可以通过cloneNode()的方法  对要移除事件的元素进行复制  在复制的时候不会保留上面绑定的事件监听程序 并且匿名函数也移除了    下面是简单的实现

        var new_btn = btn.cloneNode(true);
        btn.parentNode.replaceChild(new_btn,btn); //通过这种方式上面绑定的事件监听程序都移除了
原文地址:https://www.cnblogs.com/tiantianwaigong/p/5194612.html