2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

使用者:小號/筆記/javascript

萌娘百科,萬物皆可萌的百科全書!轉載請標註來源頁面的網頁連結,並聲明引自萌娘百科。內容不可商用。
跳至導覽 跳至搜尋

數組

是否改變原始數組

會改變原始數組

一種錯誤寫法:

let a = [1,2,3];
let b = a;
b.push(4);
console.log(a);//输出[1,2,3,4],就nm...

一種正確寫法:

let a = [1,2,3];
let b = [...a];
b.push(4);
console.log(a);//输出[1,2,3]
  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • reverse()
  • sort()
  • forEach()

不會改變原始數組

  • filter()
  • concat()
  • slice()
  • join()
  • map()
  • every()
  • some()
  • indexOf()

構造函數

基礎

摘自 https://blog.csdn.net/sinat_21742529/article/details/83659459

  • 使用new操作符調用函數

例子:

function Person(name){
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
}

var person1 = new Person('nicole');
person1.say(); // "I am nicole"

用new調用構造函數,函數內部會發生如下變化:

創建一個this變量,該變量指向一個空對象。並且該對象繼承函數的原型;
屬性和方法被加入到this引用的對象中;
隱式返回this對象(如果沒有顯性返回其他對象)

用偽程序來展示上述變化:

function Person(name){
  // 创建this变量,指向空对象
  var this = {}; 
  // 属性和方法被加入到this引用的对象中
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
  // 返回this对象
  return this;
}

可以看出,用new調用構造函數,最大特點為,this對象指向構造函數生成的對象,所以,person1.say()會返回字符串:「I am nicole」。

小貼士

如果指定了返回對象,那麼,this對象可能被丟失。

function Person(name){
  this.name = name;
  this.say = function(){
    return "I am " + this.name;
  }
  var that = {};
  that.name = "It is that!";
  return that;
}

var person1 = new Person('nicole');
person1.name; // "It is that!"
  • 直接調用函數

如果直接調用函數,那麼,this對象指向window,並且,不會默認返回任何對象(除非顯性聲明返回值)。

還是拿Person函數為例,直接調用Person函數:

var person1 = Person('nicole');
person1; // undefined
window.name; // nicole

可見,直接調用構造函數的結果,並不是我們想要的。

自有屬性

function C(a) {
  this.a = a;
  this.b = 1;
}

let d = new C("e");

ab被叫做自有屬性。

.hasOwnProperty()判斷是否為自有屬性。

let o = [];

for (let i in d) {
  if(d.hasOwnProperty(i)) {
    o.push(i);
  }
}

console.log(o);//["a","b"]

原型屬性

prototype是一個可以在所有C實例之間共享的對象。

C.prototype.f = 2;

console.log(d.f);//2

添加多個屬性:

C.prototype.f = 2;

C.prototype.g = function() {
  console.log("g");
}

C.prototype.h = function() {
  console.log("h" + this.a);
}

//等价于

C.prototype = {
  f: 2, 
  g() {
    console.log("g");
  },
  h() {
    console.log("h" + this.a);
  }
};

constructor屬性

let d = new C("e");

console.log(d.constructor === C);//返回true

注意:

C.prototype = {
  f: 2, 
  g() {
    console.log("g");
  },
  h() {
    console.log("h" + this.a);
  }
};

let d = new C("e");

console.log(d.constructor === C);//返回false
console.log(d.constructor === Object);//返回true
console.log(d instanceof C);//返回true

所以你應該在給新對象重新設置過原型對象時,再定義一個constructor屬性:

C.prototype = {
  constructor: C,
  f: 2, 
  g() {
    console.log("g");
  },
  h() {
    console.log("h" + this.a);
  }
};

原型鏈/繼承

使用.isPrototypeOf()判斷原型鏈:

console.log(C.prototype.isPrototypeOf(d));//返回true

//原型链的最顶层Object
console.log(Object.prototype.isPrototypeOf(C.prototype));//返回true

舉個.map()函數幾乎毫不相干的例子:

let x = [9,81,625]

Array.prototype.myMap = function(callback) {
  const newArray = [];
  for(let i of this){
    newArray.push(callback(i))
  }
  return newArray;
};

let s = x.map(Math.sqrt);//等价于
let s = x.myMap(Math.sqrt);

console.log(s)//[3,9,25]

用繼承避免重複:

A.prototype = {
  constructor: A,
  x() {
    console.log("c");
  }
};

B.prototype = {
  constructor: B,
  x() {
    console.log("c");
  }
};

//等价于

function C() {};

C.prototype = {
  constructor: C, 
  x() {
    console.log("c");
  }
};

A.prototype = Object.create(C.prototype);
B.prototype = Object.create(C.prototype);

A.prototype = {
  constructor: A
};

B.prototype = {
  constructor: B
};

更多見#類繼承

Mixin添加共同行為

let aMixin = (d) => {
  d.shit = () => {
    console.log("oh my god");
  }
};

let b = {
  r: "t",
  e: 2
};

let c = {
  i: "o",
  u: 7
};

//将shit()方法分配给对象
aMixin(bird);
aMixin(plane);

bird.shit();//"oh my god"
plane.shit();//"oh my god"

Get 與 Set

下兩句摘自 https://chinese.freecodecamp.org/learn/javascript-algorithms-and-data-structures/es6/use-getters-and-setters-to-control-access-to-an-object

  • Getter 函數的作用是可以讓對象返回一個私有變量,而不需要直接去訪問私有變量。
  • Setter 函數的作用是可以基於傳進的參數來修改對象中私有變量。 這些修改可以是計算,或者是直接替換之前的值。反正我沒看懂。
// 个人给出自己理解的例子
class a {
    constructor(d) {
        this.e = d;
    }
    get b() {
        return this.e + 10;
    }
    set b(c) {
        /*return无效*/ this.e = c - 1;
    }
}

let t = new a(3); // 此处 { e: 3 },随后t: { b: ()=> { return this.e + 10 }, e: 3 },得t: { b: 13, e: 3 }
let f = t.b;
let r = t.e;

t.b = 20; // 此处 { e: (c = t.b)=> { this.e = c - 1 } },得{ e: 19 },随后t: { b: ()=> { return this.e + 10 }, e: 19 },得t: { b: 29, e: 19 }
let g = t.b;
let l = t.e;
console.log(f, r, g, l); // 输出 13 3 29 19

類繼承

與原型繼承同理,而class作為語法糖更好理解。

class A {
  constructor(name) {
    this._name = name;
  }
  aunction() {
    return this._name;
  }
}
 
class B extends A {
  constructor(name, age) {
    super(name);//调用父类方法
    this._age = age;
  }
  bunction() {
    return this.aunction() + this._age ;
  }
}

let c = new A("a", "b");
let d = new B("a", "b");
console.log(c.aunction());//"a"
console.log(d.bunction());//"ab"

使用extends進行類繼承,使用super()調用父類構造方法。