JavaScript的对象详解

news2024/9/21 17:40:03

作为程序员,我们常常会听见一种说法,那就是面向对象编程。那到底什么是对象呢?有改如何面向对象编程呢?今天我们就来详细讲讲

什么是对象呢?

对象是JavaScript中一个非常重要的概念,这是因为对象可以将多个相关联的数据封装到一起,更好的描述一个事物

比如我们可以描述一辆车:Car,具有颜色(color)、速度(speed)、品牌(brand)、价格(price),行驶(travel)等等;
又比如我们可以描述一个人:Person,具有姓名(name)、年龄(age)、身高(height),吃东西(eat)、跑步(run)等等;

那么对象的使用有什么好处呢?

使用对象来描述事物,更有利于我们将现实的事物,抽离成代码中某个数据结构,所以有一些编程语言就是纯面向对象的编程语言,比Java。你在实现任何现实抽象时都需要先创建一个类,根据类再去创建对象

那么在JavaScript中的对象又是怎么样的呢?

在JavaScript中的对象被设计成一组属性的无序集合,像是一个哈希表,有key和value组成。
key是一个标识符名称,value可以是任意类型,也可以是其他对象或者函数类型
如果值是一个函数,那么我们可以称之为是对象的方法

如何创建一个对象呢?

早期使用创建对象的方式最多的是使用Object类,并且使用new关键字来创建一个对象:这是因为早期很多JavaScript开发者是从Java过来的,它们也更习惯于Java中通过new的方式创建一个对象

// 1.创建方式一: 通过new Object()创建
var obj = new Object()
obj.name = "zayyo"
obj.age = 18
obj.height = 1.88
obj.running = function() {
  console.log(this.name + "在跑步~")
}

后来很多开发者为了方便起见,都是直接通过字面量的形式来创建对象:这种形式看起来更加的简洁,并且对象和属性之间的内聚性也更强,所以这种方式后来就流行了起来

// 2.创建方式二: 字面量形式
var info = {
  name: "kobe",
  age: 40,
  height: 1.98,
  eating: function() {
    console.log(this.name + "在吃东西~")
  }
}

在前面我们的属性都是直接定义在对象内部,或者直接添加到对象内部的,但是这样来做的时候我们就不能对这个属性进行一些限制了;比如这个属性是否是可以通过delete删除的?这个属性是否在for-in遍历的时候被遍历出来呢?

对象属性的操作

如果我们想要对一个属性进行比较精准的操作控制,那么我们就可以使用属性描述符,通过属性描述符可以精准的添加或修改对象的属性,属性描述符需要使用 Object.defineProperty 来对属性进行添加或者修改

Object.defineProperty()

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

object.defineProperty ( obj, prop,descriptor)

Object.defineProperty()可以接收三个参数

参数
  • obj要定义属性的对象
  • prop要定义或修改的属性的名称或 Symbol
  • descriptor要定义或修改的属性描述符
返回值

被传递给函数的对象。

属性描述符分类

属性描述符的类型有两种:

  • 数据属性(Data Properties)描述符(Descriptor);
  • 存取属性(Accessor访问器 Properties)描述符(Descriptor);

在这里插入图片描述

数据属性描述符

数据数据描述符有如下四个特性:

  1. [[Configurable]](是否可存取):表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符;
    — 当我们直接在一个对象上定义某个属性时,这个属性的[[Configurable]]默认为true
    — 当我们通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false

  2. [[Enumerable]](是否可枚举):表示属性是否可以通过for-in或者Object.keys()返回该属性;
    — 当我们直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]默认为true
    — 当我们通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false

  3. [[Writable]](是否可修改):表示是否可以修改属性的值;
    — 当我们直接在一个对象上定义某个属性时,这个属性的[[Writable]]为true
    — 当我们通过属性描述符定义一个属性时,这个属性的[[Writable]]默认为false

  4. [[value]](属性的值):属性的value值,读取属性时会返回该值,修改属性时,会对其进行修改;默认情况下这个值是undefined

代码示例:

// name和age虽然没有使用属性描述符来定义, 但是它们也是具备对应的特性的
// value: 赋值的value
// configurable: true
// enumerable: true
// writable: true
var obj = {
  name: "zayyo",
  age: 18
}

// 数据属性描述符
// 用了属性描述符, 那么会有默认的特性
Object.defineProperty(obj, "address", {
  // 很多配置
  value: "广州市", // 默认值undefined
  // 该特殊不可删除/也不可以重新定义属性描述符
  configurable: false, // 默认值false
  // 该特殊是配置对应的属性(address)是否是可以枚举
  enumerable: true, // 默认值false
  // 该特性是属性是否是可以赋值(写入值) 
  writable: false // 默认值false
})

// 测试configurable的作用
delete obj.name
console.log(obj.name) //undefined
delete obj.address
console.log(obj.address)  //广州市

// 因为上面configurable已经设置成false所以Object.defineProperty修改也是无效的
Object.defineProperty(obj, "address", {
  value: "广州市",
  configurable: true
})

// 测试enumerable的作用
console.log(obj)
for (var key in obj) {
  console.log(key)
}
console.log(Object.keys(obj))

// 测试Writable的作用
obj.address = "深圳"
console.log(obj.address)

存取属性描述符

存取属性描述符有如下四个特性:

  1. [[Configurable]]:表示属性是否可以通过delete删除属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符;
    — 当我们直接在一个对象上定义某个属性时,这个属性的[[Configurable]]为true;
    — 当我们通过属性描述符定义一个属性时,这个属性的[[Configurable]]默认为false)

  2. [[Enumerable]]:表示属性是否可以通过for-in或者Object.keys()返回该属性;
    — 当我们直接在一个对象上定义某个属性时,这个属性的[[Enumerable]]为true;
    — 当我们通过属性描述符定义一个属性时,这个属性的[[Enumerable]]默认为false;

  3. [[get]]:获取属性时会执行的函数。默认为undefined

  4. [[set]]:设置属性时会执行的函数。默认为undefined

下面我们同样用代码来示例

var obj = {
  name: "zayyo",
  age: 18,
  _address: "广州市"//下划线+属性名默认是一个私有属性
}

// 存取属性描述符
// 存取属性描述符的使用场景
// 1.隐藏某一个私有属性被希望直接被外界使用和赋值
// 2.如果我们希望截获某一个属性它访问和设置值的过程时, 也会使用存储属性描述符
Object.defineProperty(obj, "address", {
  enumerable: true,
  configurable: true,
  get: function() {
    foo()
    //获取时返回私有属性的值
    return this._address
  },
  set: function(value) {
    bar()
    // 设置是把传入的值赋给私有属性
    this._address = value
  }
})

console.log(obj.address)

obj.address = "广州市"
console.log(obj.address)

function foo() {
  console.log("获取了一次address的值")
}

function bar() {
  console.log("设置了addres的值")
}

//set、get的定义方法二、
var obj = {
  // 私有属性(js里面是没有严格意义的私有属性)
  _age: 18,
  _eating: function() {},
  set age(value) {
    this._age = value
  },
  get age() {
    return this._age
  }
}


那如果过我们想同时定义多个属性呢?接下里我们就讲解如何同时定义多个属性的方法

如何同时定义多个属性?

Object.defineProperties() 方法直接在一个对象上定义 多个 新的属性或修改现有属性,并且返回该对象

代码示例

var obj = {}

Object.defineProperties(obj, {
  name: {
    configurable: true,
    enumerable: true,
    writable: true,
    value: "zayyo"
  },
  age: {
    configurable: true,
    enumerable: true,
    get: function() {
      return this._age
    },
    set: function(value) {
      this._age = value
    }
  }
})

还有一些不常用但是确实存在的一些对象方法给大家补充一下

对象方法补充

获取对象的属性描述符:
  • getOwnPropertyDescriptor(获取对象某一个特性属性的属性描述符)
  • getOwnPropertyDescriptors(获取对象的所有属性描述符)

代码示例:

var obj = {
  // 私有属性(js里面是没有严格意义的私有属性)
  _age: 18,
  _eating: function() {}
}

Object.defineProperties(obj, {
  name: {
    configurable: true,
    enumerable: true,
    writable: true,
    value: "zayyo"
  },
  age: {
    configurable: true,
    enumerable: true,
    get: function() {
      return this._age
    },
    set: function(value) {
      this._age = value
    }
  }
})

// 获取对象某一个特性属性的属性描述符
console.log(Object.getOwnPropertyDescriptor(obj, "name"))
console.log(Object.getOwnPropertyDescriptor(obj, "age"))

// 获取对象的所有属性描述符
console.log(Object.getOwnPropertyDescriptors(obj))


禁止对象扩展新属性:preventExtensions

给一个对象添加新的属性会失败(在严格模式下会报错)

代码示例:

var obj = {
  name: 'zayyo',
  age: 18
}

// 1.禁止对象继续添加新的属性
Object.preventExtensions(obj)

obj.height = 1.88
obj.address = "广州市"

console.log(obj)

密封对象,不允许配置和删除属性:seal

实际是调用preventExtensions ,并且将现有属性的configurable:false

代码示例:

// 2.禁止对象配置/删除里面的属性
// 方法一、自己遍历
for (var key in obj) {
  Object.defineProperty(obj, key, {
    configurable: false,
    enumerable: true,
    writable: true,
    value: obj[key]
  })
}
// 方法二、seal属性
Object.seal(obj)

delete obj.name
console.log(obj.name)

冻结对象,不允许修改现有属性: freeze

实际上是调用seal,并且将现有属性的writable: false

代码示例:

// 3.让属性不可以修改(writable: false)
Object.freeze(obj)

obj.name = "kobe"
console.log(obj.name)

那如果我们现在希望创建一系列的对象:比如Person对象,包括张三、李四、王五、李雷等等,他们的信息各不相同,那么采用什么方式来创建比较好呢?

创建多个对象的方案

学过java的同学应该知道,设计模式中有一个工厂设计模式,它就很好的能够满足我们的需求,通常我们会有一个工厂方法,通过该工厂方法我们可以产生想要的对象

// 工厂模式: 工厂函数
// 定义一个 createPerson函数
function createPerson(name, age, height, address) {
  // 1、函数内首先先创建一个对象
  var p = {}
  // 2、再进行对对象进行创建属性和赋值
  p.name = name
  p.age = age
  p.height = height;
  p.address = address

  p.eating = function() {
    console.log(this.name + "在吃东西~")
  }

  p.running = function() {
    console.log(this.name + "在跑步~")
  }

  return p
}

var p1 = createPerson("张三", 18, 1.88, "广州市")
var p2 = createPerson("李四", 20, 1.98, "上海市")
var p3 = createPerson("王五", 30, 1.78, "北京市")

// 但是工厂模式的有一个很大的缺点就是获取不到对象最真实的类型
console.log(p1, p2, p3)


工厂方法创建对象有一个比较大的问题:我们在打印对象时,对象的类型都是Object类型但是从某些角度来说,这些对象应该有一个他们共同的类型,下面我们来看一下另外一种方法:构造函数的方式
我们先理解什么是构造函数?

什么是构造函数?—想详细了解可以点击阅读我的这篇文章

构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别,构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别,我们也可以简单的理解为构造函数就是JavaScript函数;

用构造函数创建多个对象

// 规范: 构造函数的首字母一般是大写,用构造函数创建多个对象
function Person(name, age, height, address) {
  this.name = name
  this.age = age
  this.height = height
  this.address = address

  this.eating = function() {
    console.log(this.name + "在吃东西~")
  }

  this.running = function() {
    console.log(this.name + "在跑步")
  }
}

var p1 = new Person("张三", 18, 1.88, "广州市")
var p2 = new Person("李四", 20, 1.98, "北京市")

console.log(p1)
console.log(p2)
p1.eating()
p2.eating()

这个构造函数可以确保我们的对象是有Person的类型的。
但是构造函数就没有缺点了吗?

构造函数也是有缺点的,它在于我们需要为每个对象的函数去创建一个函数对象实例

JavaScript中的类和对象

当我们编写如下代码的时候,我们会如何来称呼这个Person呢?

function Person(){

}
var p1 =new Person()
var p2 =new Person()

在JS中Person应该被称之为是一个构造函数,从很多面向对象语言过来的开发者,也习惯称之为类,因为类可以帮助我们创建出来对象p1、p2。如果从面向对象的编程范式角度来看,Person确实是可以称之为类的

接下来我们详细讲解一下面向对象的特性----继承

面向对象的特性 – 继承

面向对象有三大特性:封装、继承、多态

封装:我们前面将属性和方法封装到一个类中,可以称之为封装的过程
继承:继承是面向对象中非常重要的,不仅仅可以减少重复代码的数量,也是多态前提(纯面向对象中)
多态:不同的对象在执行时表现出不同的形态

那么这里我们核心讲继承

那么继承是做什么呢?

继承可以帮助我们将重复的代码和逻辑抽取到父类中,子类只需要直接继承过来使用即可

在真正实现继承之前,我们先来理解一个非常重要的概念:原型链

JavaScript原型链

我们知道,从一个对象上获取属性,如果在当前对象中没有获取到就会去它的原型上面获取,这种往上级去寻找的方式,就形成了原型链

代码示例:

var obj = {
  name: "zayyo",
  age: 18
}

// [[get]]操作
// 1.在当前的对象中查找属性
// 2.如果没有找到, 这个时候会去原型链(__proto__)对象上查找
// 在obj的上级没有address属性
obj.__proto__ = {
}

// 原型链
// 在obj的上上级也没有address属性
obj.__proto__.__proto__ = {
  
}
// 在obj的上上上级添加了一个address属性, 就可以找到address的值,然后打印出来
obj.__proto__.__proto__.__proto__ = {
  address: "广州市"
}

console.log(obj.address)
那么什么地方是原型链的尽头呢?比如第三个对象是否也是有原型__proto__属性呢

那我们就用代码时打印试试,看能不能找到它的尽头

var obj = { name: "zayyo" }

// console.log(obj.address)

// 到底是找到哪一层对象之后停止继续查找了呢?
// 字面对象obj的原型是 [Object: null prototype] {}

console.log(obj.__proto__) //[Object: null prototype] {}

// obj.__proto__ => [Object: null prototype] {}
console.log(obj.__proto__.__proto__) //null

找到后面,我们发现obj.proto.__proto__打印的已经是null了,obj.__proto__打印的是[Object: null prototype] {},很明显字面对象obj的原型就是== [Object: null prototype] {}==

那么我们可能会问题: [Object: null prototype] {} 原型有什么特殊吗?
  • 特殊一:该对象有原型属性,但是它的原型属性已经指向的是null,也就是已经是顶层原型了
  • 特殊二:该对象上有很多默认的属性和方法
    我们来打印看看顶层对象里面都有些什么,这里的属性太多了,我们就不一一解释了,感兴趣的同学自己去查吧
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

// {
//   constructor: {  //构造属性
//     value: [Function: Object],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   __defineGetter__: {  
//     value: [Function: __defineGetter__],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   __defineSetter__: { 
//     value: [Function: __defineSetter__],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   hasOwnProperty: {
//     value: [Function: hasOwnProperty],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   __lookupGetter__: {
//     value: [Function: __lookupGetter__],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   __lookupSetter__: {
//     value: [Function: __lookupSetter__],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   isPrototypeOf: {
//     value: [Function: isPrototypeOf],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   propertyIsEnumerable: {
//     value: [Function: propertyIsEnumerable],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   toString: {
//     value: [Function: toString],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   valueOf: {
//     value: [Function: valueOf],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   },
//   ['__proto__']: {
//     get: [Function: get __proto__],
//     set: [Function: set __proto__],
//     enumerable: false,
//     configurable: true
//   },
//   toLocaleString: {
//     value: [Function: toLocaleString],
//     writable: true,
//     enumerable: false,
//     configurable: true
//   }
// }

我们来试试给改变对象的隐性原型(proto),隐私原型一般指向顶层原型[Object: null prototype] {},我们们修改了就 等于在他们中间加了一层,最终的顶层原型还是[Object: null prototype] {},这是毋庸置疑的

var obj = {
  name: "zayyo",
  age: 18
}

var obj2 = {
  address: "广州市"
}
obj.__proto__ = obj2//把boj的隐性原型指向boj2,obj2变成了obj的上层原型

Object.prototype //原本的顶层原型
console.log(obj.__proto__) //{ address: '北京市' }
console.log(obj.__proto__.__proto__) //[Object: null prototype] {}
console.log(obj.__proto__.__proto__.__proto__) //null
console.log(Object.prototype)//[Object: null prototype] {}

console.log(obj.__proto__ === Object.prototype) //false

那么如果我们想要实现继承,要怎么来实现呢?

如果我们现在需要实现继承,那么就可以利用原型链来实现了,接下来我们用代码给大家演示一下

在这里插入代码片

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java项目怎么从零部署到Linux服务器上?

目录 一.Java环境(JDK)安装 二.数据库(MySQL)安装 三.部署上线 ▐ 部署Jar包 ▐ 运行程序 ▐ 开放端口 一个Java项目首先需要一个支持它编译的Java环境,因此首先要保证服务器上安装的有相应的JDK 一.Java环境&a…

为什么使用雪花算法,有什么优缺点,如何解决?为什么不使用UUID的方法,如何解决系统回拨的问题?

为什么使用雪花算法,有什么优缺点,如何解决?为什么不使用UUID的方法,如何解决系统回拨的问题? 生成的id应该满足下面的条件: 首先是全局唯一,不能出现重复的ID之后是总体应该是递增的&#xf…

8个平面设计必备素材网站,免费下载。

平面设计师应该去哪里找免费可商用素材网站?我推荐这8个,赶紧收藏好。 1、菜鸟图库 菜鸟图库-免费设计素材下载 菜鸟图库是一个非常大的素材库,站内包含设计、办公、自媒体、图片、电商等各行业素材。网站还为新手设计师提供免费的素材&…

基于django的失物招领系统的设计与实现/ 基于Python的失物招领系统的设计与实现/失物招领管理系统

失物招领系统的设计与实现 摘要:伴随着我国全面推动信息化的趋势,我国的很多行业都在朝着互联网的方向进发。结合计算机技术的失物招领系统能够很好地解决传统失物招领存在的问题,能够提高管理员管理的效率,改善服务质量。优秀的失物招领系统…

感染了后缀为.Wormhole勒索病毒如何应对?数据能够恢复吗?

引言: 在当今日益复杂的网络安全环境中,勒索病毒成为了企业和个人面临的一大威胁。其中,.Wormhole勒索病毒以其独特的传播机制和强大的加密能力,尤为引人注目。本文将深入探讨.Wormhole勒索病毒的特点、感染途径、危害以及相应的…

XSS LABS 靶场初识

关注这个靶场的其他相关笔记:XSS - LABS —— 靶场笔记合集-CSDN博客 0x01:XSS LABS 靶场简介 XSS LABS 靶场是一个专注于跨站脚本攻击(Cross-Site Scripting,XSS)教育和训练的平台。平台中有一系列精心设计的关于 XS…

若依框架 MyBatis 改为 MyBatis-Plus 的实现步骤

本文只做了简单的实现,具体的细节需根据自己的需求进一步实现。如果实现中遇到问题欢迎留言讨论。 引入 MyBatis-Plus 引入相关依赖(pom.xml) 推荐先直接在顶级 pom.xml 中直接依赖,等调试通过之后,在去按需依赖&…

【hot100篇-python刷题记录】【三数之和】

R7-双指针篇 思路: 三个元素,代表需要3个指针,利用双指针收缩的思想,我们可以设置k,i,j三个元素指针。 k代表最外层的循环,循环一遍数组。(为了降低时间复杂度以及搜索难度,我们先将nums sort…

移动硬盘文件夹变成白色无法正常访问,怎么恢复?

在使用移动硬盘时,有时会遇到文件夹变白的情况。这通常意味着文件夹已经损坏或无法正常访问。本文将分析移动硬盘文件夹变白的原因,并提供相应的恢复方法。 一、原因分析 文件系统损坏:移动硬盘的文件系统可能因多种原因而损坏,如…

001集——CAD—C#二次开发入门——开发环境基本设置

CAD C#二次开发首先需要搭建一个舒服的开发环境,软件安装后,需要修改相关设置。本文为保姆级入门搭建开发环境教程,默认已成功安装vs和cad 。 第一步:创建类库 第二步:进行相关设置,如图: 下一…

milvus资源限制 benchmarker压测 qps优化

根据milvus 资源限制的官网,我们得出百万数据资源限制。 1.dev 环境 对接不同的配置最大的qps 如下(dev的机器内存很小) 2.于是认为当前的性能是匹配的,然后加上资源限制,配置 压测结果如下 {"run_id": "13292982fee74f64…

基于springboot+vue的民族文化推广系统设计与实现---附源码92323

摘 要 在全球化和信息化日益加深的当下,保护和推广民族文化显得尤为重要。民族文化不仅是一个国家或地区的独特标识,更是其历史、传统和智慧的结晶。然而,随着现代社会的快速发展,许多传统文化和习俗面临着被遗忘和消失的风险。因…

ssh---配置密钥对验证

1.在客户端创建密钥对 ssh-keygen -t ecdsa秘钥存放位置(生成密钥时的用户的工作目录下) 2.将公钥文件上传至服务器 3.在服务器中导入公钥文本 4.在客户机设置ssh代理功能,实现免交互登录 5.测试

Python自适应光学模态星形小波分析和像差算法

🎯要点 🎯星形小波分析像差测量 | 🎯对比傅里叶和小波分析 | 🎯定义多尺度图像质量度量,矩阵数据 | 🎯像差校正算法 | 🎯受激发射损耗显微镜布局 | 🎯干涉仪分支校准,求…

Java 虚方法表(虚函数)

虚方法表 Java 中的虚方法表(Virtual Method Table, VMT)是实现动态方法分派和多态的重要机制。它帮助 Java 运行时系统(JVM)决定在继承体系中调用哪一个方法的具体实现。 什么是虚方法表? 虚方法表是一个类的内部数…

Linux学习笔记(4)----通过网口灯判断网速是千兆还是百兆

网卡PHY 移植注意事项 注意RTL8211F的LED0,LED1,LED2,软件是可以自定义的,比如百兆,千兆,是亮哪个灯,黄灯或者绿灯,还有传输时是闪烁哪个灯,要注意硬件上是怎么驱动灯的…

获取当前计算机的处理器架构platform.machine()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 获取当前计算机的处理器架构 platform.machine() 选择题 关于以下代码的输出结果说法正确的是? import platform print("【执行】print(platform.machine())") prin…

Websocket测试工具,在线调试 - 在线工具

WebSocket 测试工具是用于测试 WebSocket 连接、发送和接收消息的工具。它们通常提供一个简单的用户界面,使开发人员能够快速验证 WebSocket 服务器的功能和性能。 在线Websocket测试工具体验地址:https://ewbang.com/websocket/index.html 什么是 WebSo…

具身智能(Embodied Intelligence)概述

目录 一、引言 二、具身感知 三、具身交互 四、具身智能体 五、虚拟到现实 一、引言 最近无论是斯坦福机器人炒虾,还是特斯拉官宣机器人进厂,都赚足了眼球,实力证明了具身智能(Embodied Intelligence)的火爆。…

SEO之网站结构优化(十四-内部链接及权重分配2)

初创企业搭建网站的朋友看1号文章;想学习云计算,怎么入门看2号文章谢谢支持: 1、我给不会敲代码又想搭建网站的人建议 2、“新手上云”能够为你开启探索云世界的第一步 博客:阿幸SEO~探索搜索排名之道 4、翻页过多 稍大型的商务…