JavaScript进阶3之参数按值传递、call,apply,bind和new的实现、继承的多种方式

JavaScript基础

  • 参数按值传递
    • 按值传递
    • 共享传递
  • call、apply、bind和new的实现
    • this
      • 软绑定
      • 硬绑定
    • call的实现
      • 第一步
      • 第二步
      • 第三步
    • apply的实现
    • bind的实现
      • 返回函数的模拟实现
      • 传参的模拟实现
      • 构造函数效果的模拟实现
      • 构造函数效果的优化实现
    • new的实现
      • 初步实现
  • 继承的多种方式&优缺点
    • 原型链继承
    • 构造函数借用
    • 最常用的方式-组合继承
    • 原型继承
    • 最好的方式-寄生式继承

参数按值传递

按值传递

  1. ECMAScript中所有函数的参数都是按值传递的。
  2. 按值传递:把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
var value = 1;
function foo(v) {
    v = 2;
    console.log(v); //2
}
foo(value);
console.log(value) // 1

内存分布:
改变前:
在这里插入图片描述
改变后:
在这里插入图片描述

当传递 value 到函数 foo 中,相当于拷贝了一份 value,假设拷贝的这份叫 _value,函数中修改的都是 _value 的值,而不会影响原来的 value 值。

共享传递

按引用传递:传递对象的引用(真实的物理地址),函数内部对参数的任何改变都会影响该对象的值,因为两者引用的是同一个对象。

var obj = {
    value: 1
};
function foo(o) {
    o.value = 2;
    console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2

改变前:
在这里插入图片描述
在这里插入图片描述

改变后:
在这里插入图片描述
在这里插入图片描述

var obj = {
    value: 1
};
function foo(o) {
    o = 2;
    console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1

共享传递是指,在传递对象的时候,传递的是地址索引。
所以修改 o.value,可以通过引用找到原值,但是直接修改 o,并不会修改原值。所以上面两个例子其实都是按共享传递。
改变前:
在这里插入图片描述
在这里插入图片描述

改变后:
在这里插入图片描述
在这里插入图片描述

函数传递参数 ,传递的是参数的拷贝:

  1. 指针拷贝,拷贝的是地址索引;
  2. 常规类型拷贝,拷贝的是值 ;

call、apply、bind和new的实现

call,apply,bind方法解决的是:this指向

this

this首先需要跟执行上下文挂钩
绑定方式:软绑定,硬绑定(call、apply、bind)

软绑定

this.name="window"
function test() {
    console.log(this.name);
}
const zhangsan = {
    name: "zhangsan",
    test: test,
};
test()
zhangsan.test()

在这里插入图片描述

硬绑定

function test() {
    console.log(this.name);
}
const xiaoming={name:'xiaoming'}
//硬绑定
test.call(xiaoming)
test.apply(xiaoming)
const t=test.bind(xiaoming)
t()

在这里插入图片描述
注意两点:

  1. call 改变了 this 的指向,指向到 xiaoming;
  2. test 函数执行了;

call的实现

call() :在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

第一步

使用软绑定的方式实现call,

所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性;
  2. 执行该函数;
  3. 删除该函数;
// 第一步
// test 是对象的属性名,反正最后也要删除它,所以起什么都可以。
xiaoming.test = test
// 第二步
xiaoming.test()
// 第三步
delete xiaoming.test

根据上述思路,提供一版:

// 第一版
Function.prototype.call2 = function(context) {
    // 首先要获取调用call的函数,用this可以获取,this指向的是 bar
    context.fn = this;
    context.fn();
    delete context.fn;  //卸磨杀驴
}

// 测试一下
 let foo = {
    value: 1
};

function bar() {
    console.log(this.value);
}

bar.call2(foo); // 1

第二步

call除了可以指定this,还可以指定参数

var foo = {
    value: 1
};

function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}

bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1

在这里插入图片描述

可以从 Arguments 对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
上述代码的Arguments中取第二个到最后一个的参数

// 以上个例子为例,此时的arguments为:
// arguments = {
//      0: foo,
//      1: 'kevin',
//      2: 18,
//      length: 3
// }
// 因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
}

