面向对象与原型原稿

【系统分析师论文】论软件开发模型及应用 2020年5月,我参与了某数字化车间管理系统的研发与设计,该系统主要通过MOM系统实现MES相关功能,上接企业层系统,下接物理采集设备,我在该项目中担任系统分析师的角色,主要负责系统分析与设计等工作。本文以该系统为例,讨论软件开发模型及应用。在需求工作流阶段,通过用户访谈和联合开发计划获取需求,利用UML用例建立 需求模型;在设计与分析工作流阶段,将需求模型转换成设计模型,对用例进行设计与分析,建立逻辑视图,确定与用例视图一一对应的关系; 阅读详情

一.创建对象

创建一个对象,然后给这个对象新建属性和方法。

var box = new Object();                 //创建一个Object对象
box.name = 'Lee';                       //创建一个name属性并赋值
box.age = 100;                          //创建一个age属性并赋值
box.run = function () {                 //创建一个run()方法并返回值
    return this.name + this.age + '运行中...';
};
alert(box.run());                       //输出属性和方法的值

上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box对象本身。这种是JavaScript创建对象最基本的方法,但有个缺点,想创建一个类似的对象,就会产生大量的代码。

var box2 = box;                     //得到box的引用
box2.name = 'Jack';                     //直接改变了name属性
alert(box2.run());                      //用box.run()发现name也改变了
var box2 = new Object();
box2.name = 'Jack';
box2.age = 200;
box2.run = function () {
    return this.name + this.age + '运行中...';
};
alert(box2.run());                      //这样才避免和box混淆,从而保持独立

为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。

function createObject(name, age) {      //集中实例化的函数
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function () {
        return this.name + this.age + '运行中...';
    };
    return obj;
}
var box1 = createObject('Lee', 100);        //第一个实例
var box2 = createObject('Jack', 200);       //第二个实例
alert(box1.run());
alert(box2.run());                      //保持独立

工厂模式解决了重复实例化的问题,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

alert(typeof box1);                     //Object
alert(box1 instanceof Object);              //true

ECMAScript中可以采用构造函数(构造方法)可用来创建特定的对象。类型于Object对象。

function Box(name, age) {               //构造函数模式
    this.name = name;
    this.age = age;
    this.run = function () {
        return this.name + this.age + '运行中...';
    };
}
var box1 = new Box('Lee', 100);         //new Box()即可
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box);             //很清晰的识别他从属于Box

使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,但问题是,这里并没有new Object(),为什么可以实例化Box(),这个是哪里来的呢?
使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给this对象;
3.没有renturn语句。

构造函数的方法有一些规范:
1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和普通函数);
2.通过构造函数创建对象,必须使用new运算符。

既然通过构造函数可以创建对象,那么这个对象是哪里来的,new Object()在什么地方执行了?执行的过程如下:
1.当使用了构造函数,并且new 构造函数(),那么就后台执行了new Object();
2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。
3.执行构造函数内的代码;
4.返回新对象(后台直接返回)。

关于this的使用,this其实就是代表当前作用域对象的引用。如果在全局范围this就代表window对象,如果在构造函数体内,就代表当前的构造函数所声明的对象。

var box = 2;
alert(this.box);                            //全局,代表window

构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new运算符来调用,否则就是普通函数。

var box = new Box('Lee', 100);          //构造模式调用
alert(box.run());
Box('Lee', 20);                         //普通模式调用,无效
var o = new Object();                   
Box.call(o, 'Jack', 200)                    //对象冒充调用
alert(o.run());                         

探讨构造函数内部的方法(或函数)的问题,首先看下两个实例化后的属性或方法是否相等。

var box1 = new Box('Lee', 100);         //传递一致
var box2 = new Box('Lee', 100);         //同上
alert(box1.name == box2.name);          //true,属性的值相等
alert(box1.run == box2.run);                //false,方法其实也是一种引用地址
alert(box1.run() == box2.run());            //true,方法的值相等,因为传参一致
可以把构造函数里的方法(或函数)用new Function()方法来代替,得到一样的效果,更加证明,他们最终判断的是引用地址,唯一性。
function Box(name, age) {               //new Function()唯一性
    this.name = name;
    this.age = age;
    this.run = new Function("return this.name + this.age + '运行中...'");
}

