關於原生js的一些研究

前陣子忙於準備CET-6,沒時間更新文章,以後大概一個月將忙於準備期末考,也應該不會更新了,今天趁週末有時間再更新一篇最近研究的一些東西吧。javascript

callee和caller

function inner(){
    console.log(arguments.callee);//指向擁有這個arguments對象的函數,即inner()
    console.log(arguments.callee.caller);//這個屬性保存着調用當前函數的函數的引用,即outer()
    console.log(inner.caller);//[Function: outer]
}

function outer(){
    inner();
}
outer();

callee放回正在執行的函數自己的引用,它是arguments的一個屬性
caller 返回一個函數的引用,這個函數調用了當前的函數。java

嚴格模式下,不容許訪問arguments.calleearguments.caller屬性,主要體如今arguments.[[Get]]內部方法node

嚴格模式下,arguments,arguments.callee,arguments.caller,arguments.callee.caller也不容許再被賦值。以下代碼所示:正則表達式

'use strict';
// 兩次都是1
void function fn(a) {
    console.log(arguments[0]);
    a = 2;
    console.log(arguments[0]);
}(1);


//function(){}(); 會運行錯誤, 以下能夠正確被運行.

void function(){
    console.log('hi');//hi
}();

在使用當即執行的函數表達式時,能夠利用 void 運算符讓 JavaScript 引擎把一個函數識別成函數表達式而不是函數聲明(語句)。數組

實參和形參

var add = function (a,b) {
    console.log(arguments.length);//3,表示實參長度
    console.log(arguments.callee.length);//2,表示形參長度
};

add(1,2,3);

Array.prototype.slice.call(arguments)

slice有兩個用法,一個是String.slice,一個是Array.slice,第一個返回的是字符串,第二個返回的是數組。瀏覽器

Array.prototype.slice.call(arguments)可以將arguments轉成數組,那麼就是arguments.toArray().slice();安全

由於arguments並非真正的數組對象,只是與數組相似而已,因此它並無slice這個方法,而Array.prototype.slice.call(arguments)能夠理解成是將arguments轉換成一個數組對象,讓arguments具備slice()方法。 好比:cookie

var arr = [1,2,3,4];
 console.log(Array.prototype.slice.call(arr,2));//[3,4]

一樣,還有Array.prototype.forEach.call()forEach() 方法讓數組的每一項都執行一次給定的函數。app

String()

咱們能夠用String()來肯定某一變量是不是null或者undefineddom

var a , b = null;
String(a);//undefined
String(b);//null

直接調用String()做爲方法時,將會執行類型轉換,返回通過toString(value)獲得的字符串字面量(與new String()不一樣),或者空字符串('').

window 對象

<script>
        (function () {
            var root = this;
            console.log(root);//即window對象
        })();
 </script>

打開控制檯,你能夠看到window對象的一系列屬性和方法:

圖片描述

new function

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

var b = new function () {};
console.log(typeof b);//object

var c = new Function ();
console.log(typeof c);//function

new function 是一個JavaScript中用戶自定義的對象

var obj = function (name) {
    this.name = name;
};
var b = new obj('trigkit4');
console.log(b.name);

js中的false和true

//false
console.log(Boolean(''));//false
console.log(Boolean(null));//false
console.log(Boolean(undefined));//false
console.log(Boolean(0));//false
console.log(Boolean(false));//false
console.log(Boolean(NaN));//false

//true
console.log(Boolean(' '));//true    
console.log(Boolean('NaN'));//true

除了false,null,undefined,空字符串'',數字0和NaN之外,其餘全部值都被當作是真,包括true,字符串""裏包含的值,以及全部對象。

valueOf() 和 toString()

valueOf()toString()方法是全部ECMAScript對象擁有的內置方法。操做對象時,valueOf()toString()會被隱式的調用。

//valueOf()
console.log(Object.valueOf());//[Function: Object]
console.log(Object.prototype.valueOf());//{}

var boo = new Boolean(1);
console.log(boo.valueOf());//true

var bar = Boolean(0);
console.log(bar.valueOf());//false

var str = String("trigkit4");
console.log(str.valueOf());//trigkit4

console.log(null.valueOf());//TypeError
console.log(undefined.valueOf());//TypeError

//toString()
console.log(Object.prototype.toString());//[object Object]
console.log(Object.toString());//function Object() { [native code] }
Object.prototype.toString.call(null);//[object Null]
Object.prototype.toString.call(undefined);//[object Undefined]
{a: 'b'}.toString();//[object Object]

valueOf()方法的目的是將對象轉換成最有意義的原始值([[PrimitiveValue]])。即ECMAScript的5種基本類型中的三種,布爾值、數字、字符串

valueOf方法被調用時,會調用內置的ToObject,並將this做爲參數傳進去。ToObject檢測會根據參數類型進行數值的轉換:

Undefined - 拋出TypeError異常
Null - 拋出TypeError異常
Boolean - 建立一個Boolean對象,調用ToBoolean生成[[PrimitiveValue]]
Number - 建立一個Number對象,調用ToNumber生成[[PrimitiveValue]]
String - 建立一個String對象,調用ToString生成[[PrimitiveValue]]
Object - 對象自己

ECMAScript對象的大多數操做的轉換結果是字符串,這兩個方法的結果是相同的。可是若是操做的對象爲NumberBoolean或者Date,結果就不一樣了。

var foo = {
    toString: function () {
        return "foo";
    },
    valueOf: function () {
        return 5;
    }
};

console.log(foo + "bar"); // 5bar
console.log([foo, "bar"].join("")); // foobar

在這個上下文環境中,咱們使用"+"操做符來使字符串鏈接,可是,foo並無使用toString來轉換成字符串,它使用valueOf轉換成一個number,這並非咱們想要的,
但它是如何工做的,這是+運算符的算術和字符串鏈接超載的反作用。"+"操做符有一個明確的處理過程:

1.評估左手側,並獲得該值。
2.評估右手側,並得到該值。
3.同時在左手和右手側調用ToPrimitive(無提示)
4.若是任何原始值是一個字符串,而後跳到7。
5.在這兩個值調用ToNumber。
6.返回值的總和。
7.在這兩個值調用toString。
8.返回的值鏈接起來

setInterval和setTimeout

alert(1); 
setTimeout("alert(2)", 0); 
alert(3);

執行順序爲:1,3,2,雖然延時了0ms

setTimeout 0  //正常狀況下javascript都是按照順序執行的。可是咱們可能讓該語句
後面的語句執行完再執行自己,這時就能夠用到setTimeout延時0ms來實現了。

cookie的建立和刪除

cookie能夠跨越一個域名下的多個網頁,但不能跨越多個域名使用。

document.cookie = 「user = 值;expires = 過時時間;path = 路徑訪問;
domain = 域名訪問;secure = 安全的https限制通訊"

cookie的建立方式

設置cookie咱們通常都封裝成一個函數:

function addCookie(sName,sValue,day) {
    var expireDate = new Date();
    expireDate.setDate(expireDate.getDate()+day);;
//設置失效時間
    document.cookie = escape(sName) + '=' + escape(sValue) +';
    expires=' + expireDate.toGMTString();6 //escape()漢字轉成unicode編碼,toGMTString() 把日期對象轉成字符串
}

刪除cookie

爲了刪除一個cookie,能夠將其過時時間設定爲一個過去的時間,例如:

//獲取當前時間
    var date=new Date();
//將date設置爲過去的時間
    date.setTime(date.getTime()-10000);
//將userId這個cookie刪除
    document.cookie="userId=828; expires="+date.toGMTString();

給cookie設置終止日期

到如今爲止,全部的cookie都是單會話cookie,即瀏覽器關閉後這些cookie將會丟失,事實上這些cookie僅僅是存儲在內存中,而沒有創建相應的硬盤文件。
在實際開發中,cookie經常須要長期保存,例如保存用戶登陸的狀態。這能夠用下面的選項來實現:

document.cookie="userId=828; expiress=GMT_String";

其中GMT_String是以GMT格式表示的時間字符串,這條語句就是將userId這個cookie設置爲GMT_String表示的過時時間,超過這個時間,cookie將消失,不可訪問。例如:若是要將cookie設置爲10天后過時,能夠這樣實現:

<script language="JavaScript" type="text/javascript">
//獲取當前時間
    var date=new Date();
    var expiresDays=10;
//將date設置爲10天之後的時間
    date.setTime(date.getTime()+expiresDays*24*3600*1000);
//將userId和userName兩個cookie設置爲10天后過時
    document.cookie="userId=828; userName=hulk; expires="+date.toGMTString();
</script>

對象和函數能夠如數組同樣,用屬性名或方法名做爲下標來訪問:

對象的建立

//對象的建立
function MyFunc(){}
var obj1 = new MyFunc();//使用new操做符,藉助MyFun函數,就建立了一個對象
var obj2 = new MyFunc;//函數也能夠沒有括號,但仍將調用該函數

能夠把上面的代碼改寫成這種等價形式:

function MyFunc(){};
var obj1 = {};//建立一個對象
MyFunc.call(obj1);//將obj1對象做爲this指針調用MyFunc函數

做用域

經過自執行的匿名函數你能夠把全部本來屬於全局的變量都隱藏起來:

//建立一個新的匿名函數,做爲包裝
(function () {
    //變量本來應該是全局的
    var msg = "Thanks for visiting";
    
    window.onunload = function () {
        console.log(msg);
    };
})();

上下文對象是經過this變量體現的,這個變量永遠指向當前代碼所處的對象中。

