五大模式(原型模式)

    技术2025-10-28  6

    单例模式

    把描述同一个事物特征的信息进行分类归组,放到同一个命名空间下(减少全局变量的污染) var name = "邢"; var age = 21; var sex = "男"; var name = "刘"; var age = 21; var sex = "男"; // var xing = { name: "邢", age: 21, sex: "男" }; var liu = { name: "刘", age: 21, sex: "男" }; //描述同一个对象的所有属性放在对象中,避免了全局变量的干扰,"单例模式" var timer = 1; var xing = { bar: function () { }, fn: function () { } }; // var timer = 1; var liu = { bar: function () { } }; ----------------------------------------------------- var name = 'erYa'; var age = 18; var name = 'jinYu'; var age = 22; let person1 = { name: 'erYa', age:18 }; let person2 = { name: 'jinYu', age: 22 }

    高级单例模式

    //高级单例模式 //jquery的源码的外层是采用了高级单例模式 var utils = (function () { var timer = 1; var num = 100; return { bar: function () { }, fn: function () { } } })() //与单例模式相比,想使用同一变量,可以避免污染全局 -------------------------------------------------- let person1 = (function(){ let fn = function(){}; let name= 'erYa'; return { name:name, age:18, fn:fn } })() let person2 = (function(){ let fn = function(){}; let name= 'jinYu'; let age = 18; return { name:name, fn:fn } })() let person3 = function(){ let name= 'jinYu'; let age = 26 return { name:name, fn:fn } } console.log(person3) // 这是一个函数,不是person3的个人信息

    工厂模式

    如果用单例模式去写很多个person就会变得很麻烦,就有了工厂模式 特点:批量生产把实现相同功能的代码封装到函数里,以后想运行这个方法,就直接执行这个函数就好了高内聚:提高代码的复用率低耦合:减少页面的重复代码 //工厂模式: 函数的封装 function createStudent(name, age) { var obj = {} obj.name = name; obj.age = age; return obj; }; var xing = createStudent('邢', 21); var liu = createStudent('刘', 21);

    对象前言

    javaScript 面向对象: 基于对象 对象: 万物皆对象 类: 指具有相同特征的一类事物 实例:具体的一个事物:

    内置类 : Number String Boolean Null Undefined Object Array RegExp Date …类一定是个函数,但函数不一定是类;

    面向对象

    把抽象的对象按照特点进行分类(大类/小类),把类的公共特征进行提取和封装,放到对应的类别中类就是对对象的一种细分,和公共部分的抽取在类中具体派生出来的具体事物就是类的实例,而且实例拥有自己私有的特征,还拥有所属类上的特征我们研究面向对象,其实就是研究对象、类、实例之间的关系和各自的知识点

    构造函数模式(构造自定义类)

    构造函数解决了实例的私有属性

    var f=new Fn();new 操作符——把 new 放在函数的前面,函数执行构造函数就是让我们创建自定义类new 函数执行 叫做构造函数运行模式,此时的Fn就是Fn类(构造函数),函数执行之后的返回结果就是一个对象,叫做实例对象(f就是Fn的实例)类就是函数数据类型的实例是对象数据类型构造函数中的this指向当前实例 如果这个函数需要参数,那么这个需要有小括号,如果不需要参数,那么小括号可以省略 new后面的函数就是构造函数,也叫类;那么通过new函数得到的返回值就叫实例;实例是构造函数new出来的; > 钩子函数:在初始化实例时会默认调用原型上的一些方法,那么这些方法就是钩子函数

    运行原理

    1、在代码执行之前,函数中会首先默认创建一个空对象 {}2、让当前函数里的this指向这个对象3、代码执行4、默认return 这个对象

    let f1 = new Fn(‘erYa’, 18); //原型三句话 //f1就是Fn的实例 //fn就是函数,也是自定义(Fn)类 //f1就是实例化的对象

    //let f3 = new Fn; 如果构造函数不传实参,可以省略执行小括号 new 函数执行 叫做构造函数运行模式,此时的Fn就是Fn类(构造函数),函数执行之后的返回结果就是一个对象,叫做实例对象(f就是Fn的实例)

    function fn() { // var obj = {}; // this = obj; this.name = 100; // return this; }; var f = new fn; fn(); console.log(f); /* 刚才那些都是js的内置类,但是我们也可以自己去自定义一些类 */ // 构造函数(构造自定义类) function Fn(name, age) { /* 形成私有作用域 形参赋值 变量提升 1、默认生成一个空对象 {} 2、让函数里的this指向这个对象 3、代码执行 4、默认return 这个对象 */ this.name = name; // 给this增加键值对 this.age = age // 给this增加键值对 this.say = function(){} return {} } // new: 他是js里的关键字 Fn() // 普通函数运行 let f = new Fn() // {} let f1 = new Fn('erYa', 18); //原型三句话 //f1就是Fn的实例 //fn就是函数,也是自定义(Fn)类 //f1就是实例化的对象 let f2 = new Fn('jinYu', 18); let f3 = new Fn;//如果构造函数不传实参,可以省略小括号 let f4 = Fn; console.log(f) console.log(f1) console.log(f2) console.log(f1.age === f2.age) console.log(f1.say === f2.say) console.log(f3) console.log(f4) // new 函数执行 叫做构造函数运行模式,此时的Fn就是Fn类(构造函数),函数执行之后的返回结果就是一个对象,叫做实例对象(f就是Fn的实例)

    构造函数和普通函数的不同

    JS为了区分构造函数和普通函数,一般将构造函数首字母大写;

    运行上的不同 普通函数–>形成私有作用域–>形参赋值–>变量提升–>代码执行–>作用域是否销毁构造函数–>形成私有作用域–>形参赋值–>变量提升–>默认生成一个对象–>把this指向这对象–>代码执行–>默认把这个对象return出去–>作用域是否销毁 执行上的不同 构造函数如果不传实参,可以不加小括号 构造函数如果手动return一个基本数据值,不能改变人家的返回值,但是手动return引用数据类型,可以改变构造函数的返回值,此时return的东西已经不是当前类的实例了【所以不要轻易修改构造函数的返回值】 function Fn(n) { let m = 10; this.total = m + n; this.say = function () { console.log(this.total) } } let f1 = new Fn(10); let f2 = new Fn(20); console.log(f1.n)//undefined console.log(f2.m)//undefined console.log(f1.total)//20 f2.say()//30 console.log(f1 === f2)//false

    创建实例的方式

    字面量创建实例的方式 let num = 1; let str = 'w'; 构造函数创建实例的方式 // 实例创建 var num = new Number(1); console.log(typeof num);// "object" console.log(num instanceof Number);//true console.log(num);//Number {1} console.log(num+1);//2 console.log(num == 1 )//比较true,绝对比较就是false // 如果是数字并且只有一个参数,代表数组的length;如果大于等于两个,那么是数组的每一项; var arr = new Array(100,200); console.log(arr);//[100, 200] console.log(typeof Array);// "function" var arr = new Array("a") console.log(arr);//["a"] ------------------------------------------------------------------------ let ss = new Number(1) console.log(ss) console.log((1).toFixed(2)) // '1.00' 把数字转换为字符串,保留指定位小数 console.log(ss.toFixed(2)) // '1.00' let w = new String(3) // 创建一个字符串的实例 console.log(w) console.log(w.substr) // f//.substr字符串里的方法 console.log(w instanceof String) // true

    检测当前实例是否属于某个类

    使用instanceof是检测当前实例是否属于某个类实例 instanceof 类,如果实例是属于这个类,那就返回true,反之就是false通过字面量方式创建的基本数据类型值不是一个标准的实例,不能使用instanceof 进行检测;引用数据类型创建的就是一个标准的实例,可以使用instanceof来进行检测;

    局限性

    instanceof不能检测基本数据类型,只能检测引用数据类型的值 // 字面量方式创建变量 // var num = 1;// num 是Number的一个实例吗?是 // console.log(num instanceof Number);// false // var obj = {}; // console.log(obj instanceof Object);// true // var ary = []; // console.log(ary instanceof Array);// true -------------------------------------------- function Fn(name, age){ this.name = name; this.age = age; } let f1 = new Fn; console.log(f1 instanceof Fn) // true console.log(1 instanceof Fn) // false

    给实例的类封装公共方法需要注意的几点

    你自己封装的方法不能与人家内置的方法同名给你自己的方法加前缀 //去重 function myUnique(){ console.log(this) let obj = {}; for (var i = 0; i < this.length; i++) { if(obj[this[i]] !== undefined){ this[i] = this[this.length-1]; this.length--; i--; continue; } obj[this[i]] = this[i] } } Array.prototype.myUnique = myUnique; console.log(ary.myUnique().sort().reverse().slice(1,3)) // 内置类的链式扩展:如果你想用链式调用,前提是你的方法的返回值必须是当前类的实例

    原型模式

    原型模式: 构造函数解决了对象实例中私有属性的问题,原有模式解决了对象实例中公有属性的问题;如果将实例的私有属性放到了公有属性上,减少了堆内存的开辟;

    原型解决了实例的公有属性

    每一个函数(普通函数,构造函数)都天生自带一个prototype属性,属性值是一个对象,它里面存储的是实例的公有属性(原型)每一个原型都天生自带一个constructor属性,其属性值指向当前原型所属的类每一个对象都天生自带一个__proto__属性,其属性值指向当前实例所属类的原型

    原型链

    在对象里查找-一个属性,先看自己私有的有没有,如果自己没有,就通过__ proto__ 属性找 到当前所属类的原型上,如果原型上有,就直接用,如果没有,继续通过原型的__ proto__ 继续往所属类的原型上找,直到找到Object类的原型上找,如果还没有,就是undefined, 这种级- 一级一级向上查找就会形成原型链 function Fn(x, y) { this.x = x; this.y = y; this.getX = function () { console.log(this.x); } } Fn.prototype.getX = function () { console.log(this.x); } Fn.prototype.getY = function () { console.log(this.y); } var f1 = new Fn(100, 200); f1.__proto__.a = 300; var f2 = new Fn(100, 200); console.log(f1.getX == f2.getX);//false console.log(f1.getY == f2.getY);//true console.log(f1.x == f2.x);//true console.log(Fn.prototype.getX === f1.getX);//false console.log(Fn.prototype.getX === f1.__proto__.getX);//true f1.getX()//100 Fn.prototype.getX();// undefined f2.__proto__.getX();//undefined Fn.prototype.getY();//undefined console.log(f1.a);//300 console.log(f1.toString);//ƒ toString() { [native code] }

    原型:

    window 是全局作用域中一个大的对象;window是Object的一个实例;Function是所有函数数据类型的基类(包括自己)Object是所有对象的基类所有的函数都有prototype和__proto__属性Object的原型的__proto__执行的是自己,js认为自己指向自己没有意义,就规定为null所有的函数数据类型(普通的函数、类【内置类,自定义类】)都是Function的一个实例,Function和Object都是Function的一个实例,那Object类的__proto__指向Function的原型所有函数都是Function的实例, 那Function也是函数, 那他的__proto__指向的是自己的原型。它的原型是一个匿名函数,但是也是对象,正常使用即可 当函数作为对象时,有length和name属性 length:代表形参的个数,name:代表函数的名字 如果一个对象你不知道谁构出来的, 那他的__proto__就指向Object内置类的原型( 所有类的原型都指向Object内置类的原型)函数的三种角色: 普通函数 构造函数 普通对象在正式场合函数是以函数的身份出场的( 这是人家的主角色)类的特点: 多态、 继承和封装给Fn的原型新增键值对;这就是原型扩展;

    原型图

    原型链:单向不可逆

    原型重定向

    内置类的原型不能被重定向可以覆盖内置类原型上的方法用新的空间地址覆盖Fn原有的空间地址;会导致constructor的丢失;重定向例子 function Fn() { this.x = 100; this.y = 100; } Fn.prototype.getX = function () { console.log(this.x) } let f1 = new Fn; Fn.prototype = { getY: function () { console.log(this.y) } }; let f2 = new Fn; console.log(f1.getX) console.log(f2.getX) console.log(f1.constructor) console.log(f2.constructor) console.log(Fn.prototype)

    阿里面试题(原型链、运算符优先级)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> function Foo() { getName = function () { console.log(1); }; return this; } Foo.getName = function () { console.log(2); }; Foo.prototype.getName = function () { console.log(3); }; var getName = function () { console.log(4); }; function getName() { console.log(5); } Foo.getName(); //2 getName(); //5//4 Foo().getName(); //2//1 getName(); //4//1 new Foo.getName(); //2 new Foo().getName(); //1//3 new new Foo().getName(); //1//3 /* 1、成员访问:寻找对象里的属性名所对应的属性值就是成员访问(19) Fn.aa 2、new(带参数列表):就是构造函数执行有括号(19) 3、new(无参数列表):就是构造函数执行没有括号(18) 优先级一样,从左到右运算 */ </script> </body> </html>

    Processed: 0.012, SQL: 9