// 执行后 args为 ["arguments[1]", "arguments[2]", "arguments[3]"]

接下来使用eval拼接成一个函数

eval('context.fn(' + args +')')

考虑到目前大部分浏览器在console中限制eval的执行,也可以使用rest
此处代码为:

// 第二版
Function.prototype.call2 = function(context) {
    context.fn = this;
    let arg = [...arguments].slice(1)  //arguments是类数组对象,将其拆分,并转为数组,然后再从第一个参数开始截取
    context.fn(...arg)  //arg数组拆分,逐步传入
    delete context.fn;
}

// 测试一下
var foo = {
    value: 1
};

function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}

bar.call2(foo, 'kevin', 18); 
// kevin
// 18
// 1

在这里插入图片描述

第三步

  1. this 参数可以传 null,当为 null 的时候,视为指向 window
    举个例子:
var value = 1;

function bar() {
    console.log(this.value);
}

bar.call(null); // 1

在这里插入图片描述

  1. 针对函数,可以实现返回值
var obj = {
    value: 1
}

function bar(name, age) {
    return {
        value: this.value,
        name: name,
        age: age
    }
}

console.log(bar.call(obj, 'kevin', 18));
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

这里

// 第三版
Function.prototype.call2 = function (context) {
        var context = context || window;
    context.fn = this;

    let arg = [...arguments].slice(1)
    let result = context.fn(...arg)

    delete context.fn
    return result
}

// 测试一下
var value = 2;

var obj = {
    value: 1
}

function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.call2(null); // 2

console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

这边给出最简化的写法:

Function.prototype.call2 = function(context, ...args) {
  // 判断是否是undefined和null
  if (typeof context === 'undefined' || context === null) {
    context = window
  }
  //es6 Symbol:每定义的symbol都是唯一的
  let fnSymbol = Symbol()
  //确保fn不重复,是唯一的
  context[fnSymbol] = this
  let fn = context[fnSymbol](...args)
  delete context[fnSymbol] 
  return fn
}

typeof 的安全机制,比如:
typeof fasldjfalsfjkasjfklasdjfld 不会抛出错误

补充一个无关知识点:1帧=1000/60=16.666毫秒

apply的实现

apply 的实现跟 call 类似,只是入参不一样,apply为数组

const foo={
    value:1
}
function bar(name,age){
    console.log(name,age,this.value)
}

bar.apply(foo,['ddd',20])

在这里插入图片描述

Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
                result = context.fn(...arr)
    }

    delete context.fn
    return result;
}

最简化版方式:

Function.prototype.apply2 = function(context, args) {
  // 判断是否是undefined和null
  if (typeof context === 'undefined' || context === null) {
    context = window
  }
  let fnSymbol = Symbol()
  context[fnSymbol] = this
  let fn = context[fnSymbol](...args)
  delete context[fnSymbol] 
  return fn
}

bind的实现

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

由此我们可以首先得出 bind 函数的两个特点:

  1. 返回一个函数;
  2. 可以传入参数;

返回函数的模拟实现

var foo = {
    value: 1
};

function bar() {
    console.log(this.value);
}

// 返回了一个函数
var bindFoo = bar.bind(foo); 

bindFoo(); // 1

关于指定 this 的指向,我们可以使用 call 或者 apply 实现

// 第一版
Function.prototype.bind2 = function (context) {
   //context === foo
    //bar === this	
    var self = this;  
    
    // 虑到绑定函数可能是有返回值的,加上return
    return function () {
        return self.apply(context);
    }

}

传参的模拟实现

关于参数的传递

var foo = {
    value: 1
};

function bar(name, age) {
    console.log(this.value);
    console.log(name);
    console.log(age);

}

var bindFoo = bar.bind(foo, 'daisy');
bindFoo('18');
// 1
// daisy
// 18