var obj = {
    yes : function(){
        //this == obj
        this.val = true;
    },
    no : function(){
        this.val = false;
    }
};
console.log(obj.val == null);//true
//執行了yes函數後,將val屬性與'obj'對象關聯起來
obj.yes();
console.log(obj.val == true);//true

String 原型方法的擴展

//公共正則表達式處理函數
    String.prototype.Regular = function(reg){
        var result = true;
        if(this.length > 0){       
            if(!reg.test(this)){   
                result = false;
            }  
        } 
        return result;
    }
    
    //.trim()方法
     String.prototype.trim = function () {
        return this.replace(/(^\s*)|(\s*$)/g,'');
};

^表示字符串必須之後面的規則開頭,而(^\s*) 表示的就是以0個空格或者多個空格開頭,後面的(\s*$) 的意思就是, 以0個空格或者多個空格結尾。

//判斷輸入內容是否爲空
    String.prototype.isNull = function(){  
        return this.trim().length == 0 ? true : false; 
    } 
    
    //判斷輸入的字符是否爲英文字母\數字\下劃線
    String.prototype.isVersion = function(){    
        var reg = /^([a-zA-Z_])([a-zA-Z0-9_.])*$/;  
        return this.Regular(reg);
    }
    
   // 判斷輸入的字符串,不包括單引號
   String.prototype.isString = function(){    
        var reg = /^[^']*$/; 
        return this.Regular(reg); 
    }
    
  //判斷輸入的字符是否爲英文字母  
    String.prototype.isLetter = function(){   
       var reg = /^[a-zA-Z]+$/;  
       return this.Regular(reg);
   }

constructor屬性

function User(){}
var me = new User();
console.log(me.constructor);//[Function: User]

//用前一個對象的Constructor引用來建立一個新的User對象
var you = new me.constructor();
console.log(me.constructor == you.constructor);//true

Object.create

function Parent(){}
 var o = Object.create(Parent.prototype);
 console.log(o instanceof Parent);//true
 console.log(o instanceof Object);//true
 console.log(Object.prototype.toString.call(o));//[object Object]

「數據屬性」是可獲取且可設置值的屬性。 數據屬性描述符包含 value 特性,以及 writable、enumerableconfigurable 特性。 若是未指定最後三個特性,則它們默認爲 false

function Parent(){}
var o = Object.create(Parent);
console.log(o instanceof Parent);//false
console.log(o instanceof Object);//true

另一個實例

var book1 = {
    title:"JS高級程序設計",
    pages : 1001,
    getTitle:function(){
        console.log(this.title);
    }
};
var book2 = Object.create(book1,{
    //title會成爲所建立對象的數據屬性
    title:{
        configurable:true,
        enumerable:true,
        value:"JS權威指南",
        wratable:true
    }
});
book1.getTitle();  //"JS高級程序設計"
book2.getTitle();  //"JS權威指南"

console.log(book1.hasOwnProperty("getTitle"));  //true
console.log('pages' in book2);  //true
console.log(book2.hasOwnProperty("getTitle"));  //false
console.log(book1.isPrototypeOf(book2));//true

再看另外一個例子:

function Constructor(){}
obj = new Constructor();
// 上面的一句就至關於:
obj = Object.create(Constructor.prototype);
console.log(obj);//{}
console.log(Object.create(Constructor.prototype));//{}

console.log(obj instanceof Constructor);//true
console.log(Constructor.prototype.isPrototypeOf(obj));//true

var foo;
foo = {};
// 以字面量方式建立的空對象就至關於:
foo = Object.create(Object.prototype);

另外:

console.log(Object.prototype);//{}
console.log(Object.create(Object.prototype));//{}

經過Object.create(Object.prototype) 建立的實例對象就繼承了Object原型下的屬性和方法。

javascript全部function類型的對象都有一個prototype屬性。這個prototype屬性自己又是一個object類型的對象,原型對象都包含一個指向構造函數的指針,而每個實例也都包含一個指向原型對象內部的指針。

參考: https://developer.mozilla.org...

prototype

function User(){}

var u1 = new User();
console.log(u1.prototype);//使用對象實例沒法訪問到prototype
console.log(User.prototype);//{},使用構造函數名訪問prototype
console.log(u1.__proto__);//{},使用對象實例訪問prototype的指針

//使用字面量的方式建立原型對象,這裏{}就是對象
User.prototype = {
    name : "trigkit4",
    age : 22
};

使用構造函數建立原型對象和使用字面量建立對象在使用上基本相同,但仍是有些區別,字面量建立的方式使用constructor屬性不會指向實例,而會指向Object,構造函數建立的方式則相反

function User(){}
User.prototype = {
    name : "trigkit4",
    age : 22
};
var u1 = new User();
console.log(u1.constructor);//function Object() {[native code]}
console.log(u1 instanceof User);//true
console.log(u1.constructor == User);//false
console.log(u1.constructor == Object);//true

//若是想讓字面量方式的constructor指向實例對象,能夠這麼作:
User.prototype = {
    constructor : User;
}

字面量方式爲何constructor會指向Object?由於User.prototype = {};這種寫法其實就是建立了一個新對象:

function User(){}

User.prototype = {
    constructor : User
};
var u1 = new User();
console.log(User.constructor);//[Function: Function]
console.log(u1.constructor == User);//true

另外一個例子:

(function () {
    
        console.log(Object.prototype);//{}
        console.log(Array.prototype);//[]
        console.log(Array.prototype.push);//[Function: push]
        console.log(Function.prototype);//[Function: Empty]
        console.log(Function.prototype.bind);//[Function: bind]
    
      
    })();

Object.prototype.toString

toString()方法被調用時,會執行下面的操做步驟:

若是this的值爲undefined,則返回"[object Undefined]".
若是this的值爲null,則返回"[object Null]".
讓O成爲調用ToObject(this)的結果.
讓class成爲O的內部屬性[[Class]]的值.
返回三個字符串"[object ", class, 以及 "]"鏈接後的新字符串.

因爲 JavaScript 中一切都是對象,任何都不例外,對全部值類型應用Object.prototype.toString.call()

方法結果以下:

console.log(Object.prototype.toString.call(123)) //[object Number]        
console.log(Object.prototype.toString.call('123')) //[object String]      
console.log(Object.prototype.toString.call(undefined)) //[object Undefined] 
console.log(Object.prototype.toString.call(true)) //[object Boolean]      
console.log(Object.prototype.toString.call({})) //[object Object]        
console.log(Object.prototype.toString.call([])) //[object Array]      
console.log(Object.prototype.toString.call(function(){})) //[object Function]


全部類型都會獲得不一樣的字符串,幾乎完美。
JavaScript中,想要判斷某個對象值屬於哪一種內置類型,最靠譜的作法就是經過Object.prototype.toString方法.

面向對象

下面是來自Prototype.js的一段代碼:

//建立一個名爲"Class"的全局對象
var Class = {
    //它只有一個函數,其做用是建立一個新的對象構造函數
    create: function(){
        //建立一個匿名的對象構造函數
        return function () {
            //調用它自己的初始化方法
            this.initialize.apply(this,arguments);
        }
    }
};

//給Object對象添加一個新的靜態方法,它的做用是把屬性從一個對象複製到另外一箇中
Object.extend = function (destination,source) {
    //遍歷全部要擴展的屬性
    for(property in source){
        //而後將他們添加到目標對象中
        destination[property] = source[property];
    }
};

成員操做符

function aFunc(){}//或者var aFunc = function(){};

aFunc.oProperty = "函數的一個屬性";
aFunc.aMethod = function(){
    console.log("函數的一個方法");
};

console.log(aFunc["oProperty"]);//將函數當成數組以屬性名做爲下標來訪問屬性
console.log(aFunc["aMethod"]());//將函數當數組以方法名做爲下標來調用方法

//遍歷函數的全部屬性和方法
for(var s in aFunc){
    console.log(s + "is a "+typeof(aFunc[s]));
}

特權方法與私有方法

function Constructor(msg){
    this.Message = msg;

    //私有屬性
    var separator = '-';
    var owner = this;

    //私有方法
    function alertMessage(){
        console.log(owner.Message);
    }
    alertMessage();

    //特權方法(也是公有方法)
    this.aptMessage = function (str) {
        this.Message += separator + str;
        alertMessage();
    }
}

//公有方法
Constructor.prototype.clearMessage = function (str) {
    this.Message = '';
};

//靜態屬性
Constructor.name = 'trigkit4';

//靜態方法
Constructor.alertName = function (name) {
    console.log(this.name);
};

特權方法是指在構造函數的做用域中使用this關鍵字定義的方法;與私有方法不一樣,特權方法可以被公開訪問,並且還可以訪問私有成員。

因爲私有和特權成員在函數的內部,所以它們會被帶到函數的每一個實例中。
公有的原型成員是對象藍圖的一部分,適用於經過 new關鍵字實例化的該對象的每一個實例 靜態成員只適用於對象的一個特殊實例

使用對象字面量語法來向prototype屬性添加全部公有成員:

function Constructor(){
    //私有和特權成員
}

//公有方法
Constructor.prototype = {
    propertyA: 'value1',
    propertyB: 'value2',
    methodA: function(){},
    methodB: function(){}
};

刪除不要的節點

DOM 元素在瀏覽器中所佔用的空間是很是大的,要及時回收不用的節點:

var node = parentNode.removeChild(node);

node = null;//設置爲空,釋放空間
CollectGarbage();//IE,回收資源
相關文章
相關標籤/搜索