一、类和对象
- super必须放在子类this之前
- constructor里面的this指向实例对象
- 方法里面的this指向这个方法的调用者
1.1 静态成员和实例成员
通过构造函数来实现类
- 实例成员:就是构造函数内部通过this添加的成员;实例成员之恶能通过实例化对象来访问
var ldh = new Star('刘德华');
console.log(ldh.name); //name为实例成员
ldh.sing(); //sing为实例成员
- 静态成员:在构造函数本身上添加的成员
Star.sex = '男';
console.log(Star.sex); //sex为静态成员
1.2 原型对象
2.2.1 prototype
- 构造函数通过原型分配的函数是所有对象所共享的;
- 每一个构造函数都有一个prototype属性;
- 可以把一些不变的方法直接定义在prototype对象上,这样所有对象的实力可以共享这些方法;(节省空间)
Star.prototype.sing = function(){
console.log("I can sing");
}
公共属性定义到构造函数上,公共的方法放到原型对象身上;
1.2.2 __proto__(对象原型)
对象身上系统自己添加一个__proto__指向构造函数的原型对象prototype;只是指明了一条路;
查找方法:先找对象里是否有函数,如有则执行;若没有就通过__proto__访问原型对象里的函数;
1.2.3 constructor
- constructor表示是通过哪个构造函数创建的对象;
- 很多情况下需要手动的利用constructor这个属性指回原来的构造函数(why?)
Star.prototype = {
sing: function(){
console.log('I can sing.');
},
moive: function(){
console.log('I can act a moive.');
}
}
此时通过 { } 对象覆盖了Star.prototype,相当于修改了原来的原型对象;所以必须要手动指回;
增添:
Star.prototype = {
constructor: Star,
...
}
1.3 原型链
- Star原型对象里面的__proto__原型指向的是Object.prototype
- Object.prototype原型对象里面的__proto__原型,指向为null
JS的成员查找机制:(就近原则,找到就不往上找了)
- 当访问一个对象的属性(方法)时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
- 如果还没有就查找原型对象的原型(Object的原型对象)
- 依此类推一直找到Object为止(null)
- __proto__对象原型的意义就在于为对象成员查找机制提供一个方向
1.4 原型对象中的this指向
- 构造函数里的this指向的是实例对象(调用者)
- 原型对象里的this指向的是实例对象(调用者)
1.5 组合继承
1.借用父构造函数继承属性:
function Father(uname, age){
this.uname = uname;
this.age = age;
}
function Son(uname, age){
Father.call(this, uname, age);
}
//call的第一个作用:调用函数
//call的第二个作用:改变函数内的this指向
//call的主要作用:实现继承
2.借用原型对象继承方法
Son.prototype = Father.prototype;
//这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会被改变(浅拷贝)
Son.prototype = new Father();
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;
Son.prototype.exam = function(){
console.log("孩子要考试");
}
1.6 类的本质(语法糖)
- 类有原型对象
- 类原型对象prototype里面有constructor指向类本身
- 类可以通过原型对象添加方法
- 类实例对象有__proto__原型指向构造函数的原型对象
ES5新增的方法:
1.forEach:forEach的return只能中止当次循环,而无法停止循环;
arr.forEach(function(currentvalue, index, array){ //value 当前项的值,index 当前项的索引,array调用的数组 });
2.filter()
//直接返回一个新数组 var newarr = arr.filter(function(currentValue, index, arr){ return value >= 20; });
3.some():能找到就需要返回true,只找第一个;
var flag = arr.some(function(value){ return value === 'ThingsYouAreLookingFor'; });
4.trim():取出字符串的两端空白字符,返回新的字符串
5.定义对象中新属性或修改原有的属性
//Object.defineProperty(Object, Property, Descriptor); Object.defineProperty(obj, 'num', {value:1000});
Object.defineProperty(obj, 'id', { //是否允许重写 writable:false, //是否允许通过Object.keys获取 enumerable:false, //不允许删除属性 & 修改特性 configurable: false });
6.获取自身所有的属性:通过数组返回
var arr = Object.keys(obj);
二、函数进阶
//1.命名函数
function fn() {};
//2.函数表达式(匿名函数)
var fun = function() {};
//3.利用new Function('参数1', '参数2', '函数体');
var f = new Function('a', 'b', 'console.log(a+b)');
改变函数内部this指向:
- fn.call();往上看
- fn.apply();
apply与call的不同之处是,它的参数必须是数组(伪数组),在函数内取数组内的值
apply的主要应用:借助与数学内置对象求最大值
let arr = [3,2,4,1,8,6]
let maxValue = Math.max.apply(Math,arr);
console.log(maxValue);
- fn.bind();返回原函数的拷贝函数;使用需求:不需要立即执行
var btn = document.querySelector('button');
btn.onclick = function(){
this.disabled = true;
setTimeout(function(){
this.disabled = false;
}.bind(this), 3000)//这里的this指向的是btn这个对象
}
三、新特性
3.1 严格模式
'use strict'
- 变量必须先声明再使用
- 不能随意删除已声明好的变量
- 严格模式下全局作用域中的函数中的this是undefined
- 如果构造函数不加new调用,this指向的是undefined,如果给它赋值则会报错
- 定时器里的this还是指向window
- 不允许函数中的参数重名
- 函数必须声明在顶层,不在if里声明
3.2 高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出;函数也是一种数据类型,同样可以错位参数,传递给另一个参数使用;(回调函数)
3.3 闭包
闭包是指有权访问另一个函数作用域中的变量的函数;变量所在的函数就是闭包;
闭包的主要作用:延伸了变量的作用范围;
var lis = document.querySelector('.nav').querySelectorAll('li');
for(var i = 0; i < lis.length; i++){
lis[i].onclick = function(){
console.log(i); //输出4
}
}
for(var i = 0; i < lis.length; i++){
//立即执行函数也称为小闭包,因为立即执行函数里面的任何一个函数都可以使用它的i这个变量
(function(i){
lis[i].onclick = function(){
console.log(i);
}
})(i)
}