基础
JavaScript的对象是一组由键-值组成的无序集合
var person = {
name: 'Bob',
tags: ['js', 'web', 'mobile'],
city: 'Beijing',
hasCar: true,
zipcode: null
};
person.name; // 'Bob'
person.zipcode; // null
person.age; // undefined
person.age = 18; // 新增一个age属性
person.age; // 18
delete person.age; // 删除age属性
属性
是否拥有某一属性,可以用in
操作符
'name' in person; // true
'grade' in person; // false
'toString' in xiaoming; // true 继承得到
判断一个属性是否是自身拥有的,而不是继承得到的
person.hasOwnProperty('name'); // true
person.hasOwnProperty('toString'); // false
var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型
包装对象看上去和原来的值一模一样,显示出来也是一模一样,但他们的类型已经变为object了!所以,包装对象和原始值用 === 比较会返回 false
typeof new Number(123); // 'object'
new Number(123) === 123; // false
typeof new Boolean(true); // 'object'
new Boolean(true) === true; // false
typeof new String('str'); // 'object'
new String('str') === 'str'; // false
强制类型装换
var n = Number('123'); // 123,相当于parseInt()或parseFloat()
typeof n; // 'number'
var b = Boolean('true'); // true
typeof b; // 'boolean'
var b2 = Boolean('false'); // true! 'false'字符串转换结果为true!因为它是非空字符串!
var b3 = Boolean(''); // false
var s = String(123.45); // '123.45'
typeof s; // 'string'
方法
在一个对象中绑定函数,称为这个对象的方法
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了
this
方法内部 this
始终指向当前对象,谁(对象)调用方法,this
就是谁。
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // this 是 xiaoming
// fn 虽然赋值为 xiaoming.age,但 fn 中的 this 并不会因此而绑定到 xiaoming
var fn = xiaoming.age;
fn(); // NaN
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth; // 这里的 this 不指向 xiaoming
}
return getAgeFromBirth();
}
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
使用变量,将 this
传入函数内部
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
};
xiaoming.age(); // 25
apply
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
func.call(对象,参数1,参数2...)
getAge.call(xiaoming);
所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
原型链上的this
var o = {f:function(){return this.a + this.b;}};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // p ---> a,p对象的原型链上的this也是指代p对象
set 与 get 函数里的this
function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o = {
re:2,
im:8,
get phase(){
return Math.atan2(this.im,this.re);
}
}
Object.defineProperty(o,'modulus',{get:modulus,enumerable:true,configurable:true});
console.log(o.phase);
console.log(o.modulus);
构造函数里this
function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a); //37
function C2(){
this.a = 37;
return {a:38};
}
var p = new C2();
console.log(p.a); //38
call/apply方法与this
function add(c,d){
return this.a + this.b + c + d;
}
var o = {a:1,b:3};
console.log(add.call(o,5,7)); //1 + 3 + 5 + 7 = 16 call是直接传参
console.log(add.apply(o,[10,20])); //1 +3 + 10 + 20 = 34 apply是传一个参数数组进去
function bar(){
return Object.prototype.toString.call(this);
}
console.log(bar.call(7)); //[object Number]
bind 后的this指向不会变了
function f(){
return this.a;
}
var g = f.bind({a:"test"});
console.log(g()); //test
var o = {a:37,f:f,g:g};
console.log(o.f()); //37
console.log(o.g()); //test
利用apply(),我们还可以动态改变函数的行为。
JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。
现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt():
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3