JS高级 —— 面向对象,ES6和ES5对比学,很好的学习资料!!!
类
- ES6 2011年开始制定,2016年发布。ES6才有class,之前没有类概念,通过构造函生成对象。
//类
class Star{
//构造函数(不写会默认一个。为类公有属性赋值)
constructor(uname){
this.unmae=uname;//【this指向new时创建的对象,函数里this指向调用者】
}
//函数
sing(song){
console.log('唱歌'+song);
}
}
var aa=new Start('刘德华');//创建类的对象
aa.sing('冰雨');
继承
class Father{
constructor(x,y){
this.x=x;
this.y=y;
}
money(){
console.log(this.x+this.y);
}
}
class Son extends Father{
constructor(x,y){
super(x,y);//调用父类构造函数
}
}
var ss=new Son(1,2);
ss.money();//子类继承父类方法
ES5面向对象
- 构造函数原型对象(prototype),是一个对象,作用:为所有对象所共享公共方法。
JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。 不变的方法放到prototype上,所有对象都共享了,方法不必重复出现在每个对象中。 - 每个对象都会有
__propto__
,它指向的就是prototype,所以每个对象能用prototype方法。 console.dir()
可以显示一个对象所有的属性和方法.- 构造函数、实例、原型对象三者之间的关系:见图
- 原型链
__proto__
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
function Star(uname,age){
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌");
}
Star.prototype.sex ='女';//在Star原型上注册成员sex
Object.prototype.sex ='男';//在Object原型上注册成员sex
var ldh = new Star('刘德华',18);
console.log(ldh.sex);//如果对象ldh有sex则取对象上的,没则找Star原型prototype里的,没则继续到object原型prototype找,最终仍然没有则返回undefined。
- 函数里面this,指向调用者。一般调用者是window。
- 函数
call
—— 调用函数,改变this指向。
function fn(){
console.log(this);
}
fn();//调用函数fn
fn.call();//调用函数fn【this指向window对象】
var o={name:'tome'};
fn.call(o);//里面this指向了o对象【改变this指向】。
- ES6之前并没有提供extends继承。是通过
构造函数+原型对象
模拟实现继承,被称为组合继承 - 继承核心原理:通过
call()
把父类型的this指向子类型的this,这样就可以实现子类型继承父类“属性”(主要作用)。
/*借用父构造函数继承【属性】*/
// 1.父构造函数
function Father(uname,age) {
// this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money=function(){
console.log('家产100元');
};
//2.子构造函数
function Son(uname, age,s) {
//this指向子构造函数的对象实例
Father.cal1(this, uname, age);//把父构造函数this指向了子构造函数对象。
this.score=s;
}
//Son.prototype=Father.prototype; —— 如此子继承父所有方法,违反了继承,因为这样是把父prototype地址给了子类。子类加个方法父也会有
Son.prototype=new Father();//【子继承父所有方法】
Son.prototype.constructor = Son;//如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.exam=function(){//子构造函数特有方法。
console.log('孩子要考试!');
};
var son = new Son('刘德华',18,100);
console.log(son);
console.log(Father.prototype);
函数
函数三种定义方式
(所有函数是Function的实例,故函数也是对象,是对象就有__proto__
—— js里万物皆对象)
// 1.自定义函数(命名函数)
function fn() {}
// 2.函数表达式(匿名函数)
var fun = function(){};
// 3.利用 new Function('参数1','参数2','函数体');(Function是构造函数,使用场景:代码执行到此处时从后台取要执行的js代码段。如不同客户同一表单的校验不同,为他们订制的js校验代码存库,如此实现一套代码,胜任各种客户需求)
var f= new Function('a','b','console.log(a+b);');
f(1,2);//调用
-
new Function()
原型链
-
函数的六种调用方式及this指向
1.普通函数 —— 方法名称();或 方法名成.call(); this指向调用者即window(因为window.方法每次())
2.对象的方法 —— var obj={sayHi:function(){}}; obj.sayHi(); this指向调用者即具体对象
3.构造函数 —— var tome = new People(); this指向调用者即具体对象
4.绑定事件函数 —— btnSave.onclick=function(){};//点击按钮时调用 this指向调用者即btnSave按钮
5.定时器函数 —— setInterval(function(){},1000);//定时器每1s自动调 this指向调用者即window
6.立即执行函数 —— (function(){})();//立刻自动调用执行 this指向调用者即window
- 用
call、bind、apply(单词:应用)
可以改变函数this指向。
* apply--【函数名.apply(对象,数组)】调用函数。简单理解为调用函数,它可以改变函数的this指向。
var arr = [1,166,3,99,4];
var max = Math.max.apply(Math,arr);//求最大
* bind--【函数名.bind(对象,参数1,...)】不会调用函数。仅能改变函数内部this指向。【使用最多】
var f= fn.bind(obj);//改变fn函数的this指向然后copy给f
f();
//使用场景:如果有的函数不需要立刻执行,又想改变函数内的this,就用bind。
var btn = document.queryselector('button');
btn.onclick = function() i
this.disabled = true;//这个this指向的是 btn这个按钮
{//that化确保操作btn对象
var that = this;
setTimeout(function(){
that.disabled = false;//定时器函数里面的this指向的是window,用变量that
},3000);
}
{//bind 改变定时器this
setTimeout(function(){
this.disabled = false;//bind把this指向为btn对象
}.bind(btn),3000);//等于 }.bind(this),3000);
}
}
'use strict';
严格模式 ES5出的,IE10+支持。
闭包
- 闭包,一个函数有权访问另一个函数作用域内变量。闭包是一种现象,意义:延伸了变量作用范围。如下:
function fn() {
var num = 10;
function fun() {
console.log(num);//fun函数访问fn函数变量num,产生闭包
}
fun();
}
fn();
//Demo2
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++){
(function(i){
setTimeout(function(){
console.log(lis[i].innerHTML);
},3000)
})(i);
}
正则表达式:
var rg = new RegExp(/123/); //正则表达式简单字面量写法:var rg=/123/;
rg.test(123);//校验变量是否符合正则表达式,返回true则符合。
- 菜鸟网站,常用正则表达式大全
var a= '123abca'.replace(/a|c/g,'啊');
(a和c都替换为啊)其中的//g
是全局匹配。//i
忽略大小写;//gi
全局匹配+忽略大小写
结构赋值
let [c,d,f]=[1,2,0];//分别给变量c/d/f赋值
let pe={name:'aa',age:12};
let {name,age}=pe;//变量name、age必须与pe里面一致
let {name : myName , age: myAge} = pe;//myName是变量了
let [s1,...s2]=[1,2,3];//1给s1,2和3给了数组s2
扩展运算符
let arr=[12,3];
let bb=[4,5];
let cc=[...arr,...bb];//两个数组合并(没去重)
arr.push(...bb);//bb放入arr
arr.includes(2);
arr若包含2则返回true。代替arr.indexOf(2)>=0
'hi abc'.startsWith('hi');
是否以某串开头,endsWith
是否以某串结尾。
Set数据结构
- Set类似Array,其成员的值是唯一的,没有重复。利用它可以去重。
let mySet=new Set([1,1,3,4]);//返回1,3,4数组
mySet.size;//长度3
mySet.add(3);//添加值
mySet.delete(3);//删除
mySet.has(3);//是否有3
mySet.clear();//清空
let arr=...mySet;//转成数组
mySet.forEach(v=>console.log(v));