Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

这 6 点知识让我对 JavaScript 的对象有了更进一步的了解 #265

Open
husky-dot opened this issue Sep 10, 2020 · 0 comments
Open

Comments

@husky-dot
Copy link
Owner

作者:Valentino Gagliardi
译者:前端小智
来源:valentinog

点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。

1. 对象方法 & this

方法只是保存函数值的属性。

简单对象方法

let rabbit = {};
rabbit.speak = function(line) {
    console.log("小兔子说: "+ line );
};
rabbit.speak("我还活着。")

输出:

T小兔子说: 我还活着。

对象方法 & this

当一个函数作为方法被调用时,对象会将函数作为属性并立即调用,就像在object.method()中一样,其主体中的特殊变量this将指向被调用的对象。


function speak(line) {
  console.log(this.type + "小兔子说:" + line)
};
let whiteRabbit = {type: "白色", speak: speak}

whiteRabbit.speak("噢,我真可爱!")

输出:

白色小兔子说:噢,我真可爱!

apply & call

  • applycall可以用于object.method()

  • applycall方法都有一个可用于模拟方法调用的第一个参数

  • 实际上第一个参数是用来指定 this


function speak(line) {
  console.log(`${this.type}的小兔子说:${line}` );
};
let whiteRabbit = {type: "白色", speak: speak};

speak.apply(whiteRabbit, ["你这个小坏蛋!"]);
speak.call({type: "黑色"}, "嘿嘿,我不坏,你不爱!");
白色的小兔子说:你这个小坏蛋!
黑色的小兔子说:嘿嘿,我不坏,你不爱!

2.Prototype(原型)

  • 几乎所有的对象都有一个prototype

  • prototype是另一个用作属性的备用源的对象

  • 当一个对象访问自身没有属性时,它会从它的prototype搜索该属性,如果没有找到就继续从它的prototypeprototype查找,依此类推,直到 null 为止。

空对象的原型

原型链最终的指向是Object的prototype, 而Object中的__proto__null

let empty = {};
console.log(empty.toString);
console.log(empty.toString());

输出:

[Function: toString]
[object Object]

其他对象(数组、函数等等)的默认属性

  • 许多对象没有直接将Object.prototype作为自己的原型,但有自己的默认属性
  • Function.prototype派生的函数和从Array.prototype派生的数组
console.log(Object.getPrototypeOf(isNaN) ==
            Function.prototype);
console.log(Object.getPrototypeOf([]) ==
Array.prototype);

输出:

true
true

Object.create 创建具有特定原型的对象

  • protoRabbit充当所有兔子共享的属性的容器

  • 单个兔子对象(如杀手兔子)包含仅适用于自身的属性(在本例中为type),并从其原型派生共享属性



let protoRabbit = {
  speak: function (line) {
    console.log(`${this.type}兔子说:${line}` );
  }
}

let killerRabbit = Object.create(protoRabbit)
killerRabbit.type = '杀手'
killerRabbit.speak('准备受死吧!')

输出:

杀手兔子说:准备受死吧!

3.构造函数

— 构造函数原型

  • 创建从某个共享原型派生的对象的更方便的方法是使用构造函数

  • 在 JavaScript 中,调用前面带有new关键字的函数会将其视为构造函数

  • 构造函数将其this变量绑定到一个新对象,除非它显式返回另一个对象值,否则此新对象将从调用中返回

  • new创建的对象被称为是其构造函数的实例

  • 约定将构造函数的名称大写,以便于与其他函数区分开


function Rabbit(type) {
    this.type = type;
}

let killerRabbit = new Rabbit("killer");
let blackRabbit = new Rabbit("black");
console.log(blackRabbit.type);

输出:

black

— 默认情况下,构造函数具有Object.prototype

  • 构造函数(实际上是所有函数)会自动获取一个名为prototype的属性,默认情况下,该属性包含一个从Object.prototype派生的普通空对象

  • 使用此构造函数创建的每个实例都将此对象作为其原型


