你不知道的JavaScript:this和對象原型
this在調用時綁定,完全取決于函數的調用位置。
綁定規則
- 默認綁定(獨立函數調用,綁定到全局對象,但嚴格模式下this會綁定到undefined)
function foo() { console.log(this.a); } var a = 2; foo(); // 2
- 隱式綁定:當函數引用有上下文對象時,this綁定在這個上下文對象上,最后一層調用位置起作用
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo } var a = "hello"; obj.foo(); // 2
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo } var bar = obj.foo; //實際上指向foo本身,獨立函數調用 var a = "hello world"; bar(); // hello world
- 顯示綁定,call和apply,第一個參數是對象,函數調用時將this綁定到這個對象上
硬綁定function foo() { console.log(this.a); } var obj = { a: 2 } var bar = function() { foo.call(obj); } bar(); // 2 setTimeout(bar, 1000); // 2 var a = "hello world"; bar.call(window); // 2
- new綁定:用new調用函數時,會創建一個新對象,并將這個新對象綁定到函數調用的this上。
function foo(a) { this.a = a; } var bar = new foo(2); //將返回的對象bar綁定在foo的this上 console.log(bar.a); //2
綁定規則優先級
- 顯示綁定高于隱式綁定
function foo() { console.log(this.a); } var obj1 = { a: 2, foo: foo } var obj2 = { a: 3, foo: foo } obj1.foo();//2 obj2.foo();//3 obj1.foo.call(obj2);//3,先將foo中的this綁定到obj2,在被obj1調用 obj2.foo.call(obj1);//2
- new綁定高于隱式綁定
function foo(something) { this.a = something; } var obj1 = { foo:foo }; var obj2 = {}; obj1.foo(2); console.log(obj1.a); //2 obj1.foo.call(obj2,3); console.log(obj2.a); //3 var bar = new obj1.foo(4); console.log(bar.a);//4 console.log(obj1.a);//2
- new綁定高于硬綁定(new 和call或者apply不能同時使用)
function foo(something) { this.a = something; } var obj1 = {}; var bar = foo.bind(obj1); bar(2); console.log(obj1.a); //2 var baz = new bar(3); console.log(obj1.a); //2 console.log(baz.a);//3
function foo(p1, p2) { this.val = p1 + p2; } var bar = foo.bind(null, "p1"); //不關心硬綁定到哪里,this會被new修改 var baz = new bar("p2"); console.log(baz.val);//p1p2
綁定例外
把null或者undefined傳入call,apply,bind等,忽略this
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null);//2,實際使用默認綁定
間接引用
function foo() {
console.log(this.a);
}
var a = 2;
var o = {a:3, foo:foo};
var p = {a:4};
o.foo();//3
(p.foo = o.foo)();//2,返回值是目標函數的引用,所以是默認綁定
軟綁定
function foo() {
console.log("name: " + this.name);
}
var obj = {name:obj},
obj2 = {name:obj2},
obj3 = {name:obj2};
var fooOBJ = foo.softBind(obj);
fooOBJ(); //name:obj
obj2.foo = foo.softBind(obj);
obj2.foo();//name:obj2
fooOBJ.call(obj3);//name:obj3
setTimeout(obj2.foo, 10);//name:obj
箭頭函數:根據外層作用域來決定this,箭頭函數的綁定無法修改
function foo() {
return (a) => {
//this繼承自foo()
console.log(this.a);
}
}
var obj1 = {a:2};
var obj2 = {a:3};
var bar = foo.call(obj1);
bar.call(obj2);//2
數組,添加數字類屬性,數組長度增加
var myArray = ["foo", 42, "bar"];
myArray.baz = "baz";
console.log(myArray.length);
myArray["3"] = "baz";
console.log(myArray.length);
屬性描述符:writable,是否可以修改屬性的值;configurable,屬性描述符是否可修改,為false的話禁止刪除這個屬性;Enumerable,可枚舉
getter / setter
var myObject = {
get a() {
return this._a_;
},
set a(val) {
this._a_ = val * 2;
}
};
myObject.a = 2;
console.log(myObject.a);
屬性的存在性,值為undefined或者不存在都返回
undefined
var myObject = {
a:2
};
"a" in myObject; // true, 會檢查原型鏈
"b" in myObject; //false
myObject.hasOwnProperty("a");//true,只檢查對象本身
myObject.hasOwnProperty("b");//false
混入
1、 顯示混入
function mixin(sourceObj, targetObj) {
for(var key in sourceObj) {
if(!(key in targetObj)) {
targetObj[key] = sourceObj[key];
}
}
return targetObj;
}
var Vehicle = {
engine: 1,
ignition: function() {
console.log("turning on my engine.");
},
drive: function() {
this.ignition();
console.log("steering and moving forward!");
}
};
var Car = mixin(Vehicle, {
wheels: 4,
drive: function() {
Vehicle.drive.call(this);
console.log("rolling on all" + this.wheels + "wheels!");
}
});
2、混合混入,先進行復制,之后再特殊化,效率低,不常用
function mixin(sourceObj, targetObj) {
for(var key in sourceObj) {
targetObj[key] = sourceObj[key];
}
return targetObj;
}
var Vehicle = {
//...
};
var Car = mixin(Vehicle, {});
mixin({
wheels: 4,
drive:function(){
//...
}
}, car);
3、寄生繼承
function Vehicle() {
this.engine = 1;
}
Vehicle.prototype.ignition = function() {
console.log("turning on my engine.");
};
Vehicle.prototype.drive = function() {
this.ignition();
console.log("steering and move forward!");
};
function Car() {
var car = new Vehicle();
car.wheels = 4;
var vehDrive = car.drive;
car.drive = function() {
vehDrive.call(this);
console.log("rolling on all" + this.wheels + "wheels!");
}
return car;
}
var mycar = new Car();
mycar.drive();
4、 隱式混入
var Something = {
cool: function() {
this.greetng = "hello world";
this.count = this.count ? this.count + 1 : 1;
}
};
Something.cool();
Something.greetng; // hello world
Something.count; // 1
var Another = {
cool: function() {
Something.cool.call(this);
}
};
Another.cool();
Another.greetng; //hello world
Another.count; // 1, count 不是共享狀態
隱式屏蔽
var anotherObject = {
a: 2
};
var myObject = Object.create(anotherObject);
anotherObject.a; // 2
myObject.a; //2
anotherObject.hasOwnProperty("a"); //true
myObject.hasOwnProperty("a"); //false
myObject.a++; //隱式屏蔽
anotherObject.a; //2
myObject.a;//3
myObject.hasOwnProperty("a");//true
構造函數 || 調用
function nosp() {
console.log("don't mind me!");
}
var a = new nosp(); //don't mind me!
a; // {}
委托模式
Task = {
setID: function(ID) {this.id = ID;},
outputID: function() {console.log(this.id);}
};
//讓XYZ委托Task
XYZ = Object.create(Task);
XYZ.prepareTask = function(ID, Lable) {
this.setID(ID);
this.Lable = Lable;
};
XYZ.outputTaskDetails = function() {
this.outputID();
console.log(this.Lable);
};
時間有點急,這篇可能有些格式上的問題,以后再看。
來自:http://www.jianshu.com/p/e6852748ae97
本文由用戶 koeb4636 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!