JavaScript学习笔记—构造函数和原型(ES5)
目标:
- 能够使用构造函数创建对象
- 能够说出原型的作用
- 能够说出访问对象成员的规则
- 能够使用 ES5新增的一些方法
构造函数和原型
1. 构造函数
构造函数:一种特殊的函数,主要用来初始化对象,即为成员变量赋初始值,它总与new一起使用。可以把一些公共的属性和方法抽取出来,然后封装到这个函数里面
注意:
- 构造函数用于创建某一类对象,其首字母要大写
- 构造函数要和 new 一起使用才有意义
new在执行时会做四件事情:
- 在内存中创建一个新的空对象。
- 让这个this指向这个新的对象。
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要return)
创建对象的方法:
- 利用 new Object() 创建对象
var obj1 = new Object();
- 利用 对象字面量 创建对象
var obj2 = {};
- 利用 构造函数 创建对象
function Phone(uname,price){
this.uname=uname;
this.price=price;
this.text=function(){
console.log('我会发短信')
}
}
实例化一下
var MI=new Phone();
构造函数中的属性和方法我们称为成员,成员可以添加
- 静态成员:在构造函数本身上添加的成员(Phone.matearial=‘金属’),只能由构造函数本身来访问
- 实例成员:在构造函数内部创建的对象成员(通过this添加的成员),只能由实例化的对象来访问
2. 构造函数原型 prototype
为什么要用到这个?
因为,如果你把共有的方法直接放在函数中,当你创建一个实例对象时会分配一个空间,又创建一个实例对象时又分配一个新的内存空间。而这些方法实现的功能是一样的,所以就造成了内存浪费
构造函数通过原型分配的函数是所有对象所共享的。
每一个构造函数都有一个 prototype 属性。 注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
1.原型是什么?
一个对象,也称 prototype 为原型对象
2.原型的作用是什么?
共享方法
3. 对象原型 _ proto _
每个对象都会有一个属性_ proto _ 指向我们构造函数的原型对象prototype
(我们对象能够使用构造函数prototype原型对象的属性和方法,就是因为有对象原型的存在)
4. constructor 构造函数
如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用 constructor 指回原来的构造函数
Phone.prototype = { //这样是赋值一个对象,而不是追加。会把之前原型对象有的东西覆盖掉
constructor:Phone;
text:function(){
console.log('我会发短信');
}
music:function(){
console.log('我会放音乐');
}
}
5.构造函数、实例和原型对象三角关系
6. 原型对象中的this指向
- 构造函数中,里面的this指向的是实例对象
- 原型对象函数里面的this指向的也是实例对象
7. 利用原型对象扩展内置对象方法
注意:数组和字符串的内置对象 不能给原型对象覆盖操作 Array.prototype={ },只能是 Array.prototype.xxx=function(){ }的方式
继承
ES6之前没有给我们提供extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
1. call()
调用这个函数,并且修改函数运行时的 this 指向
fun.call(thisArg,arg1,arg2,...)
- thisArg:当前调用函数this的指向对象
- arg1,arg2:传递的其他参数
// call方法
function fn(x,y){
console.log("是他就是他");
console.log("this");
console.log(x+y);
}
var obj={
name:'xing'
};
//调用函数
// 1. fn();
// 2. fn.call();
//可以改变这个函数的this指向, 此时 就指向了obj这个对象
fn.call(obj,1,2);
2. 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname,age){
//this 指向父构造函数的对象实例
this.uname=uname;
this.age=age;
}
// 2. 子构造函数
function Son(uname,age){
//this 指向子构造函数的对象实例
Father.call(this,uname,age);//也要传入参数的!!!
this.score=score;
}
var son =new Son('牛的话',18,100);
console.log(son);
2. 借用原型对象继承方法
这样直接赋值会有问题,如果修改了子原型对象,父原型对象会跟着一起变化
Son.prototype=Father.prototype;
如果利用对象的形式 修改了原型对象:
Son.prototype = new Father();
//如果利用对象的形式 修改了原型对象,别忘了利用constructor 指回原来的原型对象
Son.prototype.constructor=Son;
//这个是子构造函数专门的方法
Son.prototype.exam=function(){
console.log('孩子要考试');
}
ES6类的本质
-
ES6之前通过 构造函数+原型 实现面向对象编程
(1)构造函数有原型对象prototype
(2)构造函数原型对象prototype 里面有constructor 指向构造函数本身
(3)构造函数可以通过原型对象添加方法
(4)构造函数创建的实例对象有-proto- 原型指向 构造函数的原型指向 -
ES6 通过 类 实现面向对象编程
类的本质其实是一个函数 可以简单地认为 类 就是 构造函数的另外一种写法
(1)类有原型对象prototype
(2)类原型对象prototype 里面有 constructor 指向类本身
(3)类可以通过原型对象添加方法
Star.prototype.sing=function(){
console.log('春来了');
}
所以,ES6的类其实就是语法糖
(语法糖:就是一种便捷写法,简单理解,有两种方法可以实现同样的功能。但是一种写法更加清晰、方便,那么这个方法就是语法糖)
ES5 中新增的方法
- 数组方法
- 字符串方法
- 对象方法
1. 数组方法
迭代(遍历)方法:forEach()、map()、filter()、some()、every();
array.forEach(function((currentValue,index,arr))
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
array.filter(function(currentValue,index,arr))
- filter()方法创建一个新的数组,新数组中的元素是 通过检查 指定数组中 符合条件的所有元素。*主要用于筛选数组*
- 他直接返回一个数组
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
array.some(function(cu)
- some 方法用于检测数组中的元素是否满足指定条件。
- 返回的是布尔值,如果找到这个元素就返回true,如果查找不到就返回false
- 如果找到第一个满足条件的元素,则终止循环,不再继续查找
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
2. 字符串方法
trim() 方法会从一个字符串的两端删除空白字符
并不影响原字符本身,返回的是一个新的字符
str.trim()
3. 对象方法
Object.defineProperty() 定义对象中新属性或修改原有属性。
Object.defineProperty(obj,prop,descriptor)
- obj:必需,目标对象
- prop:必需,需要定义或修改属性的名字
- descriptor:必需,目标属性所拥有的特性以对象形式 { } 书写
Object.defineProperty(obj,prop,{
value:设置属性的值
writable:值是否可以重写 true|false
enumerable:目标值是否可以被枚举 true|false
(枚举,简单来说就是,你是否可以把它遍历出来)
configurable:目标属性是否可以被删除或是否可以再次修改特性 true|false
})
Object.keys( )用于获取对象自身所有的属性
Object.keys(obj)
- 效果类似for…in
- 返回一个有属性名组成的数组
为什么要使用这个差属性?直接console.log(obj) 不就可以了解到
Learning from pink老师