js未命题(杂记)

//记一段JavaScript 高性能的优化笔记;

function collectionGlobal() {
 var coll = document.getElementsByTagName_r('div'),
 len = coll.length, //缓存动态collection的length
 name = '';
 for (var count = 0; count < len; count++) {
 name = document.getElementsByTagName_r('div')[count].nodeName;
 name = document.getElementsByTagName_r('div')[count].nodeType;
 name = document.getElementsByTagName_r('div')[count].tagName;
 }
 return name;
};
// faster
function collectionLocal() {
 var coll = document.getElementsByTagName_r('div'),
 len = coll.length,  //缓存动态collection的length
 name = '';
 for (var count = 0; count < len; count++) {
 name = coll[count].nodeName; //使用缓存的coll 集合,
 name = coll[count].nodeType;
 name = coll[count].tagName;
 }
 return name; 
};
// fastest
function collectionNodesLocal() {
 var coll = document.getElementsByTagName_r('div'),
 len = coll.length, //缓存动态collection的length
 name = '',
 el = null;
 for (var count = 0; count < len; count++) {
 el = coll[count]; //访问变量的速度要比访问 集合快
 name = el.nodeName;
 name = el.nodeType;
 name = el.tagName;
 }
 return name;
};

彻底领悟,js面向对象:http://www.admin10000.com/document/13628.html 

http://doc.pfan123.com/

//这了,我们在复习js中的自定义事件地呀;

与自定义事件的函数有 Event、CustomEvent 和 dispatchEvent。

//直接自定义事件,使用 Event 构造函数:

var event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);

// Dispatch the event.
elem.dispatchEvent(event);

CustonEvent

CustomEvent 可以创建一个更高度自定义事件,还可以附带一些数据,具体用法如下:

var myEvent = new CustomEvent(eventname, options);

其中options可以是:

{
    detail: {
        ...
    },
    bubbles: true,
    cancelable: false
}

其中 detail 可以存放一些初始化的信息,可以在触发的时候调用。其他属性就是定义该事件是否具有冒泡等等功能。

dispatchEvent

这个用于触发自定义的事件。

 http://www.admin10000.com/document/6089.html

jq 中阻止事件冒泡和默认行为的方法;

1.event.stopPropagation(); 
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转) 
2.returnfalse; 
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转) 
还有一种有冒泡有关的: 
3.event.preventDefault(); 
如果把它放在头部A标签的click事件中,点击“点击我”。 
会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度 
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接

 绑定事件时的回调函数不能是匿名函数,必须是一个声明的函数,因为解除事件绑定时需要传递这个回调函数的引用,才可以断开绑定。

关于数组类型的数据判断,在我们的js中一直是一个比较难的话题,具体的可以参考我们的:http://www.cnblogs.com/xiaohuochai/p/5680833.html(js中完善的数组类型的判断滴滴呀) 

js  中数据类型的判断;

在 js 里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种。对于数组、函数、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串。

要想区别对象、数组、函数单纯使用 typeof 是不行的,javascript中,通过Object.prototype.toString方法,判断某个对象值属于哪种内置类型。常常使用Object.prototype.toString()来进行类型识别,返回代表该对象的[object 数据类型]字符串表示

[注 意]Object.prototype.toString()可以识别标准类型及内置对象类型,但不能识别自定义类型

console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]

console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/d/));//[object RegExp]
function Person(){};
console.log(Object.prototype.toString.call(new Person));//[object Object]

我们可进行一个简单封装;

function type(obj){
    return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();
}

还可以进行其他类型的基本识别滴呀;

(function(){
    console.log(Object.prototype.toString.call(arguments));//[object Arguments]
})()
console.log(Object.prototype.toString.call(document));//[object HTMLDocument]

函数Function类型返回函数代码

 当我们对一个自定义函数调用toString()方法时,可以得到该函数的源代码;如果对内置函数使用toString()方法时,会得到一个'[native code]'字符串。因此,可以使用toString()方法来区分自定义函数和内置函数