我们可以通过构造函数外面绑定同一个函数的方法来保证引用地址的一致性,但这种做法没什么必要,只是加深学习了解:

function Box(name, age) {
    this.name = name;
    this.age = age;
    this.run = run;
}
function run() {                        //通过外面调用,保证引用地址一致
    return this.name + this.age + '运行中...';
}

虽然使用了全局的函数run()来解决了保证引用地址一致的问题,但这种方式又带来了一个新的问题,全局中的this在对象调用的时候是Box本身,而当作普通函数调用的时候,this又代表window。

二.原型

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。

function Box() {}                           //声明一个构造函数
Box.prototype.name = 'Lee';                 //在原型里添加属性
Box.prototype.age = 100;                    
Box.prototype.run = function () {               //在原型里添加方法
    return this.name + this.age + '运行中...';
};

比较一下原型内的方法地址是否一致:

var box1 = new Box();
var box2 = new Box();
alert(box1.run == box2.run);                    //true,方法的引用地址保持一致

为了更进一步了解构造函数的声明方式和原型模式的声明方式,我们通过图示来了解一下:

构造函数方式
构造函数方法

原型模式方式
原型模式方法

在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就可以访问到原型里的属性和方法了。
PS:IE浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。

alert(box1.__proto__);                      //[object Object]

判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。

alert(Box.prototype.isPrototypeOf(box));        //只要实例化对象,即都会指向

原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;

虽然我们可以通过对象实例访问保存在原型中的值,但却不能访问通过对象实例重写原型中的值。

var box1 = new Box();
alert(box1.name);                           //Lee,原型里的值
box1.name = 'Jack';
alert(box.1name);                           //Jack,就近原则,
var box2 = new Box();                       
alert(box2.name);                           //Lee,原型里的值,没有被box1修改

如果想要box1也能在后面继续访问到原型里的值,可以把构造函数里的属性删除即可,具体如下:

delete box1.name;                           //删除属性
alert(box1.name);                           

如何判断属性是在构造函数的实例里,还是在原型里?可以使用hasOwnProperty()函数来验证:

alert(box.hasOwnProperty('name'));          //实例里有返回true,否则返回false

构造函数实例属性和原型属性示意图

in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。

alert('name' in box);                       //true,存在实例中或原型中

我们可以通过hasOwnProperty()方法检测属性是否存在实例中,也可以通过in来判断实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。

function isProperty(object, property) {         //判断原型中是否存在属性
    return !object.hasOwnProperty(property) && (property in object);
}
var box = new Box();
alert(isProperty(box, 'name'))                  //true,如果原型有

为了让属性和方法更好的体现封装的效果,并且减少不必要的输入,原型的创建可以使用字面量的方式:

function Box() {};
Box.prototype = {                       //使用字面量的方式
    name : 'Lee',
    age : 100,
    run : function () {
        return this.name + this.age + '运行中...';
    }
};

使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有一些区别,字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反。

var box = new Box();
alert(box instanceof Box);
alert(box instanceof Object);
alert(box.constructor == Box);              //字面量方式,返回false,否则,true
alert(box.constructor == Object);               //字面量方式,返回true,否则,false

如果想让字面量方式的constructor指向实例对象,那么可以这么做:

Box.prototype = {
    constructor : Box,                      //直接强制指向即可
};

PS:字面量方式为什么constructor会指向Object?因为Box.prototype={};这种写法其实就是创建了一个新对象。而每创建一个函数,就会同时创建它prototype,这个对象也会自动获取constructor属性。所以,新对象的constructor重写了Box原来的constructor,因此会指向新对象,那个新对象没有指定构造函数,那么就默认为Object。

原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型。

function Box() {};
Box.prototype = {                           //原型被重写了
    constructor : Box,
    name : 'Lee',
    age : 100,
    run : function () {
        return this.name + this.age + '运行中...';
    }
};
Box.prototype = {
    age = 200
};
var box = new Box();                        //在这里声明
alert(box.run());                           //box只是最初声明的原型

