是高质量js基础视频的p63-p67
**
产生对象的方法
**
- 1.使用工厂方法创建对象
将重复性代码封装在函数中,只用传形参就可以批量生产对象。
function creatPerson(name,age){
//创建新对象 是局部的object
var obj = new Object();
//向对象中添加属性
obj.name = namne;
obj.age = age;
obj.sayName= function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
var obj2 = creatPerson("孙悟空",18);
var obj3 = creatPerson("猪八戒",28);
使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,导致我们无法区分多种类型。所以这种方法用的不多。
- 2.构造函数方法创建对象
构造函数的执行流程:
1.立刻创建一个新的对象
2.将新建对象设置为函数this,在构造函数中可以用this引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
// 创建一个构造函数,专门用来创建Person对象的,
// 构造函数就是一个普通的函数,创建方式和普通函数没有区别,
// 不同的是构造函数上习惯首字母大写
//
// 构造函数和普通函数的区别就是调用方式的不同
// 普通函数就是直接调用
//
//
function P(){
}
var p1 = P();//为普通函数调用
console.log(p1);//undefined,是函数的返回值
var p2 = new P();
console.log(p2);//Object
function Person(name,age){
//name = "hello";//这是向全局中添加
this.name = name;//向新建的对象中添加属性
this.age = age;
this.sayName = function(){
alert(this.name);
};
}
var per1 = new Person("孙悟空",18);
var per2 = new Person("猪八戒",28);
function Dog(){
}
var dog = new Dog();
//使用同一个构造函数创建的对象,我们称之为一类对象。也将构造函数称为一个类
//我们将通过一个构造函数创建的对象,称之为是该类的实例。
console.log(per1);//Person
console.log(dog);//Dog
//使用instanceof可以检查一个对象是否是一个类的实例
console.log(per1 instanceof Person); //true
//所有对象都是Object的后代,任何对象做instanceof检查都会返回true
console.log(per1 instanceof Object); //true
//this的情况
//1.当以函数的形式调用时,this是window
//2.当以方法的形式调用时,谁调用this就是谁
//3.当以构造函数的形式调用时,this是新创建的对象
补充:
先回顾:
function Person(name,age){
//向对象中添加属性
this.name = name;
this.age = age;
//向对象中添加方法
this.sayName = function(){
alert(this.name);
};
}
var per1 = new Person("孙悟空",18);
var per2 = new Person("猪八戒",28);
console.log(per1.sayName == per2.sayName);//false
创建一个Person构造函数
在Person构造函数中,为每一个对象都添加了一个sayName的方法
目前我们的方法是在构造函数内部建的,
也就是构造函数每执行一次就会创建一个新的sayName方法
也就是所有实例的sayName都是唯一的。
这样就导致了构造函数执行一次就会创建一个新的方法
执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的,占用内存比较大
这是完全没有必要的,完全可以使所有的对象共享一个方法。
所以改成以下:
function Person(name,age){
//向对象中添加属性
this.name = name;
this.age = age;
//向对象中添加方法
this.sayName = fun;
}
//将sayName方法在全局作用域中定义
function fun(){
alert(this.name);
}
//创建Person的实例
var per1 = new Person("孙悟空",18);
var per2 = new Person("猪八戒",28);
console.log(per1.sayName == per2.sayName);//true
但是上述也有问题:
1.将函数定义在全局作用域,污染了全局作用域的命名空间
2.定义在全局作用域也很不安全
原型
原型prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype(无论是普通函数还是构造函数)
这个属性对应着一个对象,这个对象就是我们的原型对象
function Person(){
}
function MyClass(){
}
console.log(MyClass.prototype);//Object
console.log(MyClass.prototype == Person.prototype);//false,原型对象对应的地址不同
如果函数作为普通函数调用prototype没有任何作用。
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性指向该构造函数的原型对象,我们可以通过__proto__来访问该属性。
这个原型对象构造函数和实例都能看见 。
原型对象就相当于一个公共的区域,所有同一类的实例都可以访问这个原型对象。
我们可以将对象中共有的内容,统一设置到原型对象中,
当我们访问对象的一个属性或方法时,它会先在自身对象中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果找到则直接使用(相当于一个公共区域)。
可以解决上一小节的问题
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
//向MyClass的原型中添加一个方法 不会污染全局作用域
MyClass.prototype.sayHello = function(){
alert("hello");
};
var mc = new MyClass();
var mc2 = new MyClass();
//向mc中添加属性
mc.a = "mc中的a";
console.log(mc.a);//mc中的a
console.log(mc2.a);//123
以后我们创建构造函数时,可以将这些对象共有的属性和方法,同意添加到构造函数的原型对象中,这样不用分别为每个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
用in检查对象中是否含有某个属性时,如果对象中没有原型中有,也会返回true
可以使用对象的hasOwnProperty()来检查对象自身是否有该属性。
原型对象也是对象,所以他也有原型,当我们使用一个对象的属性或者方法时,会先在自身中寻找,如果自身中有,则直接使用,如果没有就去原型对象中寻找,原型对象中有,则使用,如果没有就去原型的原型中寻找,直到找到Object对象的原型。
Object对象的原型没有原型(null),如果在Object中依然没有找到,则返回undefined。
一层一层的寻找:原型链