function test(){
    alert(1);//test
}
test.toString();/*"function test(){
                    alert(1);//test
                  }"*/
Function.toString();//"function Function() { [native code] }"

如果存在任意原始值,它就默认将对象转换为表示它的原始值;对象是复合值,而大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值

      toString()和valueOf()的主要不同点在于,toString()返回的是字符串,而valueOf()返回的是原对象

  2、由于undefined和null不是对象,所以它们toString()和valueOf()两个方法都没有

  3、数值Number类型的toString()方法可以接收转换基数,返回不同进制的字符串形式的数值;而valueOf()方法无法接受转换基数

  4、时间Date类型的toString()方法返回的表示时间的字符串表示;而valueOf()方法返回的是现在到1970年1月1日00:00:00的数值类型的毫秒数

  5、包装对象的valueOf()方法返回该包装对象对应的原始值

  6、使用toString()方法可以区分内置函数和自定义函数

js 操作dom的一些基本练习;

 js实现简单的额两级联动菜单的使用;

<select id="province">
    <option value="0">--请选择--</option>
    <option value="1">北京</option>
    <option value="2">重庆</option>
</select>
 
城市:<select id="city">
    <option>--请选择--</option>
</select>

<script type="text/javascript">

//这是一个动态的级联操作;
//这的东西可以实时的从数据库中去取,取出来之后,缓存在我们也地呀;
//页面加载的时候,就用去加载数据了的呀;
var province=document.getElementById("province");
var city=document.getElementById("city");
var arr=new Array();
    arr[1]=new Array("海淀","昌平","西城");
    arr[2] = new Array("沙坪坝","万州","南岸");
window.onload=function (){
    province.onchange=function (){
      //当改成省份的时候,需要清空之前的数据;
       city.options.length=1;
       //从数据中取出值地呀;
       var selected=arr[this.value];
       var len=selected.length;
       //然后添加到我们的city中去地呀;
       for(let i=0;i<len;i++){
         city.add(new Option(selected[i],selected[i])); 
       }
     }  
}

js 操作dom练习,之,table表格的操作;(js操作table列,这种做法是很初级的,简直就是demo级别的,无法应用在实际的生产中滴呀)

 当然,你也可以不用通过创建节点的方式来操作,可使用我们innerHTML 的方式来实现滴呀;

姓名:<input type="text" id="name" /> <br />
联系方式:<input type="text" id="email" /> <br />
年龄:<input type="text" id="age" /> <br />
<input type="button" value="添加用户" onclick="addLine()"/> <br />
<br /><br /><hr /><br />
<table id="userTable" align="center" border=1 cellspacing=0 cellpadding=5 width="50%">
    <tr>
        <th>姓名</th>
        <th>联系方式</th>
        <th>年龄</th>
        <th>操作</th>
    </tr>
    <tr>
        <td id="en">大哥</td>
        <td>fda@fd.com</td>
        <td>15</td>
        <td>
            <input type="button" value="删除" onclick="delLine(this)" />
        </td>
    </tr>
</table>


<script type="text/javascript">

//第一种实现方式;xml dom 方式;
//这个是最基本的额写法,有种意义对应的方式滴呀;会看到很多的重复代码,当我后面吧面向对象的方式
//学习了之后,我会尝试用oo的方式进行封装滴呀;


// 这里有太多额重复代码了,后期我进行一定程度的优化滴呀;

 function bind(fn,context){
   return function (){
        return fn.apply(context,arguments);
   }
 }


// 好吧,基本的删除事件是完成了滴呀; table 的基本操作地呀;
function addLine(){
   var name=document.getElementById("name").value;
   var email=document.getElementById("email").value;
   var age=document.getElementById("age").value;
   var table=document.getElementById("userTable");
   var tr=document.createElement("tr");

   // 节点操作;
    var tdNode1 = document.createElement("td");
    var textNode1 = document.createTextNode(name);
    tdNode1.appendChild(textNode1);

     var tdNode2 = document.createElement("td");
     var textNode2 = document.createTextNode(email);
     tdNode2.appendChild(textNode2);

    var tdNode3 = document.createElement("td");
    var textNode3 = document.createTextNode(age);
    tdNode3.appendChild(textNode3);

    //创建删除按钮;
    var tdNode4 = document.createElement("td");
    var btn=document.createElement("input");
        btn.type="button";
        btn.value="删除";
        //可用这种方式来添加事件滴呀‘
        //btn.setAttribute("onclick", "javascript:alert('This is a text!');");    
        btn.setAttribute("onclick", "delLine(this)");    
        //btn.onclick=bind(delLine,btn);
        tdNode4.appendChild(btn);

        tr.appendChild(tdNode1);
        tr.appendChild(tdNode2);
        tr.appendChild(tdNode3);
        tr.appendChild(tdNode4);

        table.appendChild(tr);
   
}
//删除的方法;
function delLine(thisObj){
   trNode=thisObj.parentNode.parentNode;//tr
   trNode.parentNode.removeChild(trNode);
}

我们也可以这样写滴呀;

 btn.onclick=function (){
     delLine(this);
 }

 

操作方式二:

//同样,我们可以这样写,和改造滴呀;
function addLine2(){
     
   var name=document.getElementById("name").value;
   var email=document.getElementById("email").value;
   var age=document.getElementById("age").value;
   var table=document.getElementById("userTable");
   
  //还有这种神奇的做法滴呀;效果还算比较理想滴呀;小
   var tr=table.insertRow(table.rows.length);
       tr.innerHTML = "<td>"+name+"</td><td>"+email+"</td><td>"+age+"</td><td>"+
        "<input type='button' value='删除' onclick='delLine(this)' />   </td>";
}

 //不写了,下次接着继续:http://www.flyne.org/article/420

(function() {
   var a = b = 5;
})();

console.log(b);

//5

(function() {
   'use strict';
   var a = window.b = 5;
})();

console.log(b);

知识点:立即执行函数,作用域,严格模式

// 在 String 对象上定义一个 repeatify 函数。这个函数接受一个整数参数,来明确字符串需要重复几次。这个函数要求字符串重复指定的次数。举个例子:

// console.log('hello'.repeatify(3));
// 应该打印出 hellohellohello .

 String.prototype.repeatify=String.prototype.repeatify || function (times){
    var result='';
    for(var i=0;i<times;i++){
      str+=this;
    }
    return result;
 }

知识点:原型 怎样避免重写可能已经定义了的方法

function test() {
   console.log(a);
   console.log(foo());
   
   var a = 1;
   function foo() {
      return 2;
   }
}

test();

//这段代码的执行结果是 undefined 和 2 。

(function(a){
    console.log(a);
    var a=10;
    function a(){};
}(100))

//function a(){}

知识点:关于hostting,变量和函数的提升;

console.log(typeof null);  // object
console.log(typeof {});  //object
console.log(typeof []); //object
console.log(typeof undefined); //undefined


//最令人惊讶的输出结果可能是第三个。大多数开发人员认为 typeof [] 会返回 //Array 。如果你想测试一个变量是否为数组,您可以执行以下测试:

var myArray = [];
if (myArray instanceof Array) {
   // do something...
}

知识点,数据类型;

function printing() {
   console.log(1);
   setTimeout(function() { console.log(2); }, 1000);
   setTimeout(function() { console.log(3); }, 0);
   console.log(4);
}
printing();

想知道为什么输出顺序是这样的,你需要弄了解 setTimeout() 做了什么,以及浏览器的事件循环原理。浏览器有一个事件循环用于检查事件队列,处理延迟的事件。UI事件(例如,点击,滚动等),Ajax回调,以及提供给 setTimeout() 和 setInterval() 的回调都会依次被事件循环处理。因此,当调用 setTimeout() 函数时,即使延迟的时间被设置为 0 ,提供的回调也会被排队。回调会呆在队列中,直到指定的时间用完后,引擎开始执行动作(如果它在当前不执行其他的动作)。因此,即使 setTimeout() 回调被延迟 0 毫秒,它仍然会被排队,并且直到函数中其他非延迟的语句被执行完了之后,才会执行。