原型对象不仅仅可以在自定义对象的情况下使用,而ECMAScript内置的引用类型都可以使用这种方式,并且内置的引用类型本身也使用了原型。

alert(Array.prototype.sort);                    //sort就是Array类型的原型方法
alert(String.prototype.substring);              //substring就是String类型的原型方法
String.prototype.addstring = function () {      //给String类型添加一个方法
    return this + ',被添加了!';             //this代表调用的字符串
};
alert('Lee'.addstring());                       //使用这个方法

PS:尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种方法。因为它可能会导致命名冲突,不利于代码维护。

原型模式创建对象也有自己的缺点,它省略了构造函数传参初始化这一过程,带来的缺点就是初始化的值都是一致的。而原型最大的缺点就是它最大的优点,那就是共享。
原型中所有属性是被很多实例共享的,共享对于函数非常合适,对于包含基本值的属性也还可以。但如果属性包含引用类型,就存在一定的问题:

function Box() {};
Box.prototype = {
    constructor : Box,
    name : 'Lee',
    age : 100,
    family : ['父亲', '母亲', '妹妹'],            //添加了一个数组属性
    run : function () {
        return this.name + this.age + this.family;
    }
};
var box1 = new Box();
box1.family.push('哥哥');                 //在实例中添加'哥哥'
alert(box1.run());
var box2 = new Box();
alert(box2.run());                          //共享带来的麻烦,也有'哥哥'了

PS:数据共享的缘故,导致很多开发者放弃使用原型,因为每次实例化出的数据需要保留自己的特性,而不能共享。

为了解决构造传参和共享问题,可以组合构造函数+原型模式:

function Box(name, age) {                   //不共享的使用构造函数
    this.name = name;
    this.age = age;
    this. family = ['父亲', '母亲', '妹妹'];
};
Box.prototype = {                           //共享的使用原型模式
    constructor : Box,
    run : function () {
        return this.name + this.age + this.family;
    }
};

PS:这种混合模式很好的解决了传参和引用共享的大难题。是创建对象比较好的方法。

原型模式,不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,并且在声明一个对象时,构造函数+原型部分让人感觉又很怪异,最好就是把构造函数和原型封装到一起。为了解决这个问题,我们可以使用动态原型模式。

function Box(name ,age) {                   //将所有信息封装到函数体内
    this.name = name;
    this.age = age;
    if (typeof this.run != 'function') {            //仅在第一次调用的初始化
        Box.prototype.run = function () {
            return this.name + this.age + '运行中...';
        };
    }
}
var box = new Box('Lee', 100);
alert(box.run());

当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。当第二次调用,就不会初始化,并且第二次创建新对象,原型也不会再初始化了。这样及得到了封装,又实现了原型方法共享,并且属性都保持独立。

if (typeof this.run != 'function') {
    alert('第一次初始化');                    //测试用
    Box.prototype.run = function () {
        return this.name + this.age + '运行中...';
    };
}
var box = new Box('Lee', 100);              //第一次创建对象
alert(box.run());                           //第一次调用
alert(box.run());                           //第二次调用
var box2 = new Box('Jack', 200);                //第二次创建对象
alert(box2.run());
alert(box2.run());

PS:使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。

以上讲解了各种方式对象创建的方法,如果这几种方式都不能满足需求,可以使用一开始那种模式:寄生构造函数。

function Box(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function () {
        return this.name + this.age + '运行中...';
    };
    return obj;
}

寄生构造函数,其实就是工厂模式+构造函数模式。这种模式比较通用,但不能确定对象关系,所以,在可以使用之前所说的模式时,不建议使用此模式。
在什么情况下使用寄生构造函数比较合适呢?假设要创建一个具有额外方法的引用类型。由于之前说明不建议直接String.prototype.addstring,可以通过寄生构造的方式添加。

function myString(string) {                 
    var str = new String(string);
    str.addstring = function () {
        return this + ',被添加了!';
    };
    return str;
}
var box = new myString('Lee');              //比直接在引用原型添加要繁琐好多
alert(box.addstring());

