js基础知识深入大盘点

函数

都是Function的实例

每个js函数都是Function的对象实例,包括 箭头函数 和 对象方法

const fna = function () { }
const fnb = () => { }
const obj = {
    fnc() { }
}
console.log(fna.constructor===Function)  // true
console.log(fnb.constructor===Function)  // true
console.log(obj.fnc.constructor===Function)  // true

length属性

每个js函数都有length属性,表示函数签名中“必传”的参数的个数。fn.length在定义js函数时就已经确定好了,任何时候都不变。

    let fn = (a, b, c = 8, ...d)=> { }
    // fn.lenght 不会统计带有默认值的参数和剩余参数
    console.log(fn.length)  // 2 
    let fn = (a, b, c = 8, d)=> { }
    // fn.lenght 也不会统计 带有默认值参数后面的普通参数
    // 剩余参数后面的普通参数?剩余参数只能写在最后!
    console.log(fn.length)  // 2 

arguments内置变量(箭头函数没有)

普通函数和对象方法,都有一个局部变量 arguments 描述实参。参考:arguments性能

    function fn() {
        // arguments 只和实际传入的参数相关,与形参无关(这里形参个数为0)
        console.log(arguments.length) // 4 
     // arguments是一个可迭代对象,但不是数组(虽然类似于数组)
        for (let arg of arguments) {
            console.log('arg:', arg) // 分别输出:arg: 1,arg: 2,arg: 3,arg: 4
        }
    }
    fn(1, 2, 3, 4)
    function fn(...a) {
        // 即使形参( 即剩余参数:数组a)接收了所有的实参,arguments.length 依然是 4
     // 箭头函数可以使用这样的剩余参数,代替arguments
        console.log(arguments.length) // 4        
    }
    fn(1, 2, 3, 4)

 arguments只是类数组,可以这样转换成数组:

// 你可以这样将arguments转换为数组 
var normalArray = Array.prototype.slice.call(arguments);
// -- or --
var normalArray = [].slice.call(arguments);
// -- or --
var normalArray = Array.from(arguments);
// -- or --
var normalArray = [...arguments];
// -- or --
var normalArray =
arguments.length === 1 ? [arguments[0]]: Array.apply(null, arguments)
// 为什么要这样?
// 当 Array()调用 只有一个参数且参数是数字时,会将其作为length,创建包含指定数量的空元素的数组;
// 如果多于1个参数,就创建由这些参数组成的数组。
// 这看起来麻烦,但v8优化上更友好。
// 另外:new Array(1,2,3) 和 Array(1,2,3) 是一样的!( 有很多这样的例子。)

参数默认值

function fn(a=5) {   
    console.log(arguments.length) // 1   
    console.log(a,arguments[0])   // 5 , undefined 
}
fn(undefined)
function fn(a=5) { console.log(arguments.length) // 0 console.log(a,arguments[0]) // 5 , undefined } fn()

从上面的例子思考:如果你想真正没有传入参数时才采用默认值,即传入了undefined就使用undefined?

  • 解构赋值默认参数
  • 已经遇到的参数可以用作后面的默认参数
function f([x, y] = [1, 2], {z: z} = {z: 3}) { 
  return x + y + z; 
}

function greet(name, greeting, message = greeting + ' ' + name) {
    return [name, greeting, message];
}
  • 每次函数调用时都会重新声明一次参数变量,并对默认参数重新赋值
  • 调用一个函数分为两步:初始化参数(包含默认值初始化),然后才执行函数体。
// 示例一:
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); //[1]
append(2); //[2]

// 示例二:
let arr = []
function append(value, array = arr) {
  array.push(value);
  return array;
}

append(1); //[1]
append(2); //[1,2],

剩余参数

剩余参数是真数组

解构剩余参数

function f(...[a, b, c]) {   // 只取剩余参数中的前3个分别赋给a,b,c
  return a + b + c;
}

 箭头函数说明 

  1. 箭头函数没有prototype属性。
  2.  yield 关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作函数生成器。
  3. 箭头函数也是函数也有自己的作用域,无论是let还是var变量
  4. 箭头函数不会创建自己的this,它只会从词法层面上的自己的作用域链的上一层继承this。
    上层this变就跟着变!跟随所继承的this的变化而变化,当this从词法上指向了window(全局对象)理论上也是可以变的,但上层环境已无法变量,表现就是固定不变。
  5.  箭头函数的优先级:
    callback = callback || function() {}; // ok
    
    callback = callback || () => {};      
    // SyntaxError: invalid arrow-function arguments
    
    callback = callback || (() => {});    // ok

Object内置方法

注意Object表示静态内置的函数对象,obj表示对象实例

Object.is 

Object.is(a,b) 比较相等 类似于a===b, 不过 :

 ===  运算符将数字 -0+0 视为相等 ,而将Number.NaN与NaN视为不相等.

Object.is将数字 -0+0 视为不相等 ,而将Number.NaN 与NaN视为相等.

prototype相关

四个方法,其实影响的都是 __proto__  !!

Object.setPrototypeOf(obj, prot)  // 设置obj的原型为prot对象(可以为null)。注意:设置的是__proto__
// 注意 console.log(obj.prototype===prot, obj.__proto__===prot, prot.isPrototypeOf(obj)) 结果分别为 false,true, true
prototype1.isPrototypeOf(object1) // prototype1 是 object1 的原型(__proto__)吗? const object1 = Object.create(prototype1,config?) // 指定原型对象,创建一个对象. config 是属性配置,参考defineProperties Object.getPrototypeOf(object1) // 返回对象 object1 的原型对象

上述四个方法,设置原型,获取原型,判断原型等。注意特殊的  Object.create 

let a = {}
// 默认的原型是Object,所以a自带 toString 等方法

let a = Object.create(null)
// 这时 a.toString() 就不存在了

当然Object.create也可以做简单的继承!

扩展,密封和冻结

对应了6个静态方法:

Object.seal(obj)
Object.freeze(obj)
Object.preventExtensions(obj)
Object.isSealed(obj)
Object.isFrozen(obj)
Object.isExtensible(obj)

不可扩展对象:不可添加新的属性而已, 但可以删除已有属性,可以配置已有属性,可赋值。

密封对象:对象不可扩展,配置不可改变 ,已有属性不可删除。但可重新赋值。

冻结对象:对象不可扩展,配置不可改变,已有属性不可删除,不可重新赋值。

属性定义相关

Object.defineProperties(obj,configs)   // configs是 {key:config ...} 这样的对象
Object.defineProperty(obj,key,config)   // get set value writable enumerable configurable
Object.getOwnPropertyDescriptor(object1, 'property1');  // 返回config
Object.getOwnPropertyDescriptors(obj)   // 返回configs

Object.getOwnPropertyNames(obj)        // 返回的是所有 正常 的key   数字会变成字符串
Object.getOwnPropertySymbols(obj)   // 返回的是所有 symbol 的key
array1.propertyIsEnumerable(0)   // 返回true,表示0这个属性时可枚举的
// 注意:for...in语句以任意顺序遍历一个对象的可枚举属性(除Symbol)。

obj.hasOwnProperty('key')   // 对象obj,是否有key这个属性

注意:原型相关的 Object.create方法,也与属性相关!

其他常用

Object.assign(target,source1,source2...)   // 改变target 并返回target
Object.values(obj)  // 返回values
Object.keys(obj)  // 返回keys
Object.fromEntries(entries)  // entries是一个二维数组,内部的每个数组都有两个元素[key,value]
Object.entries(obj)  // 返回entries数组

 原型链

一张图了解原型链:

所有函数都是Function的实例:所以所有函数的__proto__最都指向 Function.prototype ,包括 Function.__proto__

所有对象都是Object的实例:所以所有对象的__proto__最终都指向 Object.prototype ,所有函数的prototype也是对象(包括Function的)自然也包括在内。

所有的函数都有两个隐含的对象(prototype和__proto__),所有对象都有一个隐含的对象(__proto__)。

posted @ 2019-10-05 15:56  enne5w4  阅读(77)  评论(0编辑  收藏  举报