理解对象
JS 中的对象是一系列无序 key: value 的集合
var obj = { a: 1, b: 2}
var person = {
name: 'hunger',
printName: function(){
console.log('My name is hsc')
}
}
但假设我们定义一个函数
function sum(a, b){
return a + b
}
console.log(sum.name) // => sum
console.log(sum.length) //2
会发现,函数 sum也有很多属性,从这个角度看,函数也是 js 对象的一种
构造对象
(1) 通过字面量来构造一个对象
这种方法缺点很明显:
太麻烦了,每次构建一个对象都是复制一遍代码
var obj1 = {
name: 'Byron',
age: 20,
printName: function(){
console.log(obj1.name);
}
}
var obj2 = {
name: 'Casper',
age: 25,
printName: function(){
console.log(obj2.name);
}
}
(2) 使用函数做自动化
这种方法解决了上一种的代码重复的问题,但是这种方法还是不够完美。这种方式构造出来的对象类型都是Object,没有识别度。并且每个对象都有一个相同的printName方法,造成了内存的浪费
function createObj(name, age)
{
var obj = {
name: name,
age: age,
printName: function(){
console.log(this.name)
}
}
return obj
}
var obj = createObj('hsc', 25)
obj.printName()
(3) 通过new运算符来构造函数,返回一个对象实例
function Person(name, age){
this.name = name;
this.age = age;
this.printName = function(){
console.log(this.name);
}
}
var p1 = new Person('Byron', 25);
var p2 = new Person('HSC', 30);
这种方式创建对象首先需要了解几个知识点
- new 运算符接受一个函数 F 及其参数:new F(arguments...)
- function作为构造函数(通过new操作符调用)的时候会返回一个类型为function的name的对象
- 前面说过函数也是一个对象,function有个constructor的属性指向其本身
那么,通过new运算符构造函数从而创建出一个对象的过程具体如何实现的呢?即var p1 = new Person('Byron', 25)具体发生了什么呢?
①创建一个空对象。空对象的 proto 属性被浏览器自动设置为 F.prototype (具体参考原型和原型链的介绍)
②初始化该对象。函数 F 被传入参数并调用,关键字 this 被设定为该空对象,可按照下面理解
function Person(name, age){
var this = {};
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
return this
}
var p1 = new Person('Byron', 25);
var p2 = new Person('HSC', 30);
③返回赋值完成的对象
注:在函数中return 基本类型,构造函数时。没有影响,但是return一个对象时,就会有影响。如下
function Person(name, age){
this.name= name;
this.age = age;
return 1 //情况①
return {a:1,b:2} //情况②
}
var p1 = new Person('Byron', 25); //情况①结果: p1{name:"Byron", age:25}
var p1 = new Person('Byron', 25); //情况②结果: p1{a:1,b:2}
这种方法构建的对象具有识别度,为什么这么说呢?先来看一看instanceof这个操作符,它可以判断对象是否为某个函数的实例。注意instanceof判断的是对象(1 instanceof Number 结果是false)
p1 instanceof Person //true
p1 instanceof Object //true
p1 instanceof Animal //false
可见通过new构造出来的对象,是属于创建它的函数的一个实例。这个创建实例的函数就是js中的类
识别度的问题是解决了,可是这样构建对象,同样每个对象都有相同的printName方法,造成了内存的浪费,这就要提到prototype(原型)了。
每个函数内部都有一个prototype对象,实例调用方法(p1.printName())时,会先去自身找有没有这个方法,找不到,会自动去__proto__中找,也就是F.prototype中找。这样重复的方法(比如printName)等可以放到F.prototype中(原型,相当于一个公共容器),可以减少内存的浪费。
所以最终的代码可以改成这样
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('Byron', 25);
var p2 = new Person('HSC', 30);
注:公共容器中的函数中的this也是指的是调用该函数的对象(所以p1.printName输出的是Byron,而p1.__proto__.printName输出的是undefined,因为p1.__proto__(即Person.portotype)并没有name属性)
所以,现在知道了通过new F 来构造对象是最好的了吧!
网友评论