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

User:小号/笔记/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()调用父类构造方法。