当需要传 name 和 age 两个参数时,可以在 bind 的时候,只传一个 name,在执行返回的函数的时候,再传另一个参数 age。
这里如果不适用rest,使用arguments进行处理:

// 第二版
Function.prototype.bind2 = function (context) {

    var self = this;  //记录bar
    // 获取bind2函数从第二个参数到最后一个参数
    var args = Array.prototype.slice.call(arguments, 1);

    return function () {
        // 这个时候的arguments是指bind返回的函数传入的参数
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(context, args.concat(bindArgs));
    }
}

rest方式:

Function.prototype.bind2=function(context,...args){
    //args=['daisy']
    // bind2的入参传递的
    const self=this  //记录bar
    return function (...returnArgs){
        //returnArgs=['18']
        //18 这个函数的入参传递
        //[...args,...returnArgs] => ['daisy','18']
        return self.apply(context,[...args,...returnArgs])
    }
}

构造函数效果的模拟实现

bind 还有一个特点,就是
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

也就是说当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效。举个例子:

var value = 2;

var foo = {
    value: 1
};

function bar(name, age) {
    this.habit = 'shopping';
    console.log(this.value);
    console.log(name);
    console.log(age);
}

bar.prototype.friend = 'kevin';

var bindFoo = bar.bind(foo, 'daisy');

var obj = new bindFoo('18');    //bind作为构造函数使用, this会指向实例 this->obj 否则 this->context
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

尽管在全局和 foo 中都声明了 value 值,最后依然返回了 undefind,说明绑定的 this 失效了
后文中new 的模拟实现,就会知道这个时候的 this 已经指向了 obj。

// 第三版
Function.prototype.bind2 = function (context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
        // 以上面的是 demo 为例,如果改成 `this instanceof fBound ? null : context`,实例只是一个空对象,将 null 改成 this ,实例会具有 habit 属性
        // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
        return self.apply(this instanceof fBound ? this : context, args.concat(bindArgs));
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
    fBound.prototype = this.prototype;
    return fBound;
}

rest方式:

Function.prototype.bind2=function(context,...args){
    const self=this
    const fBound=function(...returnArgs){
        //this->obj  obj instanceof bindFoo === this instanceof fBound ->true 则作为构造函数使用的
        return self.apply(this instanceof fBound?this:context,[...args,...returnArgs])
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
    //此时,修改obj的原型 -> 等同于修改返回的构造函数的原型
    fBound.prototype = this.prototype;
    // this是obj,希望最终obj身上也有bar身上的friend属性,
    // bar.prototype.friend = 'kevin'; new bindFoo生成的实例上也有这个属性,bindFoo.prototype = bar.prototype => fBound.prototype=this.prototype
    return fBound
}
var value = 2;

var foo = {
    value: 1
};

function bar(name, age) {
    this.habit = 'shopping';
    console.log(this.value);
    console.log(name);
    console.log(age);
}

bar.prototype.friend = 'kevin';

var bindFoo = bar.bind2(foo, 'daisy');

var obj = new bindFoo('18');

console.log(obj)

在这里插入图片描述

构造函数效果的优化实现

但是在这个写法中,我们直接将 fBound.prototype = this.prototype,我们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。这个时候,我们可以通过一个空函数来进行中转:

// 第四版
Function.prototype.bind2 = function (context) {

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};   //作为中间的prototype的过度

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)
    // fBound的原型 -> fNOP的实例
    fBound.prototype = new fNOP();
    return fBound;
}

或:

Function.prototype.bind2=function(context,...args){
    const self=this
    
    var fNOP = function () {};   //作为中间的prototype的过度
    
    const fBound=function(...returnArgs){
        //this->obj  obj instanceof bindFoo === this instanceof fBound ->true 则作为构造函数使用的
        return self.apply(this instanceof fNOP?this:context,[...args,...returnArgs])
    }
    
    fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)
    // fBound的原型 -> fNOP的实例
    fBound.prototype = new fNOP();
    return fBound;
    var fNOP = function () {};   //作为中间的prototype的过度
    fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)
    // fBound的原型 -> fNOP的实例
    fBound.prototype = new fNOP();

在这里插入图片描述

new的实现

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一
先看看 new 实现了哪些功能。

function Person (name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

Person.prototype.strength = 80;

Person.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}

var person = new Person('Kevin', '18');

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin

我们可以看到,实例 person 可以:

  1. 访问到 Otaku 构造函数里的属性;
  2. 访问到 Otaku.prototype 中的属性;

因为 new 是关键字,所以无法像 bind 函数一样直接覆盖,所以我们写一个函数,命名为 objectFactory,来模拟 new 的效果。用的时候是这样的:

function Person () {
    ……
}

// 使用 new
var person = new Person(……);
// 使用 objectFactory
var person = objectFactory(Person, ……)

初步实现

因为 new 的结果是一个新对象,所以在模拟实现的时候,我们也要建立一个新对象,假设这个对象叫 obj,因为 obj 会具有 Person 构造函数里的属性,我们可以使用 Person.apply(obj, arguments)来给 obj 添加新的属性。
然后,实例的 proto 属性会指向构造函数的 prototype,也正是因为建立起这样的关系,实例可以访问原型上的属性

// 第一版代码
function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj, arguments);

    return obj;

};

在这一版中,我们:

  1. 用new Object() 的方式新建了一个对象 obj;
  2. 取出第一个参数,就是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数;
  3. 将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性;
  4. 使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性;
  5. 返回 obj;

测试:

function Person (name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

Person.prototype.strength = 60;

Person.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}

function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj, arguments);
    return obj;
};

var person = objectFactory(Person, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin

假如构造函数有返回值

function Person (name, age) {
    this.strength = 60;
    this.age = age;

    return {
        name: name,
        habit: 'Games'
    }
}

var person = new Person('Kevin', '18');

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined

在这个例子中,构造函数返回了一个对象,在实例 person 中只能访问返回的对象中的属性。
而且还要注意一点,在这里我们是返回了一个对象,假如我们只是返回一个基本类型的值呢?
再举个例子:

function Person (name, age) {
    this.strength = 60;
    this.age = age;

    return 'handsome boy';
}

var person = new Otaku('Kevin', '18');

console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18

这次尽管有返回值,但是相当于没有返回值进行处理。
所以我们还需要判断返回的值是不是一个对象,如果是一个对象,我们就返回这个对象,如果没有,我们该返回什么就返回什么。

// 最终版的代码
function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    var ret = Constructor.apply(obj, arguments);
    return typeof ret === 'object' ? ret : obj;

};

继承的多种方式&优缺点

原型链继承

function Parent () {
    this.names = ['xianzao', 'zaoxian'];
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();

child1.names.push('test');

console.log(child1.names); // ["xianzao", "zaoxian", "test"]

var child2 = new Child();

console.log(child2.names); // ["xianzao", "zaoxian", "test"]

问题:引用类型的属性被所有实例共享,数据被共享了

构造函数借用

function Parent () {
    this.names = ['xianzao', 'zaoxian'];
}

function Child () {
	//this指向谁?Child实例化出来的对象
    Parent.call(this);
}

var child1 = new Child();

child1.names.push('test');

console.log(child1.names); // ["xianzao", "zaoxian", "test"]

var child2 = new Child();

console.log(child2.names); // ["xianzao", "zaoxian"]

优点:

  1. 避免了引用类型的属性被所有实例共享;
  2. 可以在 Child 中向 Parent 传参;
function Parent (name) {
    this.name = name;
}

function Child (name) {
    Parent.call(this, name);
}

var child1 = new Child('xianzao');

console.log(child1.name); // xianzao

var child2 = new Child('zaoxian');

console.log(child2.name); // zaoxian

缺点:
方法都在构造函数中定义,每次创建实例都会创建一遍方法。(上述的Parent)

最常用的方式-组合继承

function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {

    Parent.call(this, name); // 构造器借用了
    
    this.age = age;

}

Child.prototype = new Parent(); // 原型链继承
Child.prototype.constructor = Child; // 将构造器引用指回来

var child1 = new Child('kevin', '18');

child1.colors.push('black');

console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]