有了这些认识,理解输出结果为“1”就容易了,因为它是函数的第一句并且没有使用 setTimeout() 函数来延迟。接着输出“4”,因为它是没有被延迟的数字,也没有进行排队。然后,剩下了“2”,“3”,两者都被排队,但是前者需要等待一秒,后者等待0秒(这意味着引擎完成前两个输出之后马上进行)。这就解释了为什么“3”在“2”之前。

参考链接:http://www.tuicool.com/articles/2MVJBnZ

这是js 的一些代码片段,所以未命题滴呀;

这个,我们先打一个草稿,我们后面再进一步的进行补充;

第一种方式:

function Person(name,age,job){
    //这样写,就限制了,call 和 apply的引用滴哎呀;
     this.name=name;
     this.age=age;
     this.job=job;
     this.show=function (){
      console.log(this.name+"---"+this.job);
     }
}

function son(address){
   this.address=address;
}
var p=new Person("jack",18,"javascript");
son.prototype=p; //这个还要在生成 对象 之前执行 ,,哎,这个都是很基础的啦,原型继承,,
var s=new son("chengdu");

s.show();

第二种方式:

  我曹,这个又涉及到我们得继承了滴呀;

function Person(name,age,job){
    //这样写,就限制了,call 和 apply的引用滴哎呀;
     this.name=name;
     this.age=age;
     this.job=job;
     this.show=function (){
      console.log(this.name+"---"+this.job);
     }
}

function son(name,age,job,address){
   Person.call(this,name,age,job)
   this.address=address;
}

var s=new son("jack",18,"javascript","chengdu");
s.show();

第三种方式:(我们可以在传递参数上)

function Person(name,age,job){
    //这样写,就限制了,call 和 apply的引用滴哎呀;
     this.name=name;
     this.age=age;
     this.job=job;
     this.show=function (){
      console.log(this.name+"---"+this.job);
     }
}

function son(name,age,job,address){
   Person.call(this,...arguments) //不过这个要用到es6的特性;
   this.address=address;
}
var s=new son("jack",18,"javascript","chengdu");
s.show();

这个是我们函数的惰性加载,的两种实现方式,好处就是不用每次调用的时候,都去if else 进行一次的判断滴呀;(反正,我个人觉得是挺秒的一个方法滴呀;效果非常好滴呀;)

对了,这里还得注意一个参数:addEventListener()方法中的第三个参数设置为true时,即为事件捕获阶段

