this关键字
this的值通常是由所在函数的执行环境决定,也就是说要看函数是如何被调用的;同一个函数每一次调用,this都可能指向不同的对象。
示例:
console.log(this) // window对象在全局作用域下,this指向全局对象。
var person = {
firstName : "li",
lastName : "xiaoming",
myFunction : function() {
return this;
}
};
console.log(person.myFunction()) // // this表示person对象
var o = {
x: 1,
y: 2,
sayHello: function () {
console.log(this.x); // => 1:读取实例对象属性x的值
console.log(x); // => 报错:读取的是变量x
}
};
o.sayHello();
作用域
- 局部作用域
// 此处不能调用 carName 变量
function myFunction() {
var carName = "Volvo";
// 函数内可调用 carName 变量
}
- 全局作用域
全局变量有 全局作用域: 网页中所有脚本和函数均可使用。
var outVariable = "我是最外层变量"; //最外层变量
function outFun() { //最外层函数
var inVariable = "内层变量";
function innerFun() { //内层函数
console.log(inVariable);
}
innerFun();
}
console.log(outVariable); //我是最外层变量
outFun(); //内层变量
console.log(inVariable); //inVariable is not defined
innerFun(); //innerFun is not defined
- 作用域链
当函数嵌套时,内层函数只能在外层函数作用域内执行,在内层函数执行的过程中,若需要引人某个变量,
首先会在当前作用域中寻找,若未找到,则继续向上一- 层级的作用域中寻找,直到全局作用域。
我们称这种链式的查询关系为作用域链。
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a) // 自由变量,顺作用域链向父作用域找
console.log(b) // 自由变量,顺作用域链向父作用域找
console.log(c) // 本作用域的变量
}
F2()
}
F1()
原型链
一、构造函数
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
function Person(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
this.sayName = function () {
alert(this.name);
}
}
var person = new Person("孙悟空", 18, "男");
console.log(person) ///当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值
二、原型
每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,
这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
console.log(Person.prototype);
三、原型链
1.__proto__和constructor
每一个对象数据类型(普通的对象、实例、prototype......)也天生自带一个属性__proto__,
属性值是当前实例所属类的原型(prototype)。
原型对象中有一个属性constructor, 它指向函数对象。
console.log(person.__proto__ === Person.prototype)//true
console.log(Person.prototype.constructor===Person) //true
console.log(person.__proto__) // Person.prototype
console.log(person.__proto__.__proto__) // //Object
console.log(person.__proto__.__proto__.__proto__) // null
//所以person的原型链为
person -> Person.prototype -> Object -> null;
onsole.log(Person.prototype);
console.log(Person.prototype.__proto__); //Object
console.log(Person.prototype.__proto__.__proto__); //null
//所以Person的原型链为:
Person -> Person.prototype -> Object -> null;
- proto、prototype、constructor 的关系
示例:
var o = {};
// true :对象的__proto__等于类的prototype
console.log(o.__proto__ === Object.prototype);
// true :对象的constructor 等于 类
console.log(o.constructor === Object);
// true :o.constructor.prototype 可表示对象的原型。
console.log(o.constructor.prototype === Object.prototype);
- Object.assign()
// 基本用法
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);
// 第一个参数是目标对象,后面的参数是源对象
console.log(target); // {a: 1, b: 2, c: 3}
// 合并具有相同属性的对象
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
//数组的处理
console.log(Object.assign([2,3], [5])); // [5,3]
- Object.is(value1, value2)
// 用来比较两个值是否严格相等
console.log(Object.is("q","q")); // true
console.log(Object.is([1],[1])); // false
//与(===)的区别
//一是+0不等于-0
console.log(Object.is(+0,-0)); //false
console.log(+0 === -0) //true
//二是NaN等于本身
console.log(Object.is(NaN,NaN)); //true
console.log(NaN === NaN) //false
- Object.defineProperty()
// 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
console.log(arc.getArchive()) // [{ val: 11 }, { val: 13 }]
- Object.keys(), Object.values()
// Object.keys(): 返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
// Object.values(): 返回一个给定对象自身的所有可枚举属性值的数组.
// 简单数组
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2'];
console.log(Object.values(obj)); // ['bar', 42]
// 类数组对象
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']
console.log(Object.values(obj)); // ['a', 'b', 'c']
// 排序的类数组对象
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']
console.log(Object.values(an_obj)); // ['b', 'c', 'a']
- JSON.stringify(object)
序列化对象;把对象转换成一个字符串。
示例:
var o = {
x: 1,
y: 2
}
JSON.stringify(o); // => {"x":1,"y":2}:返回一个字符串
- JSON.parse(jsonStr)
将一个Json字符串转换为对象。
示例:
var str = '{ "x":1,"y":2 }'; // 字符串的属性名要用引号框起来
var o = JSON.parse(str);
console.log(o.x); // => 1:输出对象属性x的值
Set
对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
- 集合表示无重复值的有序列表;let set = new Set ();创建一个新的集合;
- set.add();
- set.delete()
- 校验某个值是否在set中:set.has()
const set1 = new Set([1, 2, 3, 3, 4, 5, 2]);
console.log(set1) // Set(5) {1, 2, 3, 4, 5}
let set2 = [...set1]
console.log(set2) // (5) [1, 2, 3, 4, 5]
var mySet = new Set();
mySet.add(1);
mySet.add(5).add("some text"); // 可以链式调用
console.log(mySet);
// Set [1, 5, "some text"]
mySet.add(5).add(1);
console.log(mySet);
// Set [1, 5, "some text"] // 重复的值没有被添加进去
var mySet = new Set();
mySet.add("foo");
console.log(mySet.delete("bar")); // 返回 false,不包含 "bar" 这个元素
console.log(mySet.delete("foo")); // 返回 true,删除成功
var mySet = new Set();
mySet.add('foo');
console.log(mySet.has('foo')); // 返回 true
console.log(mySet.has('bar'));// 返回 false
var set1 = new Set();
var obj1 = {'key1': 1};
set1.add(obj1);
console.log(set1.has(obj1)); // 返回 true
console.log(set1.has({'key1': 1})); // 会返回 false,因为其是另一个对象的引用
console.log(set1.add({'key1': 1})); // 现在 set1 中有2条(不同引用的)对象了
Map
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
- Map 对象。
- Map 与数组的关系。
let myMap = new Map();
let keyObj = {};
let keyFunc = function() {};
let keyString = 'a string';
// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");
myMap.size; // 3
// 读取值
myMap.get(keyString); // "和键'a string'关联的值"
myMap.get(keyObj); // "和键keyObj关联的值"
myMap.get(keyFunc); // "和键keyFunc关联的值"
console.log(myMap.get('a string')); // "和键'a string'关联的值"
// 因为keyString === 'a string'
console.log(myMap.get({})) // undefined, 因为keyObj !== {}
console.log(myMap.get(function() {})); // undefined, 因为keyFunc !== function () {}
let kvArray = [["key1", "value1"], ["key2", "value2"]];
// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象
let myMap = new Map(kvArray);
// 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
console.log(Array.from(myMap)); // 输出和kvArray相同的数组
// 更简洁的方法来做如上同样的事情,使用展开运算符
console.log([...myMap]);
// Map对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。
let first = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let second = new Map([
[1, 'uno'],
[2, 'dos']
]);
let merged = new Map([...first, ...second, [1, 'eins']]);
console.log(merged); // Map(3) {1 => 'eins', 2 => 'dos', 3 => 'three'}
console.log(merged.get(1)); //eins