Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产91精品久久久久999,特黄特色一级特色大片中文,亚洲精品白色在线发布

          整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          10分鐘搞定Java實(shí)現(xiàn)郵箱驗(yàn)證,坦率講,別被他人割

          10分鐘搞定Java實(shí)現(xiàn)郵箱驗(yàn)證,坦率講,別被他人割韭菜

          率講郵箱驗(yàn)證功能應(yīng)該大多數(shù)人都使用過(guò),比如:對(duì)用戶賬號(hào)密碼進(jìn)行找回,注冊(cè)某網(wǎng)站以郵箱作為登錄名激活賬號(hào).....等多個(gè)應(yīng)用場(chǎng)景都需要我們通過(guò)郵件進(jìn)行驗(yàn)證。此篇教程就是講解如何用Java實(shí)現(xiàn)郵箱驗(yàn)證功能,10分鐘就搞定了,簡(jiǎn)單得一匹!

          在日常生活中,我們?cè)谝粋€(gè)網(wǎng)站中注冊(cè)一個(gè)賬戶時(shí),往往在提交個(gè)人信息后,網(wǎng)站還要求我們通過(guò)手機(jī)或郵件來(lái)驗(yàn)證,郵件的話大概會(huì)是下面這個(gè)樣子的:

          用戶通過(guò)點(diǎn)擊鏈接從而完成注冊(cè),然后才能登錄。也許你會(huì)想,為什么要這么麻煩直接提交注冊(cè)不就行了嗎?這其中很大一部分原因是為了防止惡意注冊(cè)。接下來(lái)讓我們一起來(lái)使用最簡(jiǎn)單的JSP+Servlet的方式來(lái)完成一個(gè)通過(guò)郵箱驗(yàn)證注冊(cè)的小案例吧。

          準(zhǔn)備工作

          1、了解相關(guān)協(xié)議:動(dòng)手實(shí)踐之前,你最好對(duì)JSP、Servlet、SMTP協(xié)議POP3協(xié)議知識(shí)有所了解,如果對(duì)郵件收發(fā)過(guò)程完全不了解的話,可以花點(diǎn)時(shí)間仔細(xì)看一下如下圖:

          2、郵箱授權(quán)準(zhǔn)備:在了解的上述內(nèi)容之后,要實(shí)現(xiàn)這個(gè)案例,首先我們還得有兩個(gè)郵箱賬號(hào),一個(gè)用來(lái)發(fā)送郵件,一個(gè)用來(lái)接收郵件。本案例使用QQ郵箱向163郵箱發(fā)送激活郵件,因此需要登錄QQ郵箱,在設(shè)置->賬戶面板中開(kāi)啟POP3/SMTP服務(wù),以允許我們通過(guò)第三方客戶端發(fā)送郵件:進(jìn)入發(fā)件人郵件空間 -> 設(shè)置 -> 賬戶 –> 開(kāi)啟(POP3/SMT)服務(wù) 注意:僅限QQ郵箱

          圖一

          圖二

          圖三

          還要注意的是,登錄以下服務(wù): POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務(wù)時(shí),需要用到授權(quán)碼而不是QQ密碼,授權(quán)碼是用于登錄第三方郵件客戶端的專(zhuān)用密碼。因此我們需要獲得授權(quán)碼,以在后面的程序中使用。

          3、需要一個(gè)jar包:mail-1.4.7.jar

          下載地址:https://mvnrepository.com/artifact/javax.mail/mail/1.4.7

          Demo代碼實(shí)現(xiàn)

          具體步驟如下:

          1. 首先創(chuàng)建一個(gè)web工程,并加入相關(guān)依賴包:

          mail-1.4.7.jar 下載地址:https://mvnrepository.com/artifact/javax.mail/mail/1.4.7

          2. 使用MySQL創(chuàng)建一張簡(jiǎn)單的用戶表:t_user

          create table t_user(
              id int(11) primary key auto_increment comment '用戶id',
              userName varchar(100) not null comment '用戶名',
              userEmail varchar(100) not null comment '用戶郵箱',
              userPwd varchar(50) not null comment '用戶密碼',
              state int(1) not null default 0 comment '用戶激活狀態(tài):0表示未激活,1表示激活',
              code varchar(255) not null comment '激活碼'
          );

          PS:state字段(用來(lái)判斷用戶賬號(hào)是否激活)和code字段(激活碼)

          3. 創(chuàng)建一個(gè)注冊(cè)頁(yè)面

          使用JSP創(chuàng)建一個(gè)最簡(jiǎn)單的注冊(cè)頁(yè)面(過(guò)于簡(jiǎn)單,代碼省略):

          頁(yè)面效果

          4. 注冊(cè)業(yè)務(wù)邏輯分析

          1、用戶填寫(xiě)相關(guān)信息,點(diǎn)擊注冊(cè)按鈕

          2、系統(tǒng)先將用戶記錄保存到數(shù)據(jù)庫(kù)中,其中用戶狀態(tài)為未激活

          3、系統(tǒng)發(fā)送一封郵件并通知用戶去驗(yàn)證

          4、用戶登錄郵箱并點(diǎn)擊激活鏈接

          5、系統(tǒng)將用戶狀態(tài)更改為已激活并通知用戶注冊(cè)成功

          .................搞清楚了整個(gè)流程,實(shí)現(xiàn)起來(lái)應(yīng)該就不難了...................

          項(xiàng)目目錄結(jié)構(gòu)

          通過(guò)JavaMail發(fā)送郵件,具體代碼如下:

          public class Constants {
              public static final int CODE_STATUS_EXPIRED=400;//驗(yàn)證碼過(guò)期或者沒(méi)有點(diǎn)擊發(fā)送驗(yàn)證碼
              public static final String SEND_EMAIL_ACCOUNT="2921272303@qq.com";//發(fā)件人郵箱賬號(hào)
              public static final String SEND_EMAIL_CODE="arnsutissvofzfdshj";//授權(quán)碼(自己的)
          }
          public class UserServiceImpl implements UserService {
              private UserDao userDao=new UserDaoImpl();
              @Override
              public int addUser(Users users) {
                  //注冊(cè)生成唯一標(biāo)識(shí)符
                  String code=UUID.randomUUID().toString().replaceAll("-","");
                  try {
                      String newpwd=MD5.getMD5(users.getUser_pwd()).toString();
                      users.setUser_pwd(newpwd);
                      users.setCode(code);
                  } catch (NoSuchAlgorithmException e) {
                      e.printStackTrace();
                  }
                  int result=userDao.addUser(users);
                  if(result > 0){//注冊(cè)成功
                     //獲取發(fā)送郵件對(duì)象
                     EmailUtil emailUtil=new EmailUtil(users.getUser_email(),code);
                    //發(fā)起郵箱驗(yàn)證
                     new Thread(emailUtil).start();
                  }
                  return result;
              }
          }
          
          
          
          package com.cnlm.utils;
          import com.sun.mail.util.MailSSLSocketFactory;
          import javax.mail.*;
          import javax.mail.internet.AddressException;
          import javax.mail.internet.InternetAddress;
          import javax.mail.internet.MimeMessage;
          import java.security.GeneralSecurityException;
          import java.util.Properties;
          import java.util.UUID;
          /**
           * Created with IntelliJ IDEA.
           * User: cnlm
           * Date: 2020/09/014 22:30
           * Description: JavaMail發(fā)送郵件工具類(lèi)
           * QQ郵箱賬戶為發(fā)送方,首先需要進(jìn)入QQ郵箱,找到左上方的設(shè)置,然后選擇賬戶,找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務(wù),開(kāi)啟pop3,獲得授權(quán)碼
           * Version: V1.0
           */
          public class EmailUtil implements Runnable{
              private String receiveEmail;             // 收件人郵箱
              private String uuidCode;              // uuid唯一激活碼
              public EmailUtil(String receiveEmail, String uuidCode) {
                  this.receiveEmail=receiveEmail;
                  this.uuidCode=uuidCode;  // 生成唯一隨機(jī)碼;
              }
          
              @Override
              public void run() {
                   // 1.創(chuàng)建連接對(duì)象javax.mail.Session
                  // 2.創(chuàng)建郵件對(duì)象 javax.mail.Message
                  // 3.發(fā)送一封激活郵件
                  String host="smtp.qq.com"; // 指定發(fā)送郵件的主機(jī)smtp.qq.com(QQ)|smtp.163.com(網(wǎng)易)
                  Properties properties=System.getProperties();// 獲取系統(tǒng)屬性
                  properties.setProperty("mail.smtp.host", host);// 設(shè)置郵件服務(wù)器
                  properties.setProperty("mail.smtp.auth", "true");// 打開(kāi)認(rèn)證
                  //QQ郵箱需要下面這段代碼,163郵箱不需要
                  try {
                      //QQ郵箱需要下面這段代碼,163郵箱不需要
                      MailSSLSocketFactory sf=new MailSSLSocketFactory();
                      sf.setTrustAllHosts(true);
                      properties.put("mail.smtp.ssl.enable", "true");
                      properties.put("mail.smtp.ssl.socketFactory", sf);
          
                      // 1.獲取默認(rèn)session對(duì)象
                      Session session=Session.getDefaultInstance(properties, new Authenticator() {
                          public PasswordAuthentication getPasswordAuthentication() {
                               // 發(fā)件人郵箱賬號(hào)、授權(quán)碼
                              return new PasswordAuthentication(Constant.SEND_EMAIL_ACCOUNT, Constant.SEND_EMAIL_CODE);
                          }
                      });
                      // 2.創(chuàng)建郵件對(duì)象
                      Message message=new MimeMessage(session);
                      // 3.設(shè)置發(fā)件人
                      message.setFrom(new InternetAddress(Constant.SEND_EMAIL_ACCOUNT));
                     // 4.設(shè)置收件人
                      message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiveEmail));
                      // 5.設(shè)置郵件主題
                      message.setSubject("賬號(hào)激活");
                      String content="<html><head></head><body>" +
                              "<h1>這是一封激活郵件,激活請(qǐng)點(diǎn)擊以下鏈接</h1><h3>" +
                              "<a href='http://localhost:8080/register/checkRegister.do?code="
                              + uuidCode + "'>http://localhost:8080/register/checkRegister.do?code=" + uuidCode
                              + "</a></h3></body></html>";
                      message.setContent(content, "text/html;charset=UTF-8");
                      // 7.發(fā)送郵件
                      Transport.send(message);   // 阻塞方法
                      System.out.println("郵件成功發(fā)送!");
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }

          PS:自己測(cè)試時(shí)需修改賬號(hào)與授權(quán)碼。

          完成后,再有用戶提交注冊(cè)信息時(shí),應(yīng)該就能收到驗(yàn)證郵件了。用戶點(diǎn)擊鏈接后,我們要做的工作就是根據(jù)code(利用UUID生成)更改數(shù)據(jù)庫(kù)中相應(yīng)用戶的狀態(tài),然后提示用戶注冊(cè)結(jié)果了。

          最后總結(jié):

          簡(jiǎn)單介紹了如何使用JavaMail完成了一個(gè)帶郵箱驗(yàn)證的注冊(cè)案例,當(dāng)然在實(shí)際開(kāi)發(fā)中還有許多細(xì)節(jié)要注意,例如對(duì)用戶提交信息的校驗(yàn),密碼進(jìn)行加密等,此處的簡(jiǎn)單案例并未詳盡處理這些細(xì)節(jié)。

          學(xué)會(huì)了嗎?誰(shuí)在最需要的時(shí)候輕輕拍著我肩膀,誰(shuí)在最快樂(lè)的時(shí)候愿意和我分享。我是一個(gè)包夜敲代碼,想靠技術(shù)茍且的程序員。如果覺(jué)得有點(diǎn)用的話,請(qǐng)毫不留情地關(guān)注、點(diǎn)贊、轉(zhuǎn)發(fā)。這將是我寫(xiě)出更多優(yōu)質(zhì)文章的最強(qiáng)動(dòng)力!

          型判斷在 web 開(kāi)發(fā)中有非常廣泛的應(yīng)用,簡(jiǎn)單的有判斷數(shù)字還是字符串,進(jìn)階一點(diǎn)的有判斷數(shù)組還是對(duì)象,再進(jìn)階一點(diǎn)的有判斷日期、正則、錯(cuò)誤類(lèi)型,再再進(jìn)階一點(diǎn)還有比如判斷 plainObject、空對(duì)象、Window 對(duì)象等等。

          上一章節(jié)中我們也介紹了JavaScript類(lèi)型判斷,但是只講了基礎(chǔ)的幾種方法,本次整理的內(nèi)容面向更廣,實(shí)用價(jià)值更高

          typeof

          我們最最常用的莫過(guò)于 typeof,注意,盡管我們會(huì)看到諸如:

          console.log(typeof('yayu')) // string
          

          的寫(xiě)法,但是 typeof 可是一個(gè)正宗的運(yùn)算符,就跟加減乘除一樣!這就能解釋為什么下面這種寫(xiě)法也是可行的:

          console.log(typeof 'yayu') // string
          

          typeof 是一元操作符,放在其單個(gè)操作數(shù)的前面,操作數(shù)可以是任意類(lèi)型。返回值為表示操作數(shù)類(lèi)型的一個(gè)字符串。

          那我們都知道,在 ES6 前,JavaScript 共六種數(shù)據(jù)類(lèi)型,分別是:

          Undefined、Null、Boolean、Number、String、Object

          然而當(dāng)我們使用 typeof 對(duì)這些數(shù)據(jù)類(lèi)型的值進(jìn)行操作的時(shí)候,返回的結(jié)果卻不是一一對(duì)應(yīng),分別是:

          undefined、object、boolean、number、string、object

          注意以上都是小寫(xiě)的字符串。Null 和 Object 類(lèi)型都返回了 object 字符串。

          盡管不能一一對(duì)應(yīng),但是 typeof 卻能檢測(cè)出函數(shù)類(lèi)型:

          function a() {}
          console.log(typeof a); // function
          

          所以 typeof 能檢測(cè)出六種類(lèi)型的值,但是,除此之外 Object 下還有很多細(xì)分的類(lèi)型吶,如 Array、Function、Date、RegExp、Error 等。

          如果用 typeof 去檢測(cè)這些類(lèi)型,舉個(gè)例子:

          var date=new Date();
          var error=new Error();
          var symbol=new Symbol('a');
          console.log(typeof date); // object
          console.log(typeof error); // object
          console.log(typeof a); // symbol
          

          返回的都是 object 吶,這可怎么區(qū)分~ 所以有沒(méi)有更好的方法呢?

          Object.prototype.toString

          是的,當(dāng)然有!這就是 Object.prototype.toString!

          那 Object.protototype.toString 究竟是一個(gè)什么樣的方法呢?上英文版:

          When the toString method is called, the following steps are taken:

          If the this value is undefined, return "[object Undefined]".

          If the this value is null, return "[object Null]".

          Let O be the result of calling ToObject passing the this value as the argument.

          Let class be the value of the [[Class]] internal property of O.

          Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".

          如果沒(méi)有看懂,就不妨看看我理解的:

          當(dāng) toString 方法被調(diào)用的時(shí)候,下面的步驟會(huì)被執(zhí)行:

          1. 如果 this 值是 undefined,就返回 [object Undefined]
          2. 如果 this 的值是 null,就返回 [object Null]
          3. 讓 O 成為 ToObject(this) 的結(jié)果
          4. 讓 class 成為 O 的內(nèi)部屬性 [[Class]] 的值
          5. 最后返回由 "[object " 和 class 和 "]" 三個(gè)部分組成的字符串

          通過(guò)規(guī)范,我們至少知道了調(diào)用 Object.prototype.toString 會(huì)返回一個(gè)由 "[object " 和 class 和 "]" 組成的字符串,而 class 是要判斷的對(duì)象的內(nèi)部屬性。

          console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
          console.log(Object.prototype.toString.call(null)) // [object Null]
          var date=new Date();
          console.log(Object.prototype.toString.call(date)) // [object Date]
          var a=Symbol('a');
          console.log(Object.prototype.toString.call(Symbol)) // [object Symbol]
          

          正是因?yàn)檫@種特性,我們可以用 Object.prototype.toString 方法識(shí)別出更多類(lèi)型!

          那到底能識(shí)別多少種類(lèi)型呢?

          至少 12 種!

          // 以下是11種:
          var number=1; // [object Number]
          var string='123'; // [object String]
          var boolean=true; // [object Boolean]
          var und=undefined; // [object Undefined]
          var nul=null; // [object Null]
          var obj={a: 1} // [object Object]
          var array=[1, 2, 3]; // [object Array]
          var date=new Date(); // [object Date]
          var error=new Error(); // [object Error]
          var reg=/a/g; // [object RegExp]
          var func=function a(){}; // [object Function]
          function checkType() {
           for (var i=0; i < arguments.length; i++) {
           console.log(Object.prototype.toString.call(arguments[i]))
           }
          }
          

          checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)

          除了以上 11 種之外,還有:

          console.log(Object.prototype.toString.call(Math)); // [object Math]
          console.log(Object.prototype.toString.call(JSON)); // [object JSON]
          function a() {
           console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
          }
          a();
          

          type API

          既然有了 Object.prototype.toString 這個(gè)神器!那就讓我們寫(xiě)個(gè) type 函數(shù)幫助我們以后識(shí)別各種類(lèi)型的值吧!

          我的設(shè)想:

          寫(xiě)一個(gè) type 函數(shù)能檢測(cè)各種類(lèi)型的值,如果是基本類(lèi)型,就使用 typeof,引用類(lèi)型就使用 toString。此外鑒于 typeof 的結(jié)果是小寫(xiě),我也希望所有的結(jié)果都是小寫(xiě)。

          考慮到實(shí)際情況下并不會(huì)檢測(cè) Math 和 JSON,所以去掉這兩個(gè)類(lèi)型的檢測(cè)。

          我們來(lái)寫(xiě)一版代碼

          // 第一版
          var class2type={};
          // 生成class2type映射
          "Boolean Number String Function Array Date RegExp Object Error Null Undefined".split(" ").map(function(item, index) {
           class2type["[object " + item + "]"]=item.toLowerCase();
          })
          function type(obj) {
           return typeof obj==="object" || typeof obj==="function" ?
           class2type[Object.prototype.toString.call(obj)] || "object" :
           typeof obj;
          }
          

          嗯,看起來(lái)很完美的樣子~~ 但是注意,在 IE6 中,null 和 undefined 會(huì)被 Object.prototype.toString 識(shí)別成 [object Object]!

          我去,竟然還有這個(gè)兼容性!有什么簡(jiǎn)單的方法可以解決嗎?那我們?cè)俑膶?xiě)一版,絕對(duì)讓你驚艷!

          第二版

          var class2type={};
          // 生成class2type映射
          "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
           class2type["[object " + item + "]"]=item.toLowerCase();
          })
          function type(obj) {
           // 一箭雙雕
           if (obj==null) {
           return obj + "";
           }
           return typeof obj==="object" || typeof obj==="function" ?
           class2type[Object.prototype.toString.call(obj)] || "object" :
           typeof obj;
          }
          

          isFunction

          有了 type 函數(shù)后,我們可以對(duì)常用的判斷直接封裝,比如 isFunction:

          function isFunction(obj) {
           return type(obj)==="function";
          }
          

          數(shù)組

          jQuery 判斷數(shù)組類(lèi)型,舊版本是通過(guò)判斷 Array.isArray 方法是否存在,如果存在就使用該方法,不存在就使用 type 函數(shù)。

          var isArray=Array.isArray || function( obj ) {
           return type(obj)==="array";
          }
          

          但是在 jQuery v3.0 中已經(jīng)完全采用了 Array.isArray。

          在上篇中,我們抄襲 jQuery 寫(xiě)了一個(gè) type 函數(shù),可以檢測(cè)出常見(jiàn)的數(shù)據(jù)類(lèi)型,然而在開(kāi)發(fā)中還有更加復(fù)雜的判斷,比如 plainObject、空對(duì)象、Window 對(duì)象等,這一篇就讓我們接著抄襲 jQuery 去看一下這些類(lèi)型的判斷。

          plainObject

          plainObject 來(lái)自于 jQuery,可以翻譯成純粹的對(duì)象,所謂"純粹的對(duì)象",就是該對(duì)象是通過(guò) "{}" 或 "new Object" 創(chuàng)建的,該對(duì)象含有零個(gè)或者多個(gè)鍵值對(duì)。

          之所以要判斷是不是 plainObject,是為了跟其他的 JavaScript對(duì)象如 null,數(shù)組,宿主對(duì)象(documents)等作區(qū)分,因?yàn)檫@些用 typeof 都會(huì)返回object。

          jQuery提供了 isPlainObject 方法進(jìn)行判斷,先讓我們看看使用的效果:

          function Person(name) {
           this.name=name;
          }
          console.log($.isPlainObject({})) // true
          console.log($.isPlainObject(new Object)) // true
          console.log($.isPlainObject(Object.create(null))); // true
          console.log($.isPlainObject(Object.assign({a: 1}, {b: 2}))); // true
          console.log($.isPlainObject(new Person('yayu'))); // false
          console.log($.isPlainObject(Object.create({}))); // false
          

          由此我們可以看到,除了 {} 和 new Object 創(chuàng)建的之外,jQuery 認(rèn)為一個(gè)沒(méi)有原型的對(duì)象也是一個(gè)純粹的對(duì)象。

          實(shí)際上隨著 jQuery 版本的提升,isPlainObject 的實(shí)現(xiàn)也在變化,我們今天講的是 3.0 版本下的 isPlainObject,我們直接看源碼:

          // 上節(jié)中寫(xiě) type 函數(shù)時(shí),用來(lái)存放 toString 映射結(jié)果的對(duì)象
          var class2type={};
          // 相當(dāng)于 Object.prototype.toString
          var toString=class2type.toString;
          // 相當(dāng)于 Object.prototype.hasOwnProperty
          var hasOwn=class2type.hasOwnProperty;
          function isPlainObject(obj) {
           var proto, Ctor;
           // 排除掉明顯不是obj的以及一些宿主對(duì)象如Window
           if (!obj || toString.call(obj) !=="[object Object]") {
           return false;
           }
           /**
           * getPrototypeOf es5 方法,獲取 obj 的原型
           * 以 new Object 創(chuàng)建的對(duì)象為例的話
           * obj.__proto__===Object.prototype
           */
           proto=Object.getPrototypeOf(obj);
           // 沒(méi)有原型的對(duì)象是純粹的,Object.create(null) 就在這里返回 true
           if (!proto) {
           return true;
           }
           /**
           * 以下判斷通過(guò) new Object 方式創(chuàng)建的對(duì)象
           * 判斷 proto 是否有 constructor 屬性,如果有就讓 Ctor 的值為 proto.constructor
           * 如果是 Object 函數(shù)創(chuàng)建的對(duì)象,Ctor 在這里就等于 Object 構(gòu)造函數(shù)
           */
           Ctor=hasOwn.call(proto, "constructor") && proto.constructor;
           // 在這里判斷 Ctor 構(gòu)造函數(shù)是不是 Object 構(gòu)造函數(shù),用于區(qū)分自定義構(gòu)造函數(shù)和 Object 構(gòu)造函數(shù)
           return typeof Ctor==="function" && hasOwn.toString.call(Ctor)===hasOwn.toString.call(Object);
          }
          

          注意:我們判斷 Ctor 構(gòu)造函數(shù)是不是 Object 構(gòu)造函數(shù),用的是 hasOwn.toString.call(Ctor),這個(gè)方法可不是 Object.prototype.toString,不信我們?cè)诤瘮?shù)里加上下面這兩句話:

          console.log(hasOwn.toString.call(Ctor)); // function Object() { [native code] }
          console.log(Object.prototype.toString.call(Ctor)); // [object Function]
          

          發(fā)現(xiàn)返回的值并不一樣,這是因?yàn)?hasOwn.toString 調(diào)用的其實(shí)是 Function.prototype.toString,畢竟 hasOwnProperty 可是一個(gè)函數(shù)!

          而且 Function 對(duì)象覆蓋了從 Object 繼承來(lái)的 Object.prototype.toString 方法。函數(shù)的 toString 方法會(huì)返回一個(gè)表示函數(shù)源代碼的字符串。具體來(lái)說(shuō),包括 function關(guān)鍵字,形參列表,大括號(hào),以及函數(shù)體中的內(nèi)容

          EmptyObject

          jQuery提供了 isEmptyObject 方法來(lái)判斷是否是空對(duì)象,代碼簡(jiǎn)單,我們直接看源碼:

          function isEmptyObject(obj) {
           var name;
           for (name in obj) {
           return false;
           }
           return true;
          }
          

          其實(shí)所謂的 isEmptyObject 就是判斷是否有屬性,for 循環(huán)一旦執(zhí)行,就說(shuō)明有屬性,有屬性就會(huì)返回 false。

          但是根據(jù)這個(gè)源碼我們可以看出isEmptyObject實(shí)際上判斷的并不僅僅是空對(duì)象。

          舉個(gè)栗子:

          console.log(isEmptyObject({})); // true
          console.log(isEmptyObject([])); // true
          console.log(isEmptyObject(null)); // true
          console.log(isEmptyObject(undefined)); // true
          console.log(isEmptyObject(1)); // true
          console.log(isEmptyObject('')); // true
          console.log(isEmptyObject(true)); // true
          

          以上都會(huì)返回 true。

          但是既然 jQuery 是這樣寫(xiě),可能是因?yàn)榭紤]到實(shí)際開(kāi)發(fā)中 isEmptyObject 用來(lái)判斷 {} 和 {a: 1} 是足夠的吧。如果真的是只判斷 {},完全可以結(jié)合上篇寫(xiě)的 type 函數(shù)篩選掉不適合的情況

          Window對(duì)象

          Window 對(duì)象作為客戶端 JavaScript 的全局對(duì)象,它有一個(gè) window 屬性指向自身,這點(diǎn)在《JavaScript深入之變量對(duì)象》中講到過(guò)。我們可以利用這個(gè)特性判斷是否是 Window 對(duì)象。

          function isWindow( obj ) {
           return obj !=null && obj===obj.window;
          }
          

          isArrayLike

          isArrayLike,看名字可能會(huì)讓我們覺(jué)得這是判斷類(lèi)數(shù)組對(duì)象的,其實(shí)不僅僅是這樣,jQuery 實(shí)現(xiàn)的 isArrayLike,數(shù)組和類(lèi)數(shù)組都會(huì)返回 true。

          因?yàn)樵创a比較簡(jiǎn)單,我們直接看源碼:

          function isArrayLike(obj) {
           // obj 必須有 length屬性
           var length=!!obj && "length" in obj && obj.length;
           var typeRes=type(obj);
           // 排除掉函數(shù)和 Window 對(duì)象
           if (typeRes==="function" || isWindow(obj)) {
           return false;
           }
           return typeRes==="array" || length===0 ||
           typeof length==="number" && length > 0 && (length - 1) in obj;
          }
          

          重點(diǎn)分析 return 這一行,使用了或語(yǔ)句,只要一個(gè)為 true,結(jié)果就返回 true。

          所以如果 isArrayLike 返回true,至少要滿足三個(gè)條件之一:

          1. 是數(shù)組
          2. 長(zhǎng)度為 0
          3. lengths 屬性是大于 0 的數(shù)字類(lèi)型,并且obj[length - 1]必須存在

          第一個(gè)就不說(shuō)了,看第二個(gè),為什么長(zhǎng)度為 0 就可以直接判斷為 true 呢?

          那我們寫(xiě)個(gè)對(duì)象:

          var obj={a: 1, b: 2, length: 0}
          

          isArrayLike 函數(shù)就會(huì)返回 true,那這個(gè)合理嗎?

          回答合不合理之前,我們先看一個(gè)例子:

          function a(){
           console.log(isArrayLike(arguments))
          }
          a();
          

          如果我們?nèi)サ鬺ength===0 這個(gè)判斷,就會(huì)打印 false,然而我們都知道 arguments 是一個(gè)類(lèi)數(shù)組對(duì)象,這里是應(yīng)該返回 true 的。

          所以是不是為了放過(guò)空的 arguments 時(shí)也放過(guò)了一些存在爭(zhēng)議的對(duì)象呢?

          第三個(gè)條件:length 是數(shù)字,并且 length > 0 且最后一個(gè)元素存在。

          為什么僅僅要求最后一個(gè)元素存在呢?

          讓我們先想下數(shù)組是不是可以這樣寫(xiě):

          var arr=[,,3]
          var arrLike={
           2: 3,
           length: 3
          }
          

          也就是說(shuō)當(dāng)我們?cè)跀?shù)組中用逗號(hào)直接跳過(guò)的時(shí)候,我們認(rèn)為該元素是不存在的,類(lèi)數(shù)組對(duì)象中也就不用寫(xiě)這個(gè)元素,但是最后一個(gè)元素是一定要寫(xiě)的,要不然 length 的長(zhǎng)度就不會(huì)是最后一個(gè)元素的 key 值加 1。比如數(shù)組可以這樣寫(xiě)

          var arr=[1,,];
          console.log(arr.length) // 2
          

          但是類(lèi)數(shù)組對(duì)象就只能寫(xiě)成:

          var arrLike={
           0: 1,
           length: 1
          }
          

          所以符合條件的類(lèi)數(shù)組對(duì)象是一定存在最后一個(gè)元素的!

          這就是滿足 isArrayLike 的三個(gè)條件,其實(shí)除了 jQuery 之外,很多庫(kù)都有對(duì) isArrayLike 的實(shí)現(xiàn),比如 underscore:

          開(kāi)notepad++,點(diǎn)擊運(yùn)行


          運(yùn)行

          在運(yùn)行窗口中輸入C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe "$(FULL_CURRENT_PATH)"

          瀏覽器程序路徑+空格+"$(FULL_CURRENT_PATH)"

          點(diǎn)擊運(yùn)行,就可以直接調(diào)用瀏覽器運(yùn)行html了.為了方便也可以保存,并設(shè)置一個(gè)快捷鍵.


          主站蜘蛛池模板: 亚洲AV无码片一区二区三区 | 国产主播福利精品一区二区| 亚洲AV无码一区二区大桥未久| 天天视频一区二区三区| 麻豆视频一区二区三区| 国产午夜精品免费一区二区三区| 精品久久久久久无码中文字幕一区| 美女免费视频一区二区三区| 亚洲日本乱码一区二区在线二产线| 秋霞电影网一区二区三区| 亚洲AV无码一区二区三区久久精品 | 国产亚洲日韩一区二区三区| 福利片免费一区二区三区| 亚洲Av无码一区二区二三区| 91久久精品午夜一区二区| 亚洲一区二区三区无码中文字幕| 无码日韩精品一区二区人妻 | 在线精品国产一区二区| 久久精品一区二区| 色偷偷av一区二区三区| 国产av成人一区二区三区| 国产亚洲一区区二区在线| 激情内射日本一区二区三区| 国产精品熟女视频一区二区| 国产成人精品一区二区三在线观看 | 亚洲AV无码一区二区三区国产 | 亚洲福利精品一区二区三区| av无码精品一区二区三区四区| 精品国产高清自在线一区二区三区 | 午夜DV内射一区二区| 日韩精品中文字幕无码一区| 亚洲国产av一区二区三区丶| 精品欧美一区二区在线观看| 国精品无码A区一区二区| 亚州日本乱码一区二区三区 | 肥臀熟女一区二区三区| 中文字幕一区视频| 日本高清成本人视频一区| 亚洲天堂一区二区三区四区| 波多野结衣在线观看一区二区三区| 国产精品一区二区av不卡|