JavaScript系列之高级篇
Posted coderkey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript系列之高级篇相关的知识,希望对你有一定的参考价值。
一,面向对象♥
1,面向对象的编程介绍
1.1,两大编程思想
(1)含义:
面向过程和面向对象
1.2,面向过程编程 POP(Process-oriented Programming)
(1)含义:
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。
1.3,面向对象编程 OOP(Object Oriented Programming)
(1)含义:
面向对象是把事务分解成为一个一个对象,然后由对象之间分工与合作。面向对象是以对象功能来划分问题,而不是步骤。
(2)特点:
封装性、继承性和多态性。
2,ES6 中的类和对象
2.1,对象
(1)含义:
在javascript
中,对象是一组无序的相关属性和方法的集合,对象是具体的事物,所有的事物都是对象,例如字符串、数值、数组、函数等。
(2)组成:
对象是由属性和方法组成的。
2.2,类 class
(1)含义:
在ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。
类抽象了对象的公共部分,它泛指某一大类(class)。
对象特指某一个,通过类实例化一个具体的对象。
(2)特点:
1,抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)
2,对类进行实例化,获取类的对象。
2.3,创建类
(1)语法:
class name {
// class body
}
(2)创建实例:
var 变量名 = new name( );
(3)注意:
类必须使用 new 实例化对象。
(4)例如:
// 1,创建类 class
class Star {
//代码
}
// 2,利用类创建对象 new
new Star( );
2.4,类 constructor 构造函数
(1)含义:
constructor( )
方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过 new
命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给我们创建一个constructor( )
。
(2)例如:
// 1,创建类 class
class Star {
constructor(uname, age) {
this.name = uname;
this.age = age;
}
}
// 2,利用类创建对象 new
var ldh = new Star('刘德华', 20 );
var zxy = new Star('张学友', 18);
console.log(ldh.name); // 刘德华
console.log(zxy.age); // 18
(3)注意:
1,通过
class
关键字创建类,类名我们还是习惯性定义首字母大写。
2,类里面有个constructor
函数,可以接受传递过来的参数,同时返回实例对象。
3,constructor
函数,只要new
生成实例时,就会自动调用这个函数,如果不写这个函数,类也 会自动生成这个函数。
4,生成实例new
不能省略。
5,创建类,类名后面不加小括号。生成实例,类名后面加小括号,构造函数不需要加function
2.5,类中添加共有方法
(1)例如:
<script>
// 1,创建类 class
class Star {
constructor(uname, age) {
this.name = uname;
this.age = age;
}
sing(song) {
console.log(this.name + song);
}
}
// 2,利用类创建对象 new
var ldh = new Star('刘德华', 20 );
var zxy = new Star('张学友', 18);
console.log(ldh.name); // 刘德华
console.log(zxy.age); // 18
ldh.sing('冰雨');
</script>
(2)注意:
1,类里面所有的函数不需要写
function
。
2,多个函数方法之间不需要添加逗号分隔。
3,类的继承
3.1,类继承 extends
(1)含义:
子类可以继承父类的一些属性和方法。
(2)语法:
class Father {
// 父类
}
class Son extends Father {
// 子类继承父类
}
(3)例如:
<script>
class Father {
constructor( ) { }
money( ) {
console.log(100);
}
}
class Son extends Father { }
var son = new Son( );
son.money( );
</script>
3.2,super 关键字
(1)含义:
super
关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。
(2)例如:
<script>
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
// 父类中的this指向的是父类构造函数创建的实例对象
// 因为父类中的函数所访问的变量是在父类的实例对象身上去找的,
// 所以子类若想在调用的父类的方法中使用自身的变量,则需要通过super调用父类构造函数将
其值传入父类中。
sum( ) {
console.log(this.x + this.y);
}
}
// 关键字extends
class Son extends Father {
constructor(x, y) {
// 通过super调用父类的构造函数
super(x, y);
}
}
var son = new Son(1, 2);
var son2 = new Son(2, 3);
son.sum( ); // 3
son2.sum( ); // 4
// 可能出现的报错:
// ReferenceError: Must call super constructor in derived class before accessing 'this'
or returning from derived constructor
// 翻译: 当在访问this或在子构造函数return之前, 必须在子构造函数中先调用super构造函
数。
// 解释:在子类访问this或在子类的构造函数返回实例对象前,必须调用super父类构造函数
</script>
<script>
// super 关键字调用父类普通函数
class Father {
constructor( ) { }
say( ) {
// console.log('this is father');
return "this is father";
}
}
class Son extends Father {
constructor( ) {
super( );
}
say( ) {
console.log(super.say( ) + " this is son"); //在console代码中打印某函数的结果时,应该
采用return的方式返回数据,而不应该在原函数中打印,这是错误的编程方式
}
}
var son = new Son();
son.say();
// 若父类和子类含有相同的函数,则会应用就近原则,优先调用子类的函数。
</script>
<script>
class Father {
constructor(x, y) {
this.x = x
this.y = y
}
sum() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y); // super 必须在子类 this 之前调用
this.x = x // 这两句可以省略
this.y = y
}
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(4, 5)
son.subtract(); //-1
son.sum(); //9
</script>
(3)注意:
1,子类在构造函数中使用
super
,必须放到this
前面(必须先调用父类构造方法,再使用子类构造方法)
2,es6
中类没有变量提升,必须先定义类,再创建实例对象。
3,类中的共有属性和方法在访问时必须加this
。
二,对象高级
1,对象的创建模式
1.1,Object构造函数模式
(1)用法:
方式一:
Object
构造函数模式
套路:先创建空Object
对象,再动态添加属性/方法
使用场景:起始时不确定对象内部数据
问题:代码量多
(2)例如:
<script>
var p = new Object();
p.name = "tom";
p.age = 12;
p.setName = function(name){
this.name = name;
};
// 测试
p.setName("李白");
console.log(p.name,p.age);
</script>
1.2,对象字面量模式
(1)用法:
方式二:对象字面量模式
套路:使用{}
创建对象,同时指定属性和方法
适用场景:起始时对象内部数据时确定的
问题:如果创建多个对象,有重复代码
(2)例如:
<script>
var p = {
name:"tom",
age:16,
setName:function(name){
this.name = name;
}
};
// 测试
console.log(p.name,p.age);
p.setName("Jack");
console.log(p.name,p.age);
</script>
1.3,工厂模式
(1)用法:
方式三:工厂模式
套路:通过工厂函数动态创建对象并返回
适用场景:需要创建多个对象
问题:对象没有一个具体的类型,都是Object
类型
(2)例如:
<script>
function createPerson(age,name){ //返回一个对象的函数-->工厂函数
var obj = {
age:age,
name:name,
setName:function(){
this.name = name;
}
};
return obj;
}
var p1 = createPerson(16,"张三");
var p2 = createPerson(16,"李三");
console.log(p1);
console.log(p2);
function createCat(age,name){
var obj = {
age:age,
name:name,
setName:function(){
this.name = name;
}
};
return obj;
}
var c1 = createCat(15,"波斯猫")
var c2 = createCat(15,"野猫")
console.log(c1);
console.log(c2);
</script>
1.4,自定义构造函数模式
(1)用法:
方式四:自定义构造函数模式
套路:自定义构造函数,通过new创建对象
适用场景:需要创建多个类型确定的对象
问题:每个对象都有相同的数据,浪费内存
(2)例如:
<script>
// 定义类型
function Person(name,age){
this.name = name;
this.age = age;
this.setName = function(){
this.name = name;
};
}
var p1 = new Person("lisa",16);
p1.setName("bob");
console.log(p1.name,p1.age);
console.log(p1 instanceof Person);
function Student(name,price){
this.name = name;
this.price = price;
this.setName = function(){
this.name = name;
};
}
var s = new Student("熊大",1000);
console.log(s instanceof Student);
var p2 = new Person("Jack",16);
console.log(p1,p2)
</script>
1.5,构造函数+原型组合模式
(1)用法:
方式五:构造函数+原型组合
套路:自定义构造函数,属性在函数中初始化,方法添加到原型上
适用场景:需要创建多个类型确定的对象
(2)例如:
<script>
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name){
this.name = name;
};
var p1 = new Person("tom",16);
var p2 = new Person("bob",19);
console.log(p1,p2);
</script>
2,继承模式
2.1, 组合继承call( )
(1)含义:
ES6
之前并没有给我们提供 extends
继承。我们可以通过构造函数+原型对象
模拟实现继承,被称为组合继承
。
(2)语法:
// 调用这个函数,并且修改函数运行时
this
指向
fun.call(thisArg, arg1, arg2, …)
thisArg
:当前调用函数this
的指向对象。
arg1,arg2
:传递的其他参数。
(3)例如:
<script>
function fn(x, y) {
console.log(this);
console.log(x + y);
}
var o = {
name: 'adele'
}
fn(1, 2); //分别为window对象和3 this指向window
//1,fn.call( )可以调用函数
// 2,fn.call( ) 可以改变这个函数的this 指向,此时这个函数的this就指向了o这个对象。
fn.call(o, 1, 3); //输出:{name: "adele"} 和 4
</script>
(4)作用:
1,可以调用普通函数
2,可以改变this
的指向。
2.2,借用父构造函数 + call来继承属性
(1)含义:
通过 call( )
把父类型的 this
指向子类型的 this
,这样就可以实现子类型继承父类型的属性。
(2)例如:
<script>
// 父构造函数
function Father(name, age) {
this.name = name;
this.age = age;
}
// 子构造函数
function Son(name, age, sex) {
// 通过call函数改变Father函数内部this的指向,使其指向Son构造函数创建的实例对象ldh
// 从而借用父构造函数的代码为子构造函数创建的实例对象赋值,实现了逻辑上的继承属性的
关系。
Father.call(this, name, age)
this.sex = sex;
}
var ldh = new Son('刘德华', 18, '男')
console.log(ldh);
console.log(ldh.sex); // 男
</script>
2.3,借用原型对象来继承方法
(1)例如:
<script>
function Father( ) {
this.run = function( ) {
console.log('父亲喜欢跑步');
}
}
Father.prototype.work = function( ) {
console.log('父亲要工作');
}
function Son( ) {
}
// 错误方式,该代码会导致子原型对象指向父原型对象的地址,如果更改子原型对象,则实际更改的是父原型对象。
// Son.prototype = Father.prototype
// 使子原型对象指向一个父实例对象,便拥有了父构造函数的方法以及父构造函数的原型对象上的方法。
Son.prototype = new Father();
// 小问题:上述直接通过对象覆盖了子原型对象,导致了constructor指向的构造函数的改变,需要单独为其赋值。
// console.log(Son.prototype.constructor); 指向father ,需要指向son
Son.prototype.constructor = Son;
Son.prototype.exam = function( ) {
console.log('孩子要考试');
}
var ldh = new Son();
console.log(ldh);
// 打印父原型对象,正确的结果不应该包含子原型对象的方法
console.log(Father.prototype);
// 验证是否实现了继承
ldh.work( ); // 父亲要工作
ldh.run( ); // 父亲喜欢跑步
// 整个过程的描述:
// 1.先在ldh对象上找work( )和run( )
// 2.若找不到则在ldh的__proto__,即父实例对象身上找work( )和run( )
// 3.若还是找不到则在父构造函数的原型对象上找,最终找到了work( )和run( )
// 通过构造函数和原型对象实现继承的原理:(充分利用了原型链)
// 1.子对象在找不到方法时会去原型对象上找方法,
// 2.让子构造函数的原型对象指向父实例对象,则相当于子对象会去父实例对象上找方法。
// 3.若在父实例对象上找不到方法,则会去父构造函数的原型对象上找这个方法,只要找到了方
法则说明继承了父方法。
</script>
2.4,类的本质
(1)含义:
// ES6之前通过构造函数+原型实现面向对象编程
1,构造函数有原型对象
prototype
2,构造函数原型对象prototype
里面有constructor
指向构造函数本身
3,构造函数可以通过原型对象添加方法
4,构造函数创建的映例对象有__proto__
原型指向构造函数的原型对象
// ES6通过类实现面向对象编程
1,类
class
本质还是函数function
,我们也可以简单的认为类就是构造函数的另外一种写法。
2,类的所有方法都定义在类的prototype
属性上。
3,类创建的实例里面也有__proto__
指向类的prototype
原型对象
4,所以ES6
的类它的绝大部分功能,ES5
都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
5,所以ES6
的类其实就是语法糖。
6,语法糖:语法糖就是一种便捷写法、简单理解,有两种方法可以实现同样的功能,但是一种写法更加清晰、方便那么这个方法就是语法糖。
(2)例如:
<script>
class Star {
}
Star.prototype.sing = function() {
console.log('sing a song');
};
// 1.类的实质是函数,相当于构造函数
console.log(typeof Star); //function
// 2.类同构造函数一样,拥有原型对象
console.log(Star.prototype);
//3.类同构造函数一样,其原型对象上拥有constructor属性,该属性指向了类(构造函数)
console.log(Star.prototype.constructor);
var adele = new Star();
//4.类的实例对象同构造函数的实例对象一样,拥有__proto__属性,该属性指向了类的原型对象
(构造函数的原型对象)
console.log(adele.__proto__);
// 综上,ES6中的类其实是构造函数的语法糖,ES6中类的绝大多数功能都能通过ES5中的构造函
数和原型对象实现
</script>
三,ES5 中新增的方法
1,ES5 新增方法概述
(1)含义:
ES5中给我们新增了一些方法,可以很方便的操作数组或者字符串,这些方法主要包括:数组方法、字符串方法和对象方法。
(2)方法:
ES5
数组新增的方法:forEach( ),filter( ),map( ),some( ),every( )
。
find()
方法主要用来返回数组中符合条件的第一个元素(没有的话,返回undefined
)(ES6)
map()
方法主要用来对数组中的元素调用函数进行处理,并且把处理结果放在一个新数组中返回(如
果没有返回值,新数组中的每一个元素都为undefined
)(用法跟filter
类似)
every()
方法用于检测数组中所有元素是否都符合指定条件,若符合返回true
,否则返回false
; (跟some
用法相似)
2,数组方法
2.1,forEach 迭代(遍历)数组
(1)含义:
forEach( )
方法遍历数组。无返回值,用于内部操作,比如作加法器,动态添加表格元素,循环绑定事件。
(2)语法:
array.forEach(function(currentValue, index, arr) { } )
currentValue
:数组当前项的值(元素)。
index
:数组当前项的索引。
arr
:数组对象本身。
(3)例如:
<script>
var arr = [1, 2, 3, 4, 5]
var sum = 0
arr.forEach(function(value, index, array) {
console.log('每个数组元素:' + value);
console.log('每个数组元素的索引号:' + index);
console.log('数组本身' + array);
sum += value
})
console.log(sum); // 15
<script>
2.2,filter 筛选数组
(1)含义:
filter( )
方法创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组。
(2)语法:
array.filter(function(currentValue, index, arr) { } )
currentValue
:数组当前项的值(元素)。
index
:数组当前项的索引。
arr
:数组对象本身。
(3)注意:
1,它直接返回一个新数组。
2,把所有满足条件的数组元素返回回来。
(4)例如:
<script>
var arr = new Array(2, 3, 4, 6, 9);
var newArr = arr.filter(function (value, index, array) {
// 满足条件的每一个元素会被添加到一个新数组中,最后会返回新生成的数组
return value % 2 === 0;
});
console.log(newArr); // [2, 4, 6]
</script>
2.3,some 查找数组中是否有满足条件的元素
(1)含义:
some( )
方法用于检测数组中的元素是否满足指定条件,通俗点就是查找数组中是否有满足条件的元素。
(2)语法:
array.some(function(currentValue, index, arr) { } )
currentValue
:数组当前项的值(元素)。
index
:数组当前项的索引。
arr
:数组对象本身。
(3)注意:
1,它返回值是布尔值,如果查找到这个元素,就返回
true
,如果查找不到就返回false
。
2,如果找到第一个满足条件的元素,则终止循环,不在继续查找。
(4)例如:
<script>
var arr = ["apple", "banana", "orange"];
var boolean = arr.some(function (value, index, array) { // 后面两个参数可以省略
// 当查找到该元素时,直接return一个true值,后面的元素不会再查找比较。可以通过浏览器
调试工具debug验证
return value === "banana";
});
console.log(boolean); // true
</script>
3,字符串方法
3.1,trim 方法去除字符串两侧空格
(1)含义:
trim( )
方法会从一个字符串的两端删除空格字符。
(2)语法:
str.trim( )
(3)注意:
trim( )
方法并不影响原字符串本身,它返回的是一个新的字符串。
(4)例如:
var str = ‘ ldh ’
var newstr = str.trim( );
console.log(newstr); // ldh
4,对象方法
4.1,Object.keys 方法遍历对象属性
(1)含义:
Object.keys( )
用于获取对象自身所有的属性。
(2)语法:
Object.keys(obj)
(3)注意:
1,返回一个由属性名组成的数组。
2,效果类似for…in
(4)例如:
<script>
var obj = {
name: 'ldh',
age: 12,
sex: '男'
}
console.log(Object.keys(obj)); //['name','age','sex']
// 通过Object.keys可以获取一个对象含有的属性的个数
console.log(Object.keys(obj).length);
</script>
4.2,Object.defineProperty( )
(1)含义:
Object.defineProperty( )
定义新属性或修改原有的属性。
(2)语法:
Object.defineProperty( obj, prop, descriptor )
descriptor
说明:以对象形式{ }
书写value
:设置属性的值,默认为underfined
。
writable
:值是否可以重写。true
或false
,默认为false
。
enumerable
:目标属性是否可以被枚举。true
或者false
。
configurable
:目标属性是否可以被删除或是否可以再次修改特性true
或者false
,默认为false
。
(3)例如:
<script>
var obj = {
id: 1,
name: 'xiaoming',
};
// 1,原始的添加属性的方式
obj.age = 19
// 2,通过Object.defineProperty添加属性
//注意sex需要加引号,若sex存在,则覆盖;不存在,则添加。
Object.defineProperty(obj, 'sex', {
value: '男',
writable: true,
//是否可以重写,默认值为false
enumerable: true,
//是否可以通过Object.keys()遍历,默认为false
configurable: false
//是否可以删除该属性以及修改enumerable和configurable,默认为 false
});
obj.sex = '女';
delete obj.sex; //若configurable为false,则删除是无效的
//若configurable为false,则下面的代码会报错
// Object.defineProperty(obj, 'sex', {
// enumerable: false,
// configurable: true
// });
console.log(obj);
console.log(Object.keys(obj));
Object.defineProperty(obj, 'age', {
value: 22,
// writable: false
});
console.log(obj);
obj.age = 23;
console.log(obj);
console.log(Object.keys(obj));
delete obj.age;
console.log(obj);
</script>
(4)注意:
1,直接通过对象.属性 方式创建的属性,其值可以被重写,可以被遍历出,可以被删除。
2,通过Object.defineProperty( )
创建的属性默认是重写无效,无法被遍历,无法被删除的。
以上是关于JavaScript系列之高级篇的主要内容,如果未能解决你的问题,请参考以下文章