在一些安全的环境中,比如禁止使用this和new,这里的this是构造函数里不使用this,这里的new是在外部实例化构造函数时不使用new。这种创建方式叫做稳妥构造函数。

function Box(name , age) {
    var obj = new Object();
    obj.run = function () {
        return name + age + '运行中...';       //直接打印参数即可
    };
    return obj;
}
var box = Box('Lee', 100);                  //直接调用函数
alert(box.run());

PS:稳妥构造函数和寄生类似。

四.继承
继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而ECMAScript只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。

function Box() {                            //Box构造
    this.name = 'Lee';
}
function Desk() {                           //Desk构造
    this.age = 100;
}
Desk.prototype = new Box();                 //Desc继承了Box,通过原型,形成链条
var desk = new Desk();
alert(desk.age);
alert(desk.name);                           //得到被继承的属性
function Table() {                          //Table构造
this.level = 'AAAAA';
}                           
Table.prototype = new Desk();               //继续原型链继承
var table = new Table();
alert(table.name);                          //继承了Box和Desk

原型链继承流程图
构造函数实例属性和原型属性示意图

如果要实例化table,那么Desk实例中有age=100,原型中增加相同的属性age=200,最后结果是多少呢?

Desk.prototype.age = 200;                   //实例和原型中均包含age

PS:以上原型链继承还缺少一环,那就是Obejct,所有的构造函数都继承自Obejct。而继承Object是自动完成的,并不需要程序员手动继承。

经过继承后的实例,他们的从属关系会怎样呢?

alert(table instanceof Object);                 //true
alert(desk instanceof Table);                   //false,desk是table的超类
alert(table instanceof Desk);                   //true
alert(table instanceof Box);                    //true

在JavaScript里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)。继承也有之前问题,比如字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
为了解决引用共享和超类型无法传参的问题,我们采用一种叫借用构造函数的技术,或者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题。

function Box(age) {
    this.name = ['Lee', 'Jack', 'Hello']
    this.age = age;
}
function Desk(age) {
    Box.call(this, age);                        //对象冒充,给超类型传参
}
var desk = new Desk(200);
alert(desk.age);
alert(desk.name);
desk.name.push('AAA');                      //添加的新数据,只给desk
alert(desk.name);

借用构造函数虽然解决了刚才两种问题,但没有原型,复用则无从谈起。所以,我们需要原型链+借用构造函数的模式,这种模式成为组合继承。

function Box(age) {
    this.name = ['Lee', 'Jack', 'Hello']
    this.age = age;
}
Box.prototype.run = function () {               
    return this.name + this.age;
};
function Desk(age) {
    Box.call(this, age);                        //对象冒充
}
Desk.prototype = new Box();                 //原型链继承
var desk = new Desk(100);
alert(desk.run());

还有一种继承模式叫做:原型式继承;这种继承借助原型并基于已有的对象创建新对象,同时还不必因此创建自定义类型。

function obj(o) {                           //传递一个字面量函数
    function F() {}                     //创建一个构造函数
    F.prototype = o;                        //把字面量函数赋值给构造函数的原型
    return new F();                     //最终返回出实例化的构造函数
}
var box = {                             //字面量对象
    name : 'Lee',
    arr : ['哥哥','妹妹','姐姐']
};
var box1 = obj(box);                        //传递
alert(box1.name);
box1.name = 'Jack';
alert(box1.name);
alert(box1.arr);
box1.arr.push('父母');
alert(box1.arr);
var box2 = obj(box);                        //传递
alert(box2.name);
alert(box2.arr);                            //引用类型共享了

寄生式继承把原型式+工厂模式结合而来,目的是为了封装创建对象的过程。

function create(o) {                    //封装创建过程
    var f= obj(o);
    f.run = function () {
        return this.arr;                        //同样,会共享引用
    }; 
    return f;
}

组合式继承是JavaScript最常用的继承模式;但,组合式继承也有一点小问题,就是超类型在使用过程中会被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的内部。

function Box(name) {
    this.name = name;
    this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
    return this.name;
};
function Desk(name, age) {
    Box.call(this, name);                   //第二次调用Box
    this.age = age;
}
Desk.prototype = new Box();                 //第一次调用Box

以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

