JavaScript--面向对象
理解对象
xxx语言中一切皆为对象!
- 什么叫面向对象?
对象(object),台湾译作物件,是面向对象(Object Oriented)中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。
在软件系统中,对象具有唯一的标识符,对象包括属性(Properties)和方法(Methods)
,属性就是需要记忆的信息,方法就是对象能够 提供的服务。在面向对象(Object Oriented)的软件中,对象(Object)是某一个类(Class)的实例(Instance)。 —— 维基百科
特性:
封装:
把类同事物的相同的属性和方法封装到一个对象中。
继承:
继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。
多态:
多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
es5 -- 继承
function Person(name, age) {
this.name = name;
this.age = age;
this.work = function() {
console.log("正在工作")
}
}
Person.prototype.sex = "男";
Person.prototype.run = function() {
console.log("正在跑步")
}
let p = new Person("李四", 20);
function Sub(name, age) {
Person.call(this, name, age);// 构造函数继承:缺点没有继承原型的属性和方法
this.address = "beijin"// 字类的特有属性
}
// Sub.prototype = Person.prototype;// 原型链的继承: 继承了父类原型上的方法;但是这样写会导致 字类添加原型的方法时会影响父类的原型。
Sub.prototype = Object.create(Person.prototype);// 这样写解决,子类影响父类的问题;w但是控制的台打印出字类的结构,会把字类原型方法和父类原型方法分离开,这样会多出一个层级。对查找不够友好
Sub.prototype = Object.assign(Person.prototype);// 这样写解决, 字类的结构和父类的结构一样样。
Sub.prototype.study = function() {
console.log("正在学习");
}
let s = new Sub("子类", 100);
效果:
-
使用 Object.assign 错误的
12.jpg
-
使用 Object.create 正确的
22.png
es6 -- 继承
class Person {
constructor(name, age) {
//表示当前类的属性和方法
this.name = name;
this.age = age;
this.work = function() {
console.log("正在工作")
}
}
static test() { //等同于 es5 Person.test
console.log("类的静态方法")
}
// 表示原型的方法: 等同es5 Person.propetype.work
run() {
console.log("正在跑步")
}
}
let p = new Person("lisi", 20);
//extends:等同 es6 Sub.prototype = Object.create(Person.prototype); 原型链继承
class Sub extends Person {
constructor(name, age) {
//等同 es5 Person.call(this, name, age); 构造函数继承
super(name,age);
}
study() {
console.log("正在学习")
}
}
let s = new Sub("子类",100);
oop面向对象编程
在前端开发中,我们需要把一些常用的功能和效果,要封装到一个js中,这样方便我们以后的重复使用。
我们要通过 面对对象编程
学会封装插件的能力。
封装插件(OOP)
- 原生js 封装 (通过封装插件)
// Javascript
/* 创建一个构造函数 */
function FreeSlider(selector,speed) {
/* 变量改为属性 */
this.oContainer = document.querySelector(selector);
this.oWrapper = this.oContainer.querySelector('ul');
this.oSlide = this.oWrapper.querySelectorAll('li');
/* 当不传入轮播速度时,速度默认为100 */
this.speed = speed || 100;
this.containerW = this.oContainer.offsetWidth;
this.wrapperW = this.oSlide[0].offsetWidth * this.oSlide.length;
this.x = 0;
this.timer = null;
this.init();
}
/* 构造函数的原型对象 */
FreeSlider.prototype = {
constructor: FreeSlider,
/* 功能抽离,此处实现初始化 */
init: function(){
this.oWrapper.style.width = this.wrapperW * 2 + 'px';
this.oWrapper.innerHTML += this.oWrapper.innerHTML;
if(this.wrapperW < this.containerW){
this.oContainer.style.width = this.wrapperW + 'px';
}
this.slideMove();
},
/* 图片自动无限轮播 */
slideMove: function(){
/* 此处需要注意this的指向,
在setInterval回调函数中的this指向为window */
var that = this;
this.timer = setInterval(function () {
that.x++;
if(that.x > that.wrapperW){
that.x = 0;
}
that.oWrapper.style.transform = 'translate('+ (-that.x) +'px)';
},this.containerW / this.speed); // 将速度转化成定时器时间
},
/* 图片停止轮播 */
stopSlideMove: function () {
clearInterval(this.timer);
}
};
window.onload = function(){
var oContainer = document.querySelector('.container');
// 新建图片轮播对象
var mySlider = new FreeSlider('.container',300);
// 鼠标移入时清除定时器,图片停止轮播
oContainer.addEventListener('mouseover',function () {
mySlider.stopSlideMove();
});
// 鼠标移出时图片继续轮播
oContainer.addEventListener('mouseout',function () {
mySlider.slideMove();
});
}
- 基于jquery封装
(function($,window) {
//common方法封装到jQuery类对象里
$.extend({
debounce:function (fn,wait) {
let timer = null;
return function () {
if(timer) {
window.clearTimeout(timer);
}
let _this = this;
let args = arguments;
timer = setTimeout(() => {
fn.apply(_this, args)
}, wait);
}
}
})
//轮播切换封装到jQuery对象方法
$.fn.indexBannerScroll = function(options) {
var opts = $.extend({},$.fn.indexBannerScroll.defaults,options);
return this.each(function(){
var $this = $(this),
listContent = $this.find(".list"),// 如果是滚动切换时,这个是 子容器k 800 px
carouselItem = $this.find(".item"),//所有的轮播盒子
points = $this.find(".point"),//所有的点
carouselLength = carouselItem.length,//轮播的个数
currentIndex = 0,//当前对应索引
imgWidth = carouselItem.eq(0).width(),
prevBtn = $this.find(".prevBtn"),//上一个按钮
nextBtn = $this.find(".nextBtn"),//下一个按钮
speed = opts.speed,//延时时间
type = opts.type,// 切换的类型 如果是0 表示 显示隐藏 ; 如果是1表示 图片滚动
timer = null;//定时器 自动轮播用的
//先默认给第一个盒子添加激活 类
$this.find(".item:first-child").addClass("active");
// 图片切换
function bannerScroll() {
//圆点变化
points.eq(currentIndex).addClass("active2").siblings().removeClass("active2");
//图片变化
carouselItem.eq(currentIndex).addClass("active").siblings().removeClass("active");
}
//图片切换效果2
function bannerSilde() {
//圆点变化
points.eq(currentIndex%points.length).addClass("active2").siblings().removeClass("active2");
//图片的变化
listContent.stop().animate({
left: `-${(currentIndex + 1) * imgWidth} `
},1000,function () {
if(currentIndex == points.length) {
currentIndex = 0;
listContent.css("left", `-${(currentIndex + 1) * imgWidth}px`)
}else if(currentIndex == -1 ) {
currentIndex = points.length - 1;
listContent.css("left", `-${(currentIndex + 1) * imgWidth}px`)
}
})
}
//上一个按钮
prevBtn.click($.debounce(prevMethod,400))
//下一个按钮
nextBtn.click($.debounce(nextMethod,400))
//下一个的方法
function nextMethod() {
currentIndex ++;
currentIndex = currentIndex > carouselLength - 1? 0 : currentIndex;
if(type=="0") {
bannerScroll()
}else if(type == "1") {
bannerSilde()
}
}
//上一个方法
function prevMethod() {
currentIndex --;
currentIndex = currentIndex < 0? carouselLength - 1 : currentIndex;
console.log(currentIndex)
if(type=="0") {
bannerScroll()
}else if(type == "1") {
bannerSilde()
}
}
//指示点按钮
points.click(function(e) {
currentIndex = $(this).attr("data-index");
if(type=="0") {
bannerScroll()
}else if(type == "1") {
bannerSilde()
}
})
var timer = setInterval(function() {
// nextBtn.click();
},speed)
})
}
$.fn.indexBannerScroll.defaults = {
speed: 1900
}
// 异步效果显示(针对多个元素的效果)
$.fn.asyncAnimation = function(options) {
var opts = $.extend({},$.fn.asyncAnimation.defaults, options );
return this.each(function() {
var $this = $(this),
list = $this.find("li"),
delay = opts.delay,
cssAttr = opts.cssAttr.toString(),
cssValue = opts.cssValue;
function setAnimation($el) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let obj = Object.create(null);
obj[cssAttr] = cssValue;
$el.css(obj)
resolve()
}, delay)
})
}
async function excutor() {
for(let i = 0; i < list.length; i ++) {
await setAnimation(list.eq(i), 300)
}
}
excutor();
})
}
$.fn.asyncAnimation.defaults = {
delay: 300,
cssAttr: "animation",
cssValue:"img-show .5s 0.3s linear forwards"
}
//图片和文字悬浮效果(针对单个元素内嵌多个元素 效果)
$.fn.pictureTextAnimation = function(options) {
var opts = $.extend({},$.fn.pictureTextAnimation.defaults, options);
return this.each(function() {
var $this = $(this),
pircure = $this.find("img"),
text = $this.find(".text-wrap"),
overCss = opts.overCss,
outCss = opts.outCss;
$this.hover(
function() {
text.css({
"animation": overCss
})
},
function() {
text.css({
"animation": outCss
})
},
)
})
}
$.fn.pictureTextAnimation.defaults = {
overCss:"",
outCss:""
}
})(jQuery,window);
总结
只是让你知道,任何一门语言思维模式很重要,其次,掌握最底层的原生js的API。
- JS插件其实没有你想象的那么难,基本原理就是面向对象
- 将需要可灵活配置的部分作为构造函数的参数传入,插件中的各个功能可作为原型方法提供给外部调用。
当你可以把常用的效果通过面向对象编程封装后,你就可以通封装自己的UI库,不管通过vue中的UI框架,还是react中的UI框架,最底层还是自己会原生js操作api和处理业务逻辑能力
网友评论