//所谓惰性载入,  指函数执行的分支只会发生一次
//所谓的惰性载入,值函数执行的分支只会执行一次;
function addEvent(type,element,fn){
      if (element.addEventListener){
         addEvent=function (type,element,fn){
           element.addEventListener(type,fun,false)
         }
      }else if(element.attachEvent){
         addEvent=function(type,element,fn){
            element.attachEvent('on'+type,fn);
         }
      }else{
        addEvent=function(type,element,fn(){
            element['on'+type]=fn;
        }
      }
      //返回正确的需要执行的函数滴呀;
      //
      return addEvent(type,element,fn);

      //这样 函数只需要执行一次之后,就能判断,
      //浏览的兼容性,不用重复的判读了滴啊;效果是非常好滴呀;
      // 在这个惰性载入的addEvent()中,if语句的每个分支都会为addEvent变量赋值,有效覆盖了原函数。最后一步便是调用了新赋函数。下一次调用addEvent()时,便会直接调用新赋值的函数,这样就不用再执行if语句了
}

//第二种是声明函数时就指定适当的函数。 这样在第一次调用函数时就不会损失性能了,只在代码加载时会损失一点性能
////  以下就是按照这一思路重写的addEvent()。以下代码创建了一个匿名的自执行函数,通过不同的分支以确定应该使用哪个函数实现
var addEvent=(function (){
    if(document.addEventListener){
       return function (type,element,fn){
          element.addEventListener(type,fn,false);
       }else if(document.addEventListener){
          return function (type,element,fn){
             element.attachEvent('on'+type,fn);
          }
       }else{
         return function (type,element,fn){
             element.['on'+type]=fn;
          }
       }
    }

})();//在第一次执行的时候,就能确定下俩,我们浏览器的兼容性的东西,是怎样滴呀;效果是很好的;

 这些,都是我们函数使用过程的的一些高级技巧滴哎呀;

这个只是一些草稿demo滴呀;

//这个有点老僧长谈了,还不是作用域,编报的问题;
//解决方法有很多呢;
   var a=12;
   var ff={a:11,fn:function (){ alert(this.a)}};
   window.onload=ff.fn;

   window.onload=function (){
        ff.fn(); //这样才是我们想要额基本函数效果滴呀;
   }



var handler={
    msg:"this is fuck life",
    handlerFun:function (){
       alert(this.msg);
    },
    show:function (){
         var _this=this; 
       return function (){
         alert(_this.msg);  
       }
    },
    fuck:function(){
       return ()=>{
          alert(this.msg)
       }
    }
}

var obj=document.getElementById("test");
// obj.onclick=handler.handlerFun;  //错误的释放滴呀; 问题所在之处,


// //解决方法,你懂滴呀;
// obj.onclick=function (){
//    handler.handlerFun();
// }
// //或则这样;

// obj.onclick=handler.show();
  obj.onclick=handler.fuck();

顺便来不洗一下我们的箭头函数:

/箭头函数的出现,效果是非常好滴呀;
// 而箭头函数的出现就可以很好的解决该问题。箭头函数根据当前的词法作用域而不是根据this机制顺序来决定this,所以,箭头函数会继承外层函数调用的this绑定,而无论this绑定到什么

var test = () => {
    console.log(this.a);
}
//形式上等价于
var test = function(){
    console.log(this.a);
}
//实质上等价于
function fn(){
    var that = this;
    var test = function(){
        console.log(that.a);
    }
}

  function f(){
    console.log(this===window);
  }
  function fx(){
    'use strict'
    console.log(this===window);
  }
   
   var test = () => {
    console.log(this===window);
   }
   var test1 = () => {
    'use strict'
    console.log(this===window);
   }
   var test2=function (){
     'use strict'
     console.log(this===window);
   }
   f(); //true
   fx(); //false
   test(); //true
   test1();//true
   test2();//false 滴呀;

      var timer0=function(){
       setTimeout(function (){
          console.log(this.msg)
       },3000)
   }

   var timer1=function(){
         var _this=this;
       setTimeout(function (){
          console.log(_this.msg)
       },4000)
   }


   var timer2=function(){
         var _this=this;
       setTimeout(()=>{
          console.log(this.msg)
       },5000)
   }


   var timer={
    msg:"fuck life",
    timer0:timer0,
    timer1:timer1,
    timer2:timer2,
   };
   timer.timer0(); //undefined
   timer.timer1(); //fuck life
   timer.timer2(); //fuck life
//这个函数似乎简单,但其功能是非常强大的。在bind()中创建了一个闭包,闭包使用apply()调用传入的函数,并给apply()传递context对象和参数。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数
 function bind(fn,context){
   return function (){
        return fn.apply(context,arguments);
   }
 }

接着上面的话题,再来看我们想要的效果,这个,还是挺好滴呀;

 function bind(fn,context){
    return function(){
        return fn.apply(context,arguments);  //这里为啥一定要return呢,不return也能事项相同的效果滴哎呀;
    }
}          
var handler={
    message:"Event handled.",
    handlerFun:function(){
        alert(this.message);
    }
};

var obj=document.getElementById("test");
// obj.onclick=bind(handler.handlerFun,handler);

// obj.onclick=function (){
//         return  handler.handlerFun.call(handler); //返回一个可执行(立即执行的函数)
// }
//或则,这样,我曹;
obj.onclick=function(){
  handler.handlerFun();
}

这里还有一些关于js事件代理的实例方法滴呀;

    由于事件会在事件冒泡向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation),也叫事件委托

  事件代理应用事件目标的target和srcElement属性完成。利用事件代理,可以提高性能及降低代码复杂度

  有一个需求,一个<ul>中有5个<li>,移入时变浅蓝,移出时变品红

  下面分别用常规方法和事件代理方法来实现

