创建js对象有三种方式:对象字面量、内置的构造函数、自定义的构造函数
对象既有属性、又有方法
1.对象字面量创建对象:
var dog = {
name: "kitty",
getName: function() {
return "maomao";
}
}
完全删除对象属性/方法:
delete dog.name;
delete dog.getName;
2.内置构造函数创建对象:
var dog = new Object();
dog.name = "kitty";
dog.getName = function() {
return "maomao";
}
建议使用对象字面量的方式创建对象。
因为对象字面量:仅需要输入更短的字符;它强调了该对象仅是一个可变哈希映射,而不是从对象中提取的属性或方法;它并没有作用域解析;
而object构造函数:可能会继承其他人编写的遗留代码;Object构造函数仅接收一个参数,根据所传递的值的类型,Object可能会委派另一个内置构造函数来创建对象,并且返回了一个并非期望的不同对象
;
有作用域解析,可能以同样的名字创建了一个局部构造函数,解析器需要从调用Object()的位置开始一直向上查询到作用域链,直到发现全局object构造函数;
3.自定义构造函数创建对象:
var Person = function (name) {
this.name = name;
this.say = function () {
return "I am " + this.name;
}
}
var lily = new Person ("lily");
lily.say(); // 输出结果为I am lily
当以new操作符调用构造函数时,函数内部将会发生以下情况:
(1) 创建一个空对象并且this变量引用了该对象,同时还继承了该函数的原型;
(2) 属性和方法被加入到this引用的对象中;
(3) 新创建的对象由this所引用,并且最后隐式地返回this(如果没有显式地返回其他对象)
var Person = function (name) {
// 使用对象字面量模式创建一个新对象
// var this = {}; // 此语句不是真相的全部,因为空对象实际上并不空,它已经从Person的原型中创建了许多成员,因此,更像是下面的语句:var this = Object.create(Person.prototype);
// 向this添加属性和方法
this.name = name;
this.say = function () {
return "I am " + this.name;
}
// 隐式的返回this(如果没有显式地返回其他对象)
// return this;
}
本例中将say()方法添加到this中,其造成的结果是在任何时候调用new Person()时都会在内存中创建一个新的函数,此种方式效率低下,因为多个实例之间的say()方法实际上并没有改变。
更好的选择是:将方法添加到Person类的原型中
Person.prototype.say = function () {
return "I am " + this.name;
}
切记:可重用的成员,比如,可重用的方法,都应该放置到对象的原型中。
构造函数仍然只是函数,只不过它却以new的方式调用。如果在调用构造函数时忘记指定new操作符,会导致构造函数中的this**指向了全局对象(在浏览器中,this将会指向window)(注意:只有this这种模式才指向全局**):
var w = function() {
this.g = "gg";
}
var w1 = w();
console.log(typeof w1); // 输出 undefined
console.log(w1.g); // 输出 undefined
console.log(window.g) // 输出 gg
所以,在使用构造函数时,要强制使用new的模式。
对于简单的对象,不需要类似that这样的局部变量,可以仅仅从字面量中返回一个对象,如:
function Waffle() {
return {
tastes: "yummy"
}
}
var first = new Waffle(),
second = Waffle();
console.log(first.tastes); // 输出 yummy
console.log(second.tastes); // 输出 yummy
但这种模式的问题它会丢失到原型的链接,因此任何您添加到Waffle()原型的成员,对于对象来说都是不可用的
为了解决前面模式的缺点,并使得原型属性可在实例对象中使用,那么,可以使用如下两种方法(思想:可以在构造函数中检查this是否为构造函数的一个实例,如果不是,构造函数可以再次调用自身,并且在这次调用中正确的使用new操作符):
方法一:
function Waffle() {
if (!(this instanceof Waffle)) {
return new Waffle();
}
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
方法二:
function Waffle() {
if (!(this instanceof arguments.callee)) {
return new arguments.callee();
}
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
使用arguments.callee模式是基于这样的一个事实:即在每个函数内部,当该函数被调用时,将会创建一个名为arguments的对象,其中包含了传递给该函数的所有参数。同时,arguments对象中有一个名为callee的属性,该属性会指向被调用的函数。(注意:在ES5的严格模式中不支持arguments.callee属性)