顯示綁定:css
JavaScript 中的「全部」函數都有一些有用的特性(這和它們的 [[Prototype]] 有關——以後咱們會詳細介紹原型),能夠用來解決這個問題。具體點說,可使用函數的 call(..) 和apply(..) 方法。嚴格來講,JavaScript 的宿主環境有時會提供一些很是特殊的函數,它們並無這兩個方法。可是這樣的函數很是罕見,JavaScript 提供的絕大多數函數以及你自己建立的全部函數均可以使用 call(..) 和 apply(..) 方法。數組
這兩個方法是如何工做的呢?它們的第一個參數是一個對象,是給 this 準備的,接着在調用函數時將其綁定到 this。由於你能夠直接指定 this 的綁定對象,所以咱們稱之爲顯式綁定。數據結構
思考下面的代碼:app
function foo() { console.log( this.a ); } var obj = { a:2 }; foo.call( obj ); // 2
經過 foo.call(..),咱們能夠在調用 foo 時強制把它的 this 綁定到 obj 上。ide
用call來實現繼承函數
var test = { name: 'He', age: 25 }
var test2 = { write: function () { console.log(this.name) }, writeAge: function () { console.log(this.age) } }
test2.write.call(test) //He test2.writeAge.call(test) //25 test2.write(); //undefined test2.writeAge(); //undefined
1. 函數是否在 new 中調用(new 綁定)?若是是的話 this 綁定的是新建立的對象。
var bar = new foo()ui
2. 函數是否經過 call、apply(顯式綁定)或者硬綁定調用?若是是的話,this 綁定的是指定的對象。
var bar = foo.call(obj2)this
3. 函數是否在某個上下文對象中調用(隱式綁定)?若是是的話,this 綁定的是那個上下文對象。
var bar = obj1.foo()spa
4. 若是都不是的話,使用默認綁定。若是在嚴格模式下,就綁定到 undefined,不然綁定到全局對象。
var bar = foo() prototype
var myobject={ //... } myobject.a //undefined
訪問myobject對象的a屬性,返回的值爲 undefined,可是這個值有多是屬性中存儲的 undefined,也多是屬性不存在返回的 undefined,那麼如何區分這兩種狀況呢?
咱們能夠在不訪問屬性值的狀況下判斷對象中是否存在這個屬性:
var myObject = { a:2 };
("a" in myObject); // true ("b" in myObject); // false
myObject.hasOwnProperty( "a" ); // true myObject.hasOwnProperty( "b" ); // false
in 操做符會檢查屬性是否在對象及其 [[Prototype]] 原型鏈中,hasOwnProperty(..) 只會檢查屬性是否在 myObject 對象中,不會檢查 [[Prototype]] 鏈。
看起來in像是檢測容器內是否存在某個值,可是實際上檢查的是某個屬性名是否存在。
4 in [2,4,6] //false
數組[2,4,6]的屬性名是0,1,2 由於檢測的是屬性名, 因此會輸出false
//// 數組有內置的 @@iterator,所以 for..of 能夠直接應用在數組上。咱們使用內置的 @@iterator 來手動遍歷數組,看看它是怎麼工做的 var myArr = [1, 2, 3]; var it = myArr[Symbol.iterator](); it.next(); // { value:1, done:false } it.next(); // { value:2, done:false } it.next(); // { value:3, done:false } it.next(); // { done:true }
如你所見,調用迭代器的 next() 方法會返回形式爲 { value: .. , done: .. } 的值,value 是當前的遍歷值,done 是一個布爾值,表示是否還有能夠遍歷的值。
注意,和值「3」一塊兒返回的是 done:false,乍一看好像很奇怪,你必須再調用一次next() 才能獲得 done:true,從而肯定完成遍歷。這個機制和 ES6 中發生器函數的語義相關,不過已經超出了咱們的討論範圍。
和數組不一樣,普通的對象沒有內置的 @@iterator,因此沒法自動完成 for..of 遍歷。之因此要這樣作,有許多很是複雜的緣由,不過簡單來講,這樣作是爲了不影響將來的對象類型。
固然,你能夠給任何想遍歷的對象定義 @@iterator,舉例來講:
var myObject = { a: 2, b: 3 }; Object.defineProperty( myObject, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function() { var o = this; var idx = 0; var ks = Object.keys( o ); return { next: function() { return { value: o[ks[idx++]], done: (idx > ks.length) }; } }; } } ); // 手動遍歷 myObject var it = myObject[Symbol.iterator](); it.next(); // { value:2, done:false } it.next(); // { value:3, done:false } it.next(); // { value:undefined, done:true } // 用 for..of 遍歷 myObject for (var v of myObject) { console.log( v ); } // 2 // 3
咱們使用 Object.defineProperty(..) 定義了咱們本身的 @@iterator(主要是爲了讓它不可枚舉),不過注意,咱們把符號看成可計算屬性名(本章以前有介紹)。此外,也能夠直接在定義對象時進行聲明,好比 var myObject = { a:2, b:3, [Symbol.iterator]: function() { /* .. */ } }。
for..of 循環每次調用 myObject 迭代器對象的 next() 方法時,內部的指針都會向前移動並返回對象屬性列表的下一個值(再次提醒,須要注意遍歷對象屬性 / 值時的順序)。
一、對象就是鍵 / 值對的集合。能夠經過 .propName 或者 ["propName"] 語法來獲取屬性值。訪問屬性時,引擎實際上會調用內部的默認 [[Get]] 操做(在設置屬性值時是 [[Put]]),[[Get]] 操做會檢查對象自己是否包含這個屬性,若是沒找到的話還會查找 [[Prototype]]鏈(參見第 5 章)。
二、屬性的特性能夠經過屬性描述符來控制,好比 writable 和 configurable。此外,可使用Object.preventExtensions(..)、Object.seal(..) 和 Object.freeze(..) 來設置對象(及其屬性)的不可變性級別
三、屬性不必定包含值——它們多是具有 getter/setter 的「訪問描述符」。此外,屬性能夠是可枚舉或者不可枚舉的,這決定了它們是否會出如今 for..in 循環中。
四、你可使用 ES6 的 for..of 語法來遍歷數據結構(數組、對象,等等)中的值,for..of會尋找內置或者自定義的 @@iterator 對象並調用它的 next() 方法來遍歷數據值。
var foo2 = { name: 'He', sayName: function () { console.log(this.name) } } var foo2_n = Object.create(foo2); foo2_n.sayName();
Task = { setId: function (id) { this.id = id }, outputId: function () { console.log(this.id) } } // 讓 XYZ 委託 Task xyz = Object.create(Task); xyz.prepareTask = function (id, label) { this.setId(id); this.label = label } xyz.outputTaskDetails = function () { this.outputId(); console.log(this.label) } // xyz.prepareTask(1,'委託')
Foo = { init: function (who) { this.me = who }, identify: function () { return 'I am ' + this.me + '.' } } Bar = Object.create(Foo); Bar.speak = function () { console.log("Hello, " + this.identify()) } var a1 = Object.create(Bar); a1.init('A1'); var b1 = Object.create(Bar); b1.init('B1'); a1.speak(); b1.speak();
// 父類 function widget(width, height) { this.width = width || 50; this.height = height || 50; this.$elem = null; } widget.prototype.render = function ($where) { if (this.$elem) { this.$elem.css({ width: this.width + 'px', height: this.height + 'px' }).appendTo($where); } } //子類 function Button(width, height, label) { widget.call(this, width, height); this.label = label || "default"; this.$elem = $('<button>').text(this.label); } // 讓Button繼承widget Button.prototype = Object.create(widget); // 重寫render方法 Button.prototype.render = function ($where) { widget.prototype.render.call(this, $where); this.$elem.click(this.onClick.bind(this)); } Button.prototype.onClick = function (evt) { console.log("Button " + this.label + " clicked!") } $(function () { var $body = $(document.body); var button1 = new Button(70, 70, '按鈕1'); var button2 = new Button(90, 90, '按鈕2'); button1.render($body); button2.render($body); })
var widget2={ init:function(width,height){ this.width=width||50; this.height=height||50; this.$elm=null; }, insert:function($where){ if(this.$elm){ this.$elm.css({ width:this.width+'px', height:this.height+'px', marginLeft:'30px' }).appendTo($where) } } } var Button2=Object.create(widget2); Button2.setup=function(width,height,label){ this.init(width,height); this.label=label||"default"; this.$elm=$("<button>").text(this.label); } Button2.build=function($where){ this.insert($where); this.$elm.click(this.onClick.bind(this)); } Button2.onClick=function(){ console.log("Button "+this.label+" clicked"); } $(document).ready(function(){ var body=$(document.body); var button1=Object.create(Button2); var button2=Object.create(Button2); button1.setup(80,80,'取消') button1.build(body) button2.setup(80,80,'肯定!'); button2.build(body); })
ES5 規範 9.2 節中定義了抽象操做 ToBoolean,列舉了布爾強制類型轉換全部可能出現的
結果。
如下這些是假值:
• undefined
• null
• false
• +0、-0 和 NaN
• ""
假值的布爾強制類型轉換結果爲 false。
一元運算符 ! 顯式地將值強制類型轉換爲布爾值。可是它同時還將真值反轉爲假值(或者將假值反轉爲真值)。因此顯式強制類型轉換爲布爾值最經常使用的方法是 !!,由於第二個 ! 會將結果反轉回原值
var a = "0"; var b = []; var c = {}; var d = ""; var e = 0; var f = null; var g; !!a; // true !!b; // true !!c; // true !!d; // false !!e; // false !!f; // false !!g; // false
優先級
var a = 42; var b = "foo"; var c = false; var d = a && b || c ? c || b ? a : c && b : a; d; // 42
運算符優先級 && > || > ? :
利用優先級將代碼分解:
((a && b) || c) ? ((c || b) ? a : (c && b)) : a
如今來逐一執行
(1) (a && b) 結果爲 "foo"。
(2) "foo" || c 結果爲 "foo"。
(3) 第一個 ? 中,"foo" 爲真值。
(4) (c || b) 結果爲 "foo"。
(5) 第二個 ? 中,"foo" 爲真值。
(6) a 的值爲 42。
所以,最後結果爲 42。
typeof 適合基本類型和函數對象的判斷 不適用array等特殊類型
typeof 100;//number typeof true;//boolean typeof function(){};//function typeof (undefined);//undefined typeof new Object;//Object typeof [1,2];//Object typeof NaN;//number typeof null;//Object
instanceof 經常使用於判斷對象類型,它是基於原型鏈去判斷的操做符
(obj instanceof Object)
instanceof它但願左操做數(obj)是一個對象,若是不是對象,是基本數據類型(好比 string,number),直接返回false。
它但願右操做數必須是一個函數對象或者函數構造器,若是不是會拋出異常Type Error。
instanceof大概原理:判斷左操做數對象的原型鏈上是否有右構造函數的prototype屬性
[1,2] instanceof Array;//true new Object() instanceof Array; //false