一、构造函数
1.1 概述![](https://img-blog.csdnimg.cn/357b53aff28f4a75b92ee35d96394881.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5re35rKM5Yeh5Lq6,size_20,color_FFFFFF,t_70,g_se,x_16)
1.2 对象的三种创建方式(复习)
-
字面量方式
var obj = {};
-
new关键字
var obj = new Object();
-
构造函数方式
function Person(name,age){ this.name = name; this.age = age; } var obj = new Person('zs',12);
1.3 构造函数![](https://img-blog.csdnimg.cn/8a9073f4c1734fdfaac51bddf43eb6b5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5re35rKM5Yeh5Lq6,size_20,color_FFFFFF,t_70,g_se,x_16)
// 3. 利用构造函数创建对象
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh);
ldh.sing();
zxy.sing();
1.4 静态成员和实例成员
成员:属性和方法。
实例成员
实例成员就是构造函数内部通过this添加的成员,
如下列代码中:uname age sing 就是实例成员,
实例成员只能通过实例化的对象来访问
// 构造函数中的属性和方法我们称为成员, 成员可以添加
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
console.log(ldh.uname);//实例成员只能通过实例化的对象来访问
静态成员
构造函数本身也是1个对象!
静态成员:在构造函数本身上添加的成员。
如下列代码中 sex 就是静态成员,静态成员
只能通过构造函数来访问
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
// 静态成员 在构造函数本身上添加的成员 sex 就是静态成员
Star.sex = '男';
var ldh = new Star('刘德华', 18);
console.log(Star.sex);//静态成员只能通过构造函数来访问
二、原型对象
2.1 构造函数的问题
构造函数创建对象很好用,但是如果把方法定义在构造函数内,就存在浪费内存的问题。
我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上。
2.2 构造函数的原型prototype
构造函数通过原型分配的函数是所有对象所共享的。
JavaScript 规定,每一个构造函数都有一个prototype 属性,指向另一个对象,这个对象叫做【原型对象】。
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
function Star(uname, age) {
// 构造函数中定义属性
this.uname = uname;
this.age = age;
}
// 把方法定义到原型对象身上
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
ldh.sing();
zxy.sing();
// 所有的实例对象,共用一个方法,省内存
console.log(ldh.sing === zxy.sing);
2.3 对象原型
实例对象都有一个属性 __proto__ 指向构造函数的 prototype 原型对象。
之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在。
__proto__对象原型和原型对象 prototype 是等价的。
__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype。
2.4 constructor构造函数
如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数如:
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star, // 手动设置指回原来的构造函数
sing: function() {
console.log('我会唱歌');
},
movie: function() {
console.log('我会演电影');
}
}
var zxy = new Star('张学友', 19);
2.5 三角关系
构造函数、实例对象和原型对象的三角关系。
1.构造函数的prototype属性指向了构造函数原型对象
2.实例对象是由构造函数创建的,实例对象的__proto__属性指向了构造函数的原型对象
3.构造函数的原型对象的constructor属性指向了构造函数,实例对象的原型的constructor属性也指向了构造函数
四、原型链与对象成员的查找规则
4.1 原型链
<!--任何原型对象也是一个对象,该对象就有 __proto__ 属性,这样一层一层往上找,就形成了一条链,我们称此为原型链;-->
4.2 对象成员的查找机制
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
如果还没有就查找:原型对象的原型(Object的原型对象)。
依此类推一直找到 Object 为止(null)。
沿着原型链查找!!
五、原型对象的应用
5.1 原型对象函数中this指向
不管构造函数中的this,还是原型对象中的this,都指向我们new出来的实例对象。
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
var that;
Star.prototype.sing = function() {
console.log('我会唱歌');
that = this;
}
var ldh = new Star('刘德华', 18);
// 1. 在构造函数中,里面this指向的是对象实例 ldh
ldh.sing();
console.log(that === ldh);
// 2.原型对象函数里面的this 指向的是 实例对象 ldh
</script>
5.2 通过原型为数组扩展内置方法
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。
// 系统中内置了很多构造函数:例如:Object、Array
// Array构造函数也有一个对应的原型对象
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
};
// 数组的实例对象 arr
var arr = [1, 2, 3];
// 调用sum方法(成员的查找规则)
console.log(arr.sum());
console.log(Array.prototype);
// 数组的实例对象 arr1
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());
六、继承![](https://img-blog.csdnimg.cn/3cb075a7983c41568991aa66a12461b5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5re35rKM5Yeh5Lq6,size_20,color_FFFFFF,t_70,g_se,x_16)
子构造函数 继承 父构造函数!
6.1 call()方法
调用这个函数, 并且修改函数运行时的 this 指向 。
-
call()可以调用函数
-
call()可以修改this的指向,使用call()的时候 参数1是修改后的this指向,参数2,参数3。。。是函数的实参列表。
function fn(x, y) {
console.log('我想喝手磨咖啡');
console.log(this);
console.log(x + y);
}
var o = {
name: 'andy'
};
// fn();
// 1. call() 可以调用函数
// fn.call();
// 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
fn.call(o, 1, 2);
6.2 继承属性![](https://img-blog.csdnimg.cn/43015b9afef444d881c8e1ec1f54e613.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5re35rKM5Yeh5Lq6,size_20,color_FFFFFF,t_70,g_se,x_16)
-
先定义一个父构造函数
-
再定义一个子构造函数
-
子构造函数继承父构造函数的属性(使用call方法)
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例 ldh
// 3.使用call方式实现子继承父的属性【调用父构造函数,并让其this变为ldh】
Father.call(this, uname, age);
this.score = score;
}
var ldh = new Son('刘德华', 18, 100);
console.log(son);
6.3 继承方法
借用原型对象继承方法!
-
先定义一个父构造函数
-
再定义一个子构造函数
-
修改子构造函数的原型对象(new 父构造函数得到的对象)
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
七、类的本质
<script>
// ES6 之前通过 构造函数 + 原型 实现面向对象编程
// (1)构造函数有原型对象prototype
// (2)构造函数原型对象prototype里面有constructor 指向构造函数本身
// (3)构造函数可以通过原型对象添加方法
// (4)构造函数创建的实例对象有__proto__原型指向 构造函数的原型对象
// ES6 通过 类 实现面向对象编程
class Star {
}
console.log(typeof Star);
// 1. 类的本质其实还是一个函数,我们也可以简单的认为 类就是 构造函数的另外一种写法
// (1)类有原型对象prototype
console.log(Star.prototype);
// (2)类 也有原型对象,这个原型对象指向类本身
console.log(Star.prototype.constructor);
// (3)类 可以通过原型对象添加方法
Star.prototype.sing = function() {
console.log('冰雨');
};
// (4)类创建的实例对象,有__proto__原型,指向类的原型对象
var ldh = new Star();
console.dir(ldh);
console.log(ldh.__proto__ === Star.prototype);
</script>
八、ES5新增方法
8.1 数组方法forEach遍历数组
arr.forEach(function(value, index, array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
})
//相当于数组遍历的 for循环 没有返回值
8.2 数组方法filter过滤数组
var arr = [12, 66, 4, 88, 3, 7];
var newArr = arr.filter(function(value, index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value >= 20;
});
console.log(newArr);//[66,88] //返回值是一个新数组
8.3 数组方法some
some 查找数组中是否有满足条件的元素
var arr = [10, 30, 4];
var flag = arr.some(function(value,index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value < 3;
});
console.log(flag);//返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环