function obj(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
function create(box, desk) {
    var f = obj(box.prototype);
    f.constructor = desk;
    desk.prototype = f;
}
function Box(name) {
    this.name = name;
    this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
    return this.name;
};
function Desk(name, age) {
    Box.call(this, name);
    this.age = age;
}
inPrototype(Box, Desk);                     //通过这里实现继承
var desk = new Desk('Lee',100);
desk.arr.push('姐姐');
alert(desk.arr);
alert(desk.run());                          //只共享了方法
var desk2 = new Desk('Jack', 200);
alert(desk2.arr);                           //引用问题解决
【系统分析师论文】论信息系统开发方法及应用 2020年5月,我参与了某数字化车间管理系统的研发与设计,该系统主要通过MOM系统实现MES相关功能,上接企业层系统,下接物理采集设备,我在该项目中担任系统分析师的角色,主要负责系统分析与设计等工作。本文以该系统为例,讨论信息系统开发方法及应用。在需求工作流阶段,通过用户访谈和联合开发计划获取需求,利用UML用例建立 需求模型;在设计与分析工作流阶段,将需求模型转换成设计模型,对用例进行设计与分析,建立逻辑视图,确定与用例视图一一对应的关系; 阅读详情

相关推荐

H3C无线控制器AC与第三方认证系统集成实现企业级Portal短信认证方案

本文详细阐述了如何将H3C无线控制器(AC)与第三方认证系统集成,构建企业级Portal短信认证方案。该方案通过手机号作为临时凭证,实现了访客网络的实名追溯、权限控制与专业体验。文章深入解析了方案原理、H3C AC的关键配置步骤、第三方系统对接要点及短信网关选型避坑指南,为企业提升网络安全管理与访客服务质量提供了完整、可行的实战指导。

a3b4c5的博客 194

小米架构师推荐 Android源码设计模式解析与实战

推荐序 设计模式本身并不复杂,但是设计模式的出现,却是GOF大师们耗费无数心血,研究成百上千的例子,历经千锤百炼取其精华而得之,所以,它的重要性毋庸置疑。几年前,我曾见过高焕堂老师一本类似书籍的原稿,可惜此书未能出版,心中一直对此遗憾。 但今天有幸一窥优快云社区专家何红辉、关爱民老师精心撰写的这本以Android源码为案例的设计模式解析与实战一书时, 激动之情勃然而发。是的,本书的确是国内第一本...

十年代码写十年 713

生物信息学避坑指南:Scissor算法参数alpha和cutoff的黄金设置法则

本文深入解析了生物信息学中Scissor算法的关键参数alpha和cutoff的黄金设置法则,帮助研究者有效整合bulk RNA与单细胞数据,识别单细胞亚群。通过实战验证的调参策略,避开常见陷阱,获得可靠的生物学发现,特别适用于肿瘤异质性研究和免疫细胞分型等场景。

weixin_33734785的博客 450

初识设计模式之简单工厂模式、工厂方法模式、抽象工厂模式

初识设计模式之简单工厂模式、工厂方法模式、抽象工厂模式 简单工厂模式 工厂方法模式 抽象工厂模式 ​ 工厂顾名思义就是生产产品的意思,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。 1. 简单工厂模式 ​ 首先,我们有一个服装制造厂,有一张服装设计原稿。现在,我们需要根据各个经销商的要求制造出不同颜色的衣服。 Clothes接口:即服装设计原稿 public

weixin_44836808的博客 293

ArcGIS-裁剪遥感影像及dem图像

6、选择【工具箱】-【数据管理工具】-【栅格】-【裁剪】。在【输入栅格】里选择要裁剪的dem,在【输出范围】里选择刚创建的裁剪范围。选择一个输出路径,其他参数保存默认。2、起一个名称,要素类型选择【面】。点击【编辑】选择与要裁剪的dem一致的地理坐标系。1、创建需要裁剪区域的面层shp,右击选择【新建】-【shapefile】3、点击编辑器,选择开始编辑。4、选择【裁剪范围】,点击确定。5、画出想要裁剪的范围并保存。

siwenaiyou的博客 1万+

3款 433MHz 收发模块对比:SYN480R vs RXB6 vs DL-TX19,实测卷帘门遥控距离

本文深度评测了3款433MHz收发模块SYN480R、RXB6与DL-TX19在卷帘门遥控距离、穿透性能和抗干扰能力等方面的表现。通过实测数据对比,分析了超外差、超再生和PLL锁相环技术的优劣,为智能家居和工业控制领域的无线遥控方案选型提供专业参考。

weixin_30700977的博客 393

[转]关于Web前端开发,附:(百度web前端笔试面试题目)

关于Web前端及百度web前端笔试面试题目 随着各大互联网公司设立了Web前端开发工程师、设计工程师等职位,web前端越来越得到互联网企业的认可。而且其重视程度与地位也随着浏览器 端的富客户端的体现而日益提高。 眼前对HTML5的未来和走向,业内的预测是会和Flash、Silverlight等相结合,从而取代传统的客户端应用程序。而实现这个目标的客户端核 心工作是有Web前端工程师来...

weixin_30747253的博客 132

AF自动对焦 CDAF PDAF

前言 主流的AF: CDAF, PDAF, laser assist AF(这个只是辅助,在微距或者拍摄纹理不明显的场景下好用)。 1.cdaf原理 CDAF的大致原理就是检测图像锐度或者等价于锐度的参数,不断推动马达寻找最清晰点实现合焦或者对焦。如下图: 缺点:对焦准确,速度慢,由于camera帧率,cpu处理速度,马达反映时间问题不能实时对焦运动物体。 2.pdaf原理 计算相位差,将相位差转换为相位差和af code的关系....

camerall 1万+

CnOpenData 线上招聘网站信息数据

CnOpenData线上招聘网站信息数据库是一个覆盖中国主流招聘平台、时间跨度长、更新频率高的劳动力市场需求侧大数据集合。本数据库汇集了,为学术界和业界提供了一扇实时观察中国劳动力市场动态的窗口。

CnOpenData_wj的博客 2619

成对使用离轴抛物面反射镜的设计

成对使用离轴抛物面反射镜的设计

weixin_72050316的博客 638

OpenClaw实战系列01:OpenClaw接入飞书机器人全接入指南 + Ollama本地大模型

通过 OpenClaw + Ollama + 飞书的组合,我们成功搭建了一个完全私有、免费、可定制的AI助理。它不仅能在日常聊天中提供帮助,还能通过OpenClaw强大的“技能”体系,真正去操作你的电脑、管理文件、甚至执行代码。这套方案将数据留在本地,既保证了隐私安全,又锻炼了动手能力。现在,去给你的AI助理添加更多酷炫的技能吧!

PeterPan的博客 1万+

ES6语法实现模板编译

ES6语法实现模板编译基础字符串模板var template = ` <ul> <% for(var i=0; i < data.supplies.length; i++) { %> <li><%= data.supplies[i] %></li> <% } %> </ul> `;思路:怎么编译这个模板字符串呢?根本原理可以用ES5语法的循环拼接字符串,这里设置这个循环拼接函数为ec

一个有味道的Weber 3526

使用R语言实现循环神经网络RNN进行文本生成

首先,让我们回顾一下循环神经网络(Recurrent Neural Networks,RNN)的基本概念。RNN是一种深度学习技术,特别适合处理序列数据,如时间序列和文本数据。RNN的关键特性是它的隐藏状态,这个状态可以捕捉到当前输入之前的信息。这使得RNN能够利用前面的信息来影响后续的输出,从而对序列数据进行有效的处理。

斌擎科技 724

RegExp正则表达式

重难点 贪婪模式 非贪婪模式 捕获性分组 非捕获性分组 正向前瞻 负向前瞻 exec() lastIndex

一个有味道的Weber 1735

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

js正则表达式-前瞻

js正则表达式-前瞻JS 正则表达式是 JS 学习过程中的一大难点,繁杂的匹配模式足以让人头大,不过其复杂性和其学习难度也赋予了它强大的功能。文章从 JS 正则表达式的正向前瞻说起,实现否定匹配的案例。本文适合有一定 JS 正则表达式基础的同学,如果对正则表达式并不了解,还需先学习基础再来观摩这门否定大法。一、标签过滤需求不知道大家在写JS有没有遇到过这样的情况,当你要处理一串字符串时,需要写一个正

一个有味道的Weber 1609

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

单体内置对象

单体内置对象内置对象的定义是:不依赖宿主环境的对象,这些对象在ECMScript程序执行之前就已经存在了。开发人员不必实例化,因为他们已经存在了。前面我们已经介绍了大多数内置对象,例如:Object、Array、String。 ECMScript定义了2个单体内置对象 Global Math 一、Global所有的全局作用域中定义的属性和函数,都是Global对象的属性 isNaN() isFin

一个有味道的Weber 797

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

js正则表达式

js正则表达式RegExp下的方法test在字符串中测试模式匹配,成功返回true,失败返回false exec在字符串中执行匹配搜索,返回结果数组字符串的正则表达式方法 方法 含义 match(pattern) 返回pattern中的子串或null replace(pattern,replacement) 用replacement替换pattern search(pat

一个有味道的Weber 762

基本包装类型

重难点 String的几种重要的方法 1、charAt() 2、charCodeAt() 3、concat() 4、slice() 5、substring() 6、sbustr() 7、split() 8、indexOf() 9、lastIndexOf() 10、tirm() 特殊的引用类型叫基本包装类型 基本包装类型有3种: Number Boolean String一、B

一个有味道的Weber 711

js闭包

前言在js中,闭包是一个很重要又相当不容易完全理解的要点,网上关于讲解闭包的文章非常多,但是并不是非常容易读懂,在这里以《javascript高级程序设计》里面的理论为基础。用拆分的方式,深入讲解一下对于闭包的理解,如果有不对请指正。写在闭包之前闭包的内部细节,依赖于函数被调用过程所发生的一系列事件为基础,所以有必要先弄清楚以下几个概念:1.执行环境和活动对象执行环境(execution conte

一个有味道的Weber 691

Function类型

Function类型知识点索引 函数没有重载 函数声明与函数表达式 作为值的函数 函数内部属性 1、arguments 2、arguments.callee 3、apply()、call() 4、this 函数属性和方法 1、length 2、prototype 使用不带园括号的函数名是访问函数指针,而非调用函数 函数表达式 var sum=function(num1,num2

一个有味道的Weber 674

面向对象与原型重难点

一、创建对象 普通模式 优点: 缺点:每次实例化产生大量重复的代码 工厂模式 优点:集中实例化解决普通模式实例化产生大量重复代码的问题 缺点:无法区分谁到底是哪个对象的实例 构造函数 优点:既解决普通模式重复实例化的问题也解决工厂模式对象识别问题 缺点:两个实例化后的属性或方法不相等 二、5种函数模式 原型模式 优点:解决构造函数两个实例化后的属性或方法不相等的问题 缺点:无法传参,

一个有味道的Weber 541

面向对象与原型三

继承原型链继承function Box(){//被继承的函数叫做超类型(父类,基类) this.name='lee'; } function Desk(){//集成的函数叫做子类型(子类,派生类) this.age=100 } //通过原型链集成,超类型实例化后的对象实例,赋值给子类的原型属性 //new Box()会将Box构造里的信息和原型里的信息都交给Desk Desk.pro

一个有味道的Weber 468

面向对象与原型一

面向对象和原型创建对象var box=new Object(); box.name='chen'; box.age=26; box.run=function() { return this.name+this.age; } alert(box.run());var box2=new Object(); box2.name='jack'; box2.age=24; box2.run=funct

一个有味道的Weber 460

面向对象与原型二

构造函数+原型模式为了解决构造函数传参和共享问题,衍生出组合构造函数+原型模式。简而言之就是需要独立的部分用构造函数,需要共享的部分用原型。 优点:这种模式很好的解决了传参和引用共享的大难题。是创建对象比较好的方法。function Box(name, age) {//不共享的使用构造函数 this.name = name; this.age = age; this. fa

一个有味道的Weber 442
上一篇: 面向对象与原型重难点
下一篇: 关于json的几个方法
chentian888
博客等级 码龄11年 16粉丝 76原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值