构造函数
用 new 关键字来调用的函数,称为构造函数。当一个函数执行 new 操作时,会执行以下三步
- 1、生成空对象
- 2、将this指向创建的空对象
- 3、返回空对象
new的作用就是创建或返回了一个对象
// 通俗来说,就是执行了类似如下这样的事
function Person(name){
var this = {}; // 创建this变量,指向空对象
this.name = name; // 属性和方法被加入到this引用的对象中
this.say = function () { return "I am " + this.name; }
return this; // 返回this对象
}
-- 如果 return 的是一个对象,则返回该对象,而不是 this。如果返回的是原始类型,则依旧返回 this
// 返回
function User1(name) { this.name = name; return { id: 1 };}
new User1("Onion"); // {id: 1}
function User2(name) { this.name = name; return "user"; }
new User2("Onion"); // {name: 'Onion'}
-- 构造函数内定义的函数和原型链上的函数。【构造函数】为每次 new 操作新建一个 function 对象,而【原型链上的函数】指向同一个 function 对象
function User(name) { this.name = name; this.sayHi = function() { }; }
User.prototype.sayHiAgain = function() {
console.log(`My name is ${this.name}`);
};
const onion = new User("Onion");
const garlic = new User("Garlic");
console.log(onion.sayHi === garlic.sayHi); // false
console.log(onion.sayHiAgain === garlic.sayHiAgain); // true
JS对象分为函数对象与普通对象
- JS中的内置对象,如
String、Number、Boolean、RegExp、Date、Array、Object、Function、Error等,因为他们是native代码实现的,他们的原型打印出来都是ƒ () { [native code] }。内置对象本质上也是函数,所以可以通过他们创建对象,创建出的对象的隐式原型(__proto__)指向对应内置对象的prototype属性,最顶层的原型对象依然指向Object.prototype。
'abc'.__proto__ === String.prototype; // true
new String('abc').__proto__ === String.prototype; //true
new Number(1).__proto__ ==== Number.prototype; // true
[1,2,3].__proto__ === Array.prototype; // true
new Array(1,2,3).__proto__ === Array.prototype; // true
({}).__proto__ === Object.prototype; // true
new Object({}).__proto__ === Object.prototype; // true
var f = function() {};
f.__proto__ === Function.prototype; // true
var f = new Function('{}');
f.__proto__ === Function.prototype; // true
函数对象,其实就是 JavaScript 的用函数来模拟的类实现。 所有 Function 的实例都是函数对象,其他的均为普通对象,其中包括 Function 实例的实例。
Function.__proto__ === Function.prototype//true
function fun1(){};
const fun2 = function(){};
const fun3 = new Function('name','console.log(name)');
const obj1 = {};
const obj2 = new Object();
const obj3 = new fun1();
const obj4 = new new Function();
console.log(typeof Object); // function
console.log(typeof Function); // function
console.log(typeof fun1); // function
console.log(typeof fun2); // function
console.log(typeof fun3); // function
console.log(typeof obj1); // object
console.log(typeof obj2); // object
console.log(typeof obj3); // object
console.log(typeof obj4); // object
// 每个对象都有__proto__属性,但是只有函数对象才有prototype属性
fun1.prototype // {constructor: ƒ}
obj1.prototype // undefined
// **准则1:原型对象(即Person.prototype)的constructor指向构造函数本身**
Person.prototype.constructor == Person
// **准则2:实例(即person01)的__proto__和原型对象指向同一个地方**
person01.__proto__ == Person.prototype
new Animal()
Dog.prototype === animal.proto === Animal.prototype
function Animal(){
this.type = "animal";
}
Animal.prototype.getType = function(){
return this.type;
}
function Dog(){
this.name = "dog";
}
Dog.prototype = new Animal();
var xiaohuang = new Dog();
//原型链关系
xiaohuang.__proto__ === Dog.prototype
Dog.prototype.__proto__ === Animal.prototype
Animal.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
instanceof和typeof
instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象原型链中的任何位置
原型和原型链
proto(也就是[[Prototype]]
<1>constructor,prototype和__proto的关系
<2>Function instanceof Object 和Object instanceof Function的结果为什么都是true
<3>为什么所有的对象的原型最终都指向Object.prototype而不是Object
作用域
闭包
this
JavaScript 中 this 的四条绑定规则
https://fecoding.cn/2016/09/15/the-rule-of-binding-this-in-javascript/
二、JavaScript中this的四种情况(this是函数的内置对象,所以,只能出现在函数内部)
this所在函数fn无人调用的情况下this指向window
默认绑定,在不能应用其它绑定规则时使用的默认规则
默认绑定
隐式绑定 xxx.fn() 函数的调用是在某个对象上触发的,即调用位置上存在上下文对象。典型的形式为 XXX.fun() XXX.fn();fn()前如果什么都没有,那么肯定不是隐式绑定
一个对象中一个带有this的方法被调用后,this指向window,不是调用它的对象
显示绑定 xxx.call()
箭头函数 () => {}
person1.show4()() 相当于 var func = person3.show();func()
var age = 18; var obj = { age : 21, fn: functoin(){ console.log(this.age) } } (false || obj.fn)() // 18复制代码在上面的代码中,在对象中的fn方法执行之前,会先执行‘||’运算,相当于: (false || function(){ console.log(this.age) })()
setTimeout 中的回调直接指向window
call()函数
基础类型相加
字符串的优先级高,当遇到一边是字符串时,都转换为字符串再拼接。不是字符串情况下,尝试把两边的操作变量转换为数字,如果两边都转换成功,则进行数字加法。
引用对象类型
Object 对象在进行 "+" 操作时,会先调用自己的 toString 方法,再进行字符串拼接
[] + [] = ''
[] + [[1]] = '1'
[] + [{ a: 1}] = '[object object]' // {a: 1}调用toString()先转为[object object]
[] + ({}) = '[object object]'
({}) + [1] = '[object object]1'
({}) + ({}) = '[object object][object object]'
({}) + ({a: [1]}) = '[object object][object object]'
+{} = 'NaN' // 由于控制台解析导致,请看以下解释
注:console.log({}+{})得到的这样的结果,但是,在有些浏览器例如Firefox、Edge控制台直接输入{}+{},会得到NaN,因为浏览器会把{} + {}直译为相当于+{}语句,因为它们会认为以花括号开头({)的,是一个区块语句的开头,而不是一个对象字面量,所以会认为略过第一个{},把整个语句认为是个+{}的语句,也就是相当于强制求出数字值的Number({})函数调用运算,相当于Number("[object Object]")运算,最后得出的是NaN。如果加上圆括号({}) + {},则可以避免这样的问题。
基础类型 + 引用对象类型
基础类型和引用对象类型进行 “+” 号运算时,两遍都转换为字符串后再进行比较。
1 + []
1 + ({}) = '1[object object]'
'2' + [] = '2'
'2' + ({}) = '2[object object]'
false + [] = 'false'
false + [{}] = 'false[object object]'
false + ({}) = 'false[object object]'
null + [] = 'null'
null + ({}) = 'null[object object]'
null + [{}] = 'null[object object]'
undefined + [] = 'undefined'
undefined + ({}) = 'undefined[object object]'
undefined + [{}] = 'undefined[object object]'
NaN + [] = 'NaN'
// 复杂例子
[1,2,['abc'],[4,5,{ name:'abe' }]].toString() = '1,2,abc,4,5,[object object]'
函数对象toString结果
Function进行“+”号运算时也遵循先转换为字符串后再运算。Function 的 toString 方法不是返回 [object Object],而是将整个方法体返回为字符串,连换行和缩进都完整保持。 Function 的 toString,返回的是定义函数时,等号右边的全部内容字符串。func3等价于func1。
let func1 = function(){} // func1.toString() 结果为 'function(){}'
let func2 = (a, b) => {} // func2.toString() 结果为 '(a, b) => {}'
function func3(){} // func3.toString() 结果为 'function func3(){}'
1 + func1 // '1function(){}'
({}) + func1 // '[object Object]function(){}'
false + func1 // 'falsefunction(){}'
1 + func2 // '1(a, b) => {}'
总结
- 都是基础类型,存在字符串时,两边转为字符串再运算,不存在字符串,两边转为数字再运算
- 存在引用对象,两边转换为字符串后再运算