<style>
#box{background-color: pink;}
.in{height: 30px;}
</style>
<ul id="box">
    <li class="in">1</li>
    <li class="in">2</li>
    <li class="in">3</li>
    <li class="in">4</li>
    <li class="in">5</li>
</ul>
<script>
//常规方法
var tags = box.getElementsByTagName('li');
for(var i = 0; i < tags.length; i++){
    tags[i].onmouseover = function(e){
        this.style.backgroundColor = 'lightblue';
    }
    tags[i].onmouseout = function(e){
        this.style.backgroundColor = 'pink';
    }
}
</script>

<script>
//事件代理方法
box.onmouseover = function(e){
    e = e || event;
    var target = e.target || e.srcElement;
    target.style.backgroundColor = 'lightblue';
}
box.onmouseout = function(e){
    e = e || event;
    var target = e.target || e.srcElement;
    target.style.backgroundColor = 'pink';
}
</script>

 阻止事件冒泡 和 默认的事件的兼容性写法,效果很好滴哎呀

//阻止事件冒泡的兼容性写法

function stopBubble(e) {
    // 如果提供了事件对象,则这是一个非IE浏览器
    if ( e && e.stopPropagation ) {
        // 因此它支持W3C的stopPropagation()方法 
        e.stopPropagation();
    } else { 
        // 否则,我们需要使用IE的方式来取消事件冒泡
        window.event.cancelBubble = true;
    }
}

//阻止默认事件的 兼容性写法;
function stopDefault( e ) {
     // 阻止默认浏览器动作(W3C)
     if ( e && e.preventDefault ) {
         e.preventDefault();
     } else {
        // IE中阻止函数器默认动作的方式
        window.event.returnValue = false;
    }
    return false;
}
function clicked(event) {
    stopDefault(event);
    alert("我阻止了点击A标签的默认事件");
}
var handler = function(e){
    e = e || event;
    if(e.stopPropagation){
        e.stopPropagation();
    }else{
        e.cancelBubble = true;
    }
}

defaultPrevented 属性表示默认行为是否被阻止; 返回true表示阻止,返回false表示表示没有阻止;

注意,ie8 不支改属性;我曹;

阻止,默认行为的方式一(两种方式):

<a id="a0" href="http://www.cnblogs.com" target="_blank">链接</a>

<a id="a1" href="http://www.cnblogs.com" onclick="return false;" target="_blank">链接</a>

<script type="text/javascript">

var a=document.getElementById("a0");
a.onclick=function (){

  return false;  ///这届通过returnfalse 也可以阻止我们额默认行为;
}
</script>

还有就是我们的returnValue 属性,是可读写的,默认是我们的true,将起设置为false,可以取消默认的行为,但是他们的 firefox 和 ie9 不支持;

preventDefault() 方法取消浏览器对当前事件的默认行为,无返回值,但是他妈的ie8 又不支持,所有就有了我们的兼容性写法滴呀;效果还是挺不错滴呀;

var handler=function (e){
    var e=e|| event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
       e.returnValue=false;
    }
}

cancelable

  cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性。返回true时,表示可以取消。否则,表示不可取消。

总结:

     1、在DOM0级事件处理程序中取消默认行为,使用returnValue、preventDefault()和return false都有效

  2、在DOM2级事件处理程序中取消默认行为,使用return false无效

  3、在IE事件处理程序中取消默认行为,使用preventDefault()无效

关于input中的value的一点点

。如果是一个表单元素,则它的作用域链是 this -> this.form -> document 。先从<input type="button">对象中寻找username属性,发现没有。然后找到它的父级form,form的username可以找到<input type="text">元素(表单元素可以直接通过name值访问),然后找到其value值123后弹出

原文地址:https://www.cnblogs.com/mc67/p/6913931.html