var child2 = new Child('daisy', '20');

console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。

原型继承

function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

缺点:
包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。

var person = {
    name: 'kevin',
    friends: ['daisy', 'kelly']
}

var person1 = createObj(person);
var person2 = createObj(person);

person1.name = 'person1';
console.log(person2.name); // kevin

person1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

最好的方式-寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。

function createObj (o) {
    var clone = Object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/454067.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

能耗数据采集网关在钢铁企业的应用-天拓四方

能耗数据采集网关是一种集成多种传感器和数据通信技术的智能化设备&#xff0c;它能够实现对生产现场各类能耗数据的实时采集、存储和传输。通过网关设备&#xff0c;企业可以构建一个全面、高效的能源管理系统&#xff0c;对生产过程中的能源消耗进行实时监控和精准控制&#…

pcl弧度角度换算:rad2deg,deg2rad

角度弧度换算公式: 代码及结果在:cmath 中cos sin等常用函数的坑(弧度角度换算)-CSDN博客 pcl也有自带的rad2deg,deg2rad: 头文件 #include<pcl/common/angles.h> 代码如下 #include <iostream> #include<pcl/common/angles.h> int main() {vector<…

全球首个 AI 超级工程师:拥有全栈技能,一个指令就能完成整个开发过程

全球首位AI软件工程师Devin是由初创公司Cognition推出的&#xff0c;它被认为是世界上第一个完全自主的AI软件工程师[2][15]。Devin具备强大的编程和软件开发能力&#xff0c;能够在多个方面协助或完全独立地完成软件开发任务[15]。它的核心能力包括自学新语言、开发迭代App、自…

SpringBoot自动配置原理(简单总结)

SpringBoot2和SpringBoot3的自动配置原理大致相同&#xff0c;只是存放我们导入的starter中的配置类的信息的文件由对应starter的jar包下的META-INF/spring.factories文件变成了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。 此外…

数据分析之一些Excel函数

数据分析之Excel的使用 SUM()求和SUMIF()单条件求和SUMIFS()多条件求和日期函数YEAR()提取年份MONTH()提取月份DAY()提取日DATE()函数 SUBTOTAL()求和IF()函数IF嵌套 VLOOKUP()搜索取值MATCH()返回行值或列值INDEX()定位取值 SUM()求和 SUM(number1,[number2],…) 对选中的区域…

websocket逆向案例

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、案例地址二、分析流程三、逆向参数四、webSocket 交互位置总结 前言 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供…

Java项目:基于springboot实现的OA协同办公系统(源码+数据库+毕业论文)

一、项目简介 本项目是一套基于Springbootvue实现的付费自习室系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

以客户为中心、以市场为导向的创新研发能力:塑造企业核心竞争力的关键

在当今竞争激烈的市场环境中&#xff0c;企业的生存与发展往往取决于其核心竞争力。其中&#xff0c;以客户为中心、以市场为导向的创新研发能力&#xff0c;成为了塑造企业核心竞争力的关键要素。本文将探讨这一观点&#xff0c;并结合实际案例进行分析。 一、以客户为中心&am…

TCP收发——计算机网络——day02

今天主要讲了TCP的收发 TCP发端步骤 ①socket ②connect ③send ④closeTCP收端步骤 ①socket ②bind ③listen ④accept ⑤recv ⑥clise其函数主要有 connect int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:发送链接请求参数:sockfd:套接…

Linux:锁和线程同步的相关概念以及生产者消费者模型

文章目录 加锁的基本原则死锁死锁的概念死锁的条件 线程同步生产者消费者模型模型的理解 理解cp问题条件变量 本篇总结的是关于Linux中锁的相关概念以及生产者消费者模型 加锁的基本原则 加锁的基本原则&#xff1a;谁加锁谁解锁&#xff0c;不要把加锁和解锁这样的操作放在两…

淘宝基于Nginx二次开发的Tengine服务器

最近在群里看到这样一张阿里云网关报错的截图&#xff0c;我保存下来看了下 看到下面有 Tengine提供技术支持&#xff0c;这个Tengine是什么东西呢&#xff1f;我搜索了下似乎是淘宝在nginx的基础上自己改的Web服务器 Tengine还支持OpenResty框架&#xff0c;该框架是基于Ngin…

ios xcode 15 PrivacyInfo.xcprivacy 隐私清单 查询应用使用的隐私api

1.需要升级mac os系统到13 兼容 xcode 15.1 2.升级mac os系统到14 兼容 xcode 15.3 3.选择 New File 4.直接搜索 privacy 能看到有个App Privacy 5.右击Add Row 7.直接选 Label Types 8.选中继续添加就能添加你的隐私清单了 苹果官网文档

UE4案例记录

UE4案例记录&#xff08;制作3D角色显示在UI中&#xff09; 制作3D角色显示在UI中 转载自youtube视频 https://www.youtube.com/channel/UCC8f6SxKJElVvaRb7nF4Axg 新建项目 创建一个Actor 场景组件->摄像机组件->场景捕获组件2D&#xff0c;之后添加一个骨骼网格体…

打破信息获取的界限:灵雀云推出自主研发智能文档机器人KnowledGenie

自LLM&#xff08;Large Language Model&#xff09;技术的迅速崭露头角以来&#xff0c;整个AI领域已经发生了翻天覆地的变化。LLM技术的不断进步&#xff0c;特别是以ChatGPT为代表的技术&#xff0c;为人工智能领域带来了前所未有的发展机遇。这种技术的出现&#xff0c;使得…

全国车辆识别代码信息API查询接口-VIN深度解析

我们先来介绍下什么是vin码&#xff0c;以及vin码的构成结构解析&#xff0c;汽车VIN码&#xff0c;也叫车辆识别号码&#xff0c;通俗可以理解为汽车的身份证号码。 VIN码一共分四大部分&#xff1a; 1~3位&#xff0c;是世界制造厂识别代号&#xff08;WMI&#xff09;&…

计算机网络 —— 运输层

运输层 5.1 运输层概述 运输层的主要任务是&#xff0c;如何为运行在不同主机上的应用进程提供直接的通信服务。运输层协议又称为端到端协议。 根据应用需求的不同&#xff0c;因特网的运输层为应用层提供了两种不同的运输协议&#xff0c;即面向连接的TCP和无连接的UDP 5.2…

c 语言中指针注意事项

看看下面两个 #include<iostream> using namespace std;int main() {int a 10;char p[6];*((int *)p) *(& a); // 正确写法*p *(&a); // 错误写法cout << *(int*)p; } 把原因写在评论区

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的手写数字和符号识别(深度学习训练+UI界面+训练数据集)

摘要&#xff1a;开发手写数字和符号识别对于智能交互系统具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个手写数字和符号识别&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同模…

金融需要多样性,量化需要C++!通过本文,你可以知道:1、为什么是C++

通过本文&#xff0c;你可以知道&#xff1a; 1、为什么是C 2、Python的用武之地 3、量化C岗位薪酬水平 C VS Python 量化交易系统开发语言主要用C&#xff0c;也有人用Python。 但是从经验看&#xff0c;用C开发的量化交易系统能够让在系统中程序运行的速度更快。 量化交易…

qml中toolbox控件、ComboBox控件、PlainText实现及美化

一. 内容简介 qml中toolbox控件、ComboBox控件、PlainText实现及美化 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3pytorch 安装pytorch(http://t.csdnimg.cn/GVP23) 2.4QT 5.14.1 新版QT6.4,&#xff0c;6.5在线安装经常失败&#xff0c;而5.9版本…