diff --git "a/Rarrot/articles/JavaScript/new\346\223\215\344\275\234\347\254\246.md" "b/Rarrot/articles/JavaScript/new\346\223\215\344\275\234\347\254\246.md" new file mode 100644 index 00000000..dcc0c159 --- /dev/null +++ "b/Rarrot/articles/JavaScript/new\346\223\215\344\275\234\347\254\246.md" @@ -0,0 +1,101 @@ +# new操作符 + +new操作符会进行四步: +1. 创建一个空对象 +2. 把空对象和构造函数的prototype关联起来 +3. 把构造函数的this绑定到空对象上 +4. 根据构造函数的返回值类型返回结果,如果是值类型就返回空对象,如果是引用类型就返回引用类型 + +```JavaScript +function newFn(Fun, ...args) { + // 1. 创建一个空对象 + let obj = {}; + // 2. 把空对象和构造函数的prototype关联起来 + obj.__proto__ = Fun.prototype; + // 3. 把构造函数的this绑定到空对象上 + const result = Fun.apply(obj,args) + // 4. 根据构造函数的返回值类型返回结果,如果是值类型就返回空对象,如果是引用类型就返回引用类型 + return result instanceof Object ? result : obj; +} + +function person(name) { + this.name = name; +} + +person.prototype.say = () => { + console.log('说话'); +}; + +let obj = newFn(person, "Rarrot"); +obj.say(); // 说话 +console.log(obj) // person {name: 'Rarrot'} +``` + +## 注意 + +1. 引用类型之间通过new操作符创建的对象是不相等的,例如: + + ```JavaScript + function Person() { + this.name = 'Rarrot'; + } + + let person1 = new Person(); + let person2 = new Person(); + + console.log(person1 === person2); // false + console.log([ 1 ] === [ 1 ]); // false + ``` + +2. 对象的key都是**字符串**,如果是引用类型也会自动转换为字符串,例如: + + ```JavaScript + let obj = {}; + let arr1 = { a: 1 }; + let arr2 = { b: 2 }; + + obj[arr1] = 1; + obj[arr2] = 2;// arr1.toString() === arr2.toString(),所以会覆盖掉arr1 + + for (let key in obj) { + console.log(key + ':' + obj[key]); // [object Object]:2 + } + ``` + +3. 对象找属性|方法的顺序: + + 在对象本身找 ==> 在构造函数上找 ==> 在对象原型上找 ==> 构造函数原型上找 ==> 对象上一级找 ==> Object.prototype找 + + ```JavaScript + function Person() { + this.name = 'Rarrot'; + this.age = 777; // 在构造函数中添加 + } + Person.prototype.age = '999'; // 在构造函数原型上添加 + + let person = new Person(); + person.age = '666'; // 在对象本身添加 + person.__proto__.age = '888'; // 在对象原型上添加 + + Object.prototype.age = '000'; // 在Object上添加 + + console.log(person.age); // 666 + + console.log(person.__proto__ === Person.prototype); // true + console.log(Person.prototype.__proto__ === Object.prototype); // true + console.log(Object.prototype.__proto__); // null + ``` + +## object + +为什么在Object 参考页,会发现左侧列出许多属性和方法——大大超过我们在自己定义的对象中看到的继承成员的数量。 + +原因在于,继承的属性和方法是定义在 prototype 属性之上的(你可以称之为子命名空间 (sub namespace) )——那些以 Object.prototype. 开头的属性,而非仅仅以 Object. 开头的属性。 + +prototype 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中,而不希望被继承的则放于Object自身,记住每一个对象都有一个原型(prototype)属性,其指向另一个对象。由下图可以看出,prototype内部存在有许多的属性和方法,原因即为以上所述 + +![](https://cdn.jsdelivr.net/gh/hr1201/img@main/imgs/202402291750719.png) + +于是 Object.prototype.watch()、[Object.prototype.valueOf()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) 等等成员,适用于任何继承自 Object() 的对象类型,包括使用构造器创建的新的对象实例。 + +[Object.is()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is)、[Object.keys()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/keys),以及其他不在 prototype 对象内的成员,不会被“对象实例”或“继承自 Object() 的对象类型”所继承。这些方法/属性仅能被 Object() 构造器自身使用。 \ No newline at end of file diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/this.md" b/Rarrot/articles/JavaScript/this.md similarity index 100% rename from "Rarrot/articles/JavaScript/\351\227\256\351\242\230/this.md" rename to Rarrot/articles/JavaScript/this.md diff --git "a/Rarrot/articles/JavaScript/\344\275\234\347\224\250\345\237\237.md" "b/Rarrot/articles/JavaScript/\344\275\234\347\224\250\345\237\237.md" new file mode 100644 index 00000000..75b78d69 --- /dev/null +++ "b/Rarrot/articles/JavaScript/\344\275\234\347\224\250\345\237\237.md" @@ -0,0 +1,115 @@ +# 作用域 + +1. **全局作用域**:全局作用域是最外围的作用域,根据 ECMAScript 的定义,全局作用域在网页中任何地方都能访问到。 + +2. **函数作用域**:函数作用域是在函数内部声明的变量只能在函数内部访问。 + +3. **块级作用域**:块级作用域是在代码块内部声明的变量只能在该代码块内部访问。 + + +## 全局作用域 + +全局作用域是最外围的作用域,根据 ECMAScript 的定义,全局作用域在网页中任何地方都能访问到。 + +```javascript +var a = 1; +console.log(a); // 1 +``` + +## 函数作用域 + +函数作用域是在函数内部声明的变量只能在函数内部访问。 + +```javascript +function foo() { + var a = 1; + console.log(a); // 1 +} + +foo(); +console.log(a); // Uncaught ReferenceError: a is not defined +``` + +## 块级作用域 + +块级作用域是在代码块内部声明的变量只能在该代码块内部访问。 + +```javascript +console.log(a); // undefined,变量提升 + +if (true) { + var a = 1; + console.log(a); // 1 + + let b = 2; + console.log(b); // 2 +} + +console.log(a); // 1 +console.log(b); // Uncaught ReferenceError: b is not defined +``` + +## 作用域链 + +作用域链是一个指向变量对象的指针列表,它保证了变量的有序访问。内部可以访问外部的变量,但是外部不能访问内部的变量。 + +注意:如果内部变量和外部变量同名,内部变量会覆盖外部变量。 + +```javascript +var a = 1; + +function foo() { + var b = 2; + + function bar() { + var c = 3; + console.log(a); // 1 + console.log(b); // 2 + console.log(c); // 3 + } + + bar(); +} + +foo(); +``` + +## 优先级 + +声明变量 > 声明普通函数 > 参数 > 变量提升 + +```javascript +function foo() { + // var a = 1; // 声明a变量 + + console.log(a); // ƒ a() {},如果前面有声明a变量,则输出声明变量的值 + + var a = 2; // 变量提升 + + // 普通声明函数是不看写函数时的位置的,只看函数声明的位置 + function a() {} +} + +foo(); +``` + +## 注意 + +注意声明变量时不使用`var`关键字,会自动提升到全局作用域。 + +```javascript +(function () { + var a = b = 10; + + /* + * 等价于 + * b = 10; // 全局作用域 + * var a = b; + */ +})() + +console.log(b); // 10 + +console.log(a); // Uncaught ReferenceError: a is not defined +``` + diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/\345\205\263\344\272\216\346\267\261\346\213\267\350\264\235.md" "b/Rarrot/articles/JavaScript/\345\205\263\344\272\216\346\267\261\346\213\267\350\264\235.md" similarity index 100% rename from "Rarrot/articles/JavaScript/\351\227\256\351\242\230/\345\205\263\344\272\216\346\267\261\346\213\267\350\264\235.md" rename to "Rarrot/articles/JavaScript/\345\205\263\344\272\216\346\267\261\346\213\267\350\264\235.md" diff --git "a/Rarrot/articles/JavaScript/\346\225\260\347\273\204.md" "b/Rarrot/articles/JavaScript/\346\225\260\347\273\204.md" new file mode 100644 index 00000000..97e92613 --- /dev/null +++ "b/Rarrot/articles/JavaScript/\346\225\260\347\273\204.md" @@ -0,0 +1,98 @@ +# 数组 + +## 判断数组 + +```js +// 1. isArray +const arr = [1, 2, 3] +console.log(Array.isArray(arr)) // true + +// 2. instanceof +console.log(arr instanceof Array) // true + +// 3. constructor +console.log(arr.constructor === Array) // true + +// 4. Object.prototype.toString.call() +console.log(Object.prototype.toString.call(arr).indexOf('Array') !== -1) // true + +// 5. Array.prototype.isPrototypeOf() +console.log(Array.prototype.isPrototypeOf(arr)) // true +``` + +## slice和splice + +`slice`和`splice`都是数组的方法,但是它们的作用不同。 + +- `slice`:返回一个新的数组,包含从开始到结束(不包括结束)的元素,原数组不会被修改。 + +```js +const arr = [1, 2, 3, 4, 5] +const newArr = arr.slice(1, 3) +console.log(newArr) // [2, 3] +console.log(arr) // [1, 2, 3, 4, 5] +``` + +- `splice`:从数组中添加或删除元素,返回被删除的元素,原数组会被修改。 + +```js +const arr = [1, 2, 3, 4, 5] +const newArr = arr.splice(1, 3) +console.log(newArr) // [2, 3, 4] +console.log(arr) // [1, 5] +``` + +## 数组去重 + +### 1. Set + +```js +const arr = [1, 2, 3, 4, 5, 1, 2, 3] +const newArr = [...new Set(arr)] +console.log(newArr) // [1, 2, 3, 4, 5] +``` + +### 2. filter + +```js +const arr = [1, 2, 3, 4, 5, 1, 2, 3] +const newArr = arr.filter((item, index) => arr.indexOf(item) === index) +console.log(newArr) // [1, 2, 3, 4, 5] +``` + +### 3. reduce + +```js +const arr = [1, 2, 3, 4, 5, 1, 2, 3] +const newArr = arr.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []) +console.log(newArr) // [1, 2, 3, 4, 5] +``` + +## 数组扁平化 + +### 1. flat + +```js +const arr = [1, [2, 3], [4, [5, 6]]] +const newArr = arr.flat(Infinity) +console.log(newArr) // [1, 2, 3, 4, 5, 6] +``` + +### 2. reduce + +```js +const arr = [1, [2, 3], [4, [5, 6]]] +const flatten = arr => arr.reduce((prev, cur) => prev.concat(Array.isArray(cur) ? flatten(cur) : cur), []) +const newArr = flatten(arr) +console.log(newArr) // [1, 2, 3, 4, 5, 6] +``` + +## 数组乱序 + + ```js + const arr = [1, 2, 3, 4, 5] + const newArr = arr.sort(() => Math.random() - 0.5) + console.log(newArr) + ``` + + diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/\347\220\206\350\247\243\345\216\237\345\236\213\351\223\276.md" "b/Rarrot/articles/JavaScript/\347\220\206\350\247\243\345\216\237\345\236\213\351\223\276.md" similarity index 100% rename from "Rarrot/articles/JavaScript/\351\227\256\351\242\230/\347\220\206\350\247\243\345\216\237\345\236\213\351\223\276.md" rename to "Rarrot/articles/JavaScript/\347\220\206\350\247\243\345\216\237\345\236\213\351\223\276.md" diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/new\346\223\215\344\275\234\347\254\246.md" "b/Rarrot/articles/JavaScript/\351\227\256\351\242\230/new\346\223\215\344\275\234\347\254\246.md" deleted file mode 100644 index 39da5965..00000000 --- "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/new\346\223\215\344\275\234\347\254\246.md" +++ /dev/null @@ -1,32 +0,0 @@ -# new操作符 - -new操作符会进行四步: -1. 创建一个空对象 -2. 把空对象和构造函数的prototype关联起来 -3. 把构造函数的this绑定到空对象上 -4. 根据构造函数的返回值类型返回结果,如果是值类型就返回空对象,如果是引用类型就返回引用类型 - -```JavaScript -function newFn(Fun, ...args) { - // 1. 创建一个空对象 - let obj = {}; - // 2. 把空对象和构造函数的prototype关联起来 - obj.__proto__ = Fun.prototype; - // 3. 把构造函数的this绑定到空对象上 - const result=Fun.apply(obj,args) - // 4. 根据构造函数的返回值类型返回结果,如果是值类型就返回空对象,如果是引用类型就返回引用类型 - return result instanceof Object ? result : obj; -} - -function person(name) { - this.name = name; -} - -person.prototype.say = () => { - console.log('说话'); -}; - -let obj = newFn(person, "Rarrot"); -obj.say(); -console.log(obj) -``` \ No newline at end of file diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/object.md" "b/Rarrot/articles/JavaScript/\351\227\256\351\242\230/object.md" deleted file mode 100644 index 9565e493..00000000 --- "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/object.md" +++ /dev/null @@ -1,12 +0,0 @@ -# object -为什么在Object 参考页,会发现左侧列出许多属性和方法——大大超过我们在自己定义的对象中看到的继承成员的数量。 - -原因在于,继承的属性和方法是定义在 prototype 属性之上的(你可以称之为子命名空间 (sub namespace) )——那些以 Object.prototype. 开头的属性,而非仅仅以 Object. 开头的属性。 - -prototype 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中,而不希望被继承的则放于Object自身,记住每一个对象都有一个原型(prototype)属性,其指向另一个对象。由下图可以看出,prototype内部存在有许多的属性和方法,原因即为以上所述 - -![](https://cdn.jsdelivr.net/gh/hr1201/img@main/imgs/202402291750719.png) - -于是 Object.prototype.watch()、[Object.prototype.valueOf()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) 等等成员,适用于任何继承自 Object() 的对象类型,包括使用构造器创建的新的对象实例。 - -[Object.is()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is)、[Object.keys()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/keys),以及其他不在 prototype 对象内的成员,不会被“对象实例”或“继承自 Object() 的对象类型”所继承。这些方法/属性仅能被 Object() 构造器自身使用。 \ No newline at end of file diff --git "a/Rarrot/articles/JavaScript/\351\227\256\351\242\230/this\351\227\256\351\242\230.md" "b/Rarrot/articles/JavaScript/\351\227\256\351\242\230/this\351\227\256\351\242\230.md" new file mode 100644 index 00000000..a0c067ce --- /dev/null +++ "b/Rarrot/articles/JavaScript/\351\227\256\351\242\230/this\351\227\256\351\242\230.md" @@ -0,0 +1,106 @@ +# this问题 + +问题一: + + ```javascript + function Fun(){ + getName = function(){ + console.log(1); + } + return this; + } + + Fun.getName = function(){ + console.log(2); + } + + Fun.prototype.getName = function(){ + console.log(3); + } + + var getName = function(){ + console.log(4); + } + + function getName(){ + console.log(5); + } + + Fun.getName(); // 2 不是Fun() + getName(); // 4 声明的getName优先 + Fun().getName(); // 1 + getName(); // 1 上一行执行了Fun(),对getName重新赋值 + new Fun().getName(); // 3 Fun()中的getName()没有用this进行指向,所以根据原型链,调用到Fun原型上的getName() + ``` + +问题二: + + ```javascript + var o = { + a: 10, + b: { + fn: function () { + console.log(this.a); // undefined + console.log(this); // {fn: ƒ}, this指向b对象 + }, + }, + }; + o.b.fn(); + ``` + +问题三: + + ```javascript + window.name = "Rarrot"; + function A() { + this.name = "A"; + } + A.prototype.say = function () { + console.log(this); + return this.name + 1; + }; + + let a = new A(); + let funa = a.say; + /* 相当于 + let funa = function () { + console.log(this); // window + return this.name + 1; + }; + */ + + console.log(funa()) // Rarrot1 + ``` + +问题四: + + ```javascript + var length = 16; // Number + function fn() { + return this.length + 1; // this指向全局对象window + } + + var obj = { + length: 5, + method1: function () { + return fn(); + }, + }; + + obj.method2 = fn; + /* 相当于: + var obj = { + length: 5, + method1: function (fn) { + return fn(); + }, + method2 = function () { + return this.lenght + 1; + } + }; + */ + + console.log(obj.method1()); // 17 + console.log(fn() === obj.method2()); // false 17 !== 6 + console.log(obj.method1() === obj.method2()); // false 17 !== 6 + ``` \ No newline at end of file