function Rabbit(type) {
  this.type = type;
}

let blackRabbit = new Rabbit("黑色");
Rabbit.prototype.speak = function(line) {
  console.log(`${this.type}的兔子说:${line}` );
};
blackRabbit.speak("Boom...一波王炸!");

输出:

黑色的兔子说:Boom...一波王炸!

4. 重写派生属性

— 相同的原型名称

  • 如果原型中有同名的属性,则不会更改此属性
  • 该属性被添加到对象本身

function Rabbit(type) {
    this.type = type;
}
let blackRabbit = new Rabbit("black");
let killerRabbit = new Rabbit("killer");

Rabbit.prototype.teeth = "small";
console.log(killerRabbit.teeth);
// small
killerRabbit.teeth = "long, sharp, and bloody";
console.log(killerRabbit.teeth);
// long, sharp, and bloody
console.log(blackRabbit.teeth);
// small
console.log(Rabbit.prototype.teeth);
// small

下面 console.log(blackRabbit.teeth)的结果是small,因为blackRabbit对象不具有teeth 属性,它继承自Rabbit对象自己的teeth 属性,值为 small

5. 原型的干扰

— 可枚举与不可枚举

let map = {}

function storePhi(event, phi) {
  map[event] = phi
}

storePhi('pizza', 0.069)
storePhi('touched tree', -0.081)

Object.prototype.nonsense = 'hi'

for(let name in map) {
  console.log(name)
}

console.log('nonsense' in map)
console.log('toString' in map)

输出结果:

pizza
touched tree
nonsense
true
true

toString没有出现在for/in循环中,但是in运算符中返回true,这是因为 JS 区分可枚举属性不可枚举属性

我们通过简单分配创建的所有属性都是可枚举的,Object.prototype中的标准属性都是不可改变的,这就是为什么它们不出现在这样的for/in循环中的原因。


let map = {};
function storePhi(event, phi) {
    map[event] = phi;
}

storePhi("pizza", 0.069);
storePhi("touched tree", -0.081);

Object.defineProperty(Object.prototype, "hiddenNonsense",
                {enumerable: false, value: "hi"})

for (var name in map) {
    console.log(name)
}

console.log(map.hiddenNonsense)

输出:

pizza
touched tree
hi

通过使用Object.defineproperty函数可以定义自己的不可枚举属性,该函数允许我们控制要创建的属性的类型,在该示例中,hiddenNonsense在 map 中,但在 for...in 中不会显示。

— hasOwnProperty vs in 操作符

const map = {}
console.log("toString" in map)
console.log(map.hasOwnProperty("toString"))

输出:

true
false

hasOwnProperty方法告诉我们对象本身是否具有该属性,而无需查看其原型,这通常是比in运算符提供给我们的信息更有用的信息。

因此,如果你对基础对象原型感到困惑时,建议你可以这样写for/in循环:

for (var name in map) {
    if (map.hasOwnProperty(name)) {
        // ... this is an own property
    }
}

6.无原型对象

Object.create函数使我们能够创建具有特定原型的对象。我们还可以传递null作为原型,用来创建不带原型的新对象。

因此,我们不再需要hasOwnProperty,因为对象拥有的所有属性都是它自己的属性。现在,无论人们对Object.prototype做了什么,我们都可以安全地使用for/in循环


var map = Object.create(null);
map["pizza"] = 0.069;
console.log("toString" in map);
// false
console.log("pizza" in map);
// true

人才们的 【三连】 就是小智不断分享的最大动力,如果本篇博客有任何错误和建议,欢迎人才们留言,最后,谢谢大家的观看。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://medium.com/javascript-in-plain-english/six-things-you-should-know-about-objects-in-javascript-ccd11a9e1998

文章每周持续更新,可以微信搜索**【大迁世界 】第一时间阅读,回复【福利】**有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant