TS学习笔记04 JS创建对象的方式
首先我们回顾下JS中创建对象的方式
比如说我按照下面的创建了两个对象分别为stu1和stu2,比如说我现在想给这两个对象都添加一个新的方法,但是这两个对象都分别独立的,只能一个个添加。无法通过prototype添加共享功能。
/**
* 回顾一:JS中定义对象的几种方式
* 优点:简单、方便
* 缺点:只能描述一个对象的结构,无法为多个对象添加共享的原型功能
*
*/
方式一:对象字面量
var stu1 = {
name:'tom',
age:18,
study:function(){
console.log('正在学习。。。。');
}
}
// 没有原型,无法通过prototype添加共享功能
// stu1.prototype.show = function(){
// console.log('自我介绍');
// }
var stu2 = {
name:'alice',
age:20
}
console.log(stu1.name,stu1.age);
stu1.study();
stu1.show();//会报错,Cannot not set property 'show' of underfind
方式2:构造函数/构造器
/**
* 方式2:构造函数/构造器
* 优点:基于同一个构造函数创建对象,多个对象具有相同的结构,可以添加共享和原型功能
* 缺点:无法为构造函数提供独立的作用域
*/
//如果需要添加元素,在构造函数里面添加,其余的对象都会读到这个元素
function Student(name,age){
this.name = name; // this表示将来new出来的当前对象
this.age = age;
this.study = function(){
console.log('正在学习。。。。');
}
}
//new一个新的对象,这个对象名对应的就是上述构造器的.this,比如this.name实际上就是str1.name
var str1 = new Student('tom',18);
// 通过原型的方式添加功能
Student.prototype.sex = 'male';
Student.prototype.show = function(){
console.log('自我介绍:'+this.name+','+this.age+','+this.sex);
console.log(data);
}
stu1.show(); //output:自我介绍:tom,18,male
构造函数中的属性 和原型中的属性 有什么不同?
我们先new两个实例。
function Student(name,age){
this.name = name; // this表示将来new出来的当前对象
this.age = age;
this.study = function(){
console.log('正在学习。。。。');
}
}
Student.prototype.sex = 'male';
Student.prototype.show = function(){
console.log('自我介绍:'+this.name+','+this.age+','+this.sex);
console.log(data);
}
var stu1 = new Student('tom',18);
var stu2 = new Student('alice',20);
console.log(stu1)
console.log(stu2)
打印后的结果如图:
我在上述的代码中,通过原型的方式添加了一个属性sex为male,这个属性属于原型的,属于全局的。而new出来的age和name属性属于实例属性,这两者是不一样的。
观察下面的代码,我把stu1添加一个属性,再同时打印stu1和stu2。
可以明显看到,stu1中多了一个属性(stu1原本不具有这个属性),但是原型中的sex依旧是male。
stu1.sex = 'female'; // 为stu1添加一个实例属性sex,并不是修改原型中的属性
那么如何修改原型中的属性呢?
首先我们需要找到原型。可以看出在[[Prototype]]这个属性里面包裹的是原型。
修改原型,再次打印出来后发现原型被成功的修改了。
stu1.__proto__.sex = 'female';
并且再次打印stu2,发现stu2的原型也同样被修改了。
总结就是:
构造函数中的属性:每个实例都有独立的属性,互不影响;
原型中的属性:所有实例所共享,访问的是同一个值。
方式三:闭包构造函数
通过自执行函数 (function(){})()
将构造函数和原型定义包裹起来,构造一个独立作用域
// 定义一个变量Student来接受这个自执行函数返回的结果
var Student = (function(){
// 这个data是定义在这个函数里面的,所以函数外面是访问不了的,这就解决了方法二无法为构造函数提供独立的作用域的痛点
var data = 'hello'; // 全局作用域
function Student(name,age){
this.name = name; // this表示将来new出来的当前对象
this.age = age;
this.study = function(){
console.log('正在学习。。。。');
}
}
// 通过原型的方式添加功能
Student.prototype.sex = 'male';
Student.prototype.show = function(){
console.log('自我介绍:'+this.name+','+this.age+','+this.sex);
console.log(data);
}
return Student;
})();
var stu1 = new Student('tom',18);
var stu2 = new Student('alice',20);
stu1.show();//output: tom,18,male hello
stu2.show();//output: